Ordine di triggerszione di EventListenerList

In un’applicazione Swing, ho un numero di sotto-pannelli, ognuno dei quali ascolta un singolo JSlider . Il pannello genitore circostante ascolta anche tutti i pannelli secondari. Per ottenere risultati coerenti nell’esempio seguente, ho dovuto aggiungere prima il genitore e poi il listener locale. Questo ha senso, dato l’ordine prescritto in EventListenerList e spiegato in questo articolo . Posso fare affidamento su questo ordine o devo organizzare un evento diverso?

 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); } ... } 

Addendum: la discussione in EventListenerList sembra essere un consiglio di implementazione piuttosto che una garanzia. L’approccio di concatenamento suggerito da Pstanton impone l’ordine corretto in modo più affidabile. Ad esempio, SubPanel di ChangeListener può semplicemente inoltrare l’evento al genitore.

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

Poiché la documentazione di JSlider e JComponent ecc non menziona l’ordine di notifica del listener, esiterei a fare affidamento su di esso, almeno senza test approfonditi su ogni versione successiva di JRE.

Se hai davvero bisogno di fare affidamento sull’ordine, prendi in considerazione l’idea di creare una catena di ascoltatori, cioè Listener si notificherà l’ascoltatore due ecc.

Un po ‘vecchio e molto tardi per rispondere. Ma la mia mente instabile mi sta davvero costringendo a entrare.

Posso fare affidamento su questo ordine o devo organizzare un evento diverso?

Credo che mantengano l’ordine, la documentazione del componente non ci dice molto, ma il codice sorgente è sempre nostro amico. Cominciamo dalla funzione addChangeListener(listener) di JSlider :

PASSO 1: chiamare jSlider.addChangeListener(listener) aggiunge il listener a un listener list .

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

PASSO 2: codice sorgente di EvenListenerList : synchronized add(Class t, T l) : aggiunge gli ascoltatori e il tipo corrispondente in modo tale che il nuovo listener sia aggiunto alla fine Object[] e per un indice i , Object[i] è il tipo del listener e Object[i+1] è l’istanza del listener.

 public synchronized  void add(Class 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; } } 

PASSO 3: La funzione fireStateChanged() di JSlider è responsabile dell’invio di eventi a tutti gli ascoltatori della lista. Il codice sorgente ci dice che chiama la funzione stateChanged() ogni ascoltatore visitandoli dalla fine dell’elenco dei listener.

 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: il meccanismo di aggiunta (sincronizzata) e di visita degli ascoltatori nell’elenco degli ascoltatori ci dice che: mantiene l’ordine LAST ADD FIRST VISIT. Cioè, il successivo listener (secondario) verrà chiamato prima, poi il precedente (genitore) aggiunto listener e così via. Il codice di gestione degli eventi Swing viene eseguito su EDT. E come EventQueue invia l’evento Nello stesso ordine in cui vengono enqueued , l’evento figlio verrà inviato prima dell’evento padre.

Quindi credo che l’ ordine sia mantenuto.