2010-01-29 17 views
8

Swing uygulamasında, her biri tek bir JSlider dinleyen çok sayıda alt panelim var. Çevredeki ana panel ayrıca tüm alt panelleri dinler. Aşağıdaki örnekte tutarlı sonuçlar elde etmek için, önce üst öğeyi ve sonra da yerel dinleyiciyi eklemeliydim. Bu, EventListenerList'da belirtilen talimatlar verildiğinde ve bu article numaralı belgede açıklandığı gibi mantıklıdır. Bu siparişe güvenebilir miyim ya da farklı bir etkinlik göndermeyi ayarlamalı mıyım?EventListenerList ateş emri

class SubPanel extends JPanel implements ChangeListener { 

    private final JSlider slider = new JSlider(); 
    private final JLabel label = new JLabel(); 
    private final String name; 
    private float value; 

    public SubPanel(String name, float value, ChangeListener parent) { 
     this.name = name; 
     this.value = value; 
     ... 
     slider.addChangeListener(parent); 
     slider.addChangeListener(this); 
    } 
    ... 
} 

Ek: EventListenerList tartışma uygulama tavsiyesi yerine bir garanti gibi görünüyor. pstanton tarafından önerilen zincirleme yaklaşımı, doğru siparişi daha güvenli bir şekilde uygular. Örneğin, SubPanel 's ChangeListener, olayı yalnızca ebeveyne iletebilir. JSlider ve JComponent vb belgeleri dinleyici bildirim sırasını söz olmadığından

@Override 
    public void stateChanged(ChangeEvent e) { 
     ... 
     parent.stateChanged(e); 
    } 
+0

İlginç bir soru ve tartışma! 1+ –

+0

['Dönüştürücü'] (http://docs.oracle.com/javase/tutorial/uiswing/components/panel.html) uygulama' ConverterRangeModel' içinde bir örnek içerir. – trashgod

+0

Sadece googling yaparken, yazılarınızı aldım, detaylarını açıklamak istedim. Lütfen mesaj sayımını yap ve tarif ettiğim bir şey yanlış olabilirse bana işaret et! – Sage

cevap

4

, en azından JRE sonraki her sürümünde kapsamlı testler olmaksızın, buna güvenmek tereddüt ediyorum.

Gerçekten, sipariş güvenmek vb dinleyici iki bildirir dinleyici zinciri, yani Dinleyici biri kurma dikkate gerekiyorsa

+0

Genel olarak durum değişikliği (girişin aksine) olayları olay nesnesini tamamen yok saymak daha sağlamdır. (Performans hakkında kafanız karışmayın - milyonlarca saniyede bir ortalama işlemcinin * yapabildiğine kıyasla kaç döngü kullandığınızı düşünün). –

+0

@ Tom: Bu benim cevabımla ilgili bir yorum mu, yoksa sorusu mu? – pstanton

+0

tamam, senin noktan tamamen açık değil. – pstanton

1

Biraz eski ve cevap çok geç. Ama kararsız aklımı gerçekten beni içine çekmeye zorluyor.

Bu siparişi güvenebilir miyim veya farklı bir etkinliği göndermek için düzenlemeliyim mi?

Onların düzeni korumak inanıyorum, komponente belgelerine kadar bize söylemez, ama kaynak kodu her zaman bizim dostumuzdur. Bize addChangeListener(listener) işlevinden JSlider ait başlayalım:

ADIM 1: çağıran jSlider.addChangeListener(listener) bir listener list için listener ekler.

public void addChangeListener(ChangeListener l) { 
     listenerList.add(ChangeListener.class, l); 
    } 

ADIM 2: synchronized add(Class<T> t, T l): EvenListenerList arasında kaynak kodu Object[i] olup, dinleyici ve yeni bir dinleyici Object[] sonunda ve bir indeks i için ilave edilir, öyle ki, ilgili türü ekler dinleyicinin tipi ve Object[i+1], dinleyici örneğidir.

public synchronized <T extends EventListener> void add(Class<T> t, T l) { 
    // There were other checking here 
    // omitted as irrelevant to the discussion 
    } else { 
     // Otherwise copy the array and add the new listener 
     int i = listenerList.length; 
     Object[] tmp = new Object[i+2]; 
     System.arraycopy(listenerList, 0, tmp, 0, i); 

     tmp[i] = t; // add the class type 
     tmp[i+1] = l; // add the listener instance 

     listenerList = tmp; 
    } 
    } 

ADIM 3:JSlider ait fireStateChanged() fonksiyon listesinin her dinleyiciye olayı göndermekten sorumludur. Kaynak kodu, her dinleyicinin stateChanged() işlevini, dinleyici listesinin sonundan ziyaret ederek çağırdığını bildirir.

protected void fireStateChanged() { 
     Object[] listeners = listenerList.getListenerList(); 
     for (int i = listeners.length - 2; i >= 0; i -= 2) { 
      if (listeners[i]==ChangeListener.class) { 
       if (changeEvent == null) { 
        changeEvent = new ChangeEvent(this); 
       } 
       ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); 
      } 
     } 
    } 

Summery: mekanizması (senkronize) ekleme ve dinleyiciler listesindeki dinleyicilerin ziyaret bize söyler: o SON İLK ZİYARETİ düzeni ADD korumak. Yani, daha sonra (çocuk) eklenen dinleyici ilk çağrılacak, daha sonra (ebeveyn) eklenmiş dinleyici vb.Salıncak olay işleme kodu EDT'de çalışır. Ve EventQueue, olayı enqueued ile aynı sırada gönderir, alt olaydan önce alt olay gönderilir.

düzeninin korunduğuna inanıyorum.

+1

İlginç bir tasarım deseni olsa da, güvendiğim bir uygulama detayıdır. – trashgod

+0

muhtemelen, ama benim için, 'EventListListener' mekanizmasını * güvenilmez * çağıran biz azar azar gibi görünüyor;) – Sage

+1

sadece @ trashgod yorumunu vurgulamak için: bildirimin sırası açıkça belirtilmemiş (bkz. Fasulye çeşidi). Ayrıca, emir, gözlemlenebilir bir yaşam süresi boyunca değişebilir. LAF değişiminde dinleyicileri kaldırarak/ekleyerek. Yani, genel bir kural olarak ** herhangi bir somut uygulamaya güvenmeyin, haber verilmeksizin değişebilir! – kleopatra