2010-01-29 15 views
8

En una aplicación Swing, tengo una serie de subpaneles, cada uno escuchando un solo JSlider. El panel principal circundante también escucha todos los subpaneles. Para obtener resultados consistentes en el siguiente ejemplo, tuve que agregar primero el padre y , luego el oyente local. Esto tiene sentido, dado el orden prescrito en EventListenerList y se explica en este article. ¿Puedo confiar en ese pedido o debo hacer arreglos para enviar un evento diferente?Orden de activación EventListenerList

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

Adición: la discusión en EventListenerList parece ser un consejo aplicación en lugar de una garantía. El enfoque de encadenamiento sugerido por pstanton impone el orden correcto de manera más confiable. Por ejemplo, SubPanel 's ChangeListener puede simplemente reenviar el evento al padre.

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

¡Interesante pregunta y discusión! 1+ –

+0

La aplicación ['Converter'] (http://docs.oracle.com/javase/tutorial/uiswing/components/panel.html) incluye un ejemplo en' ConverterRangeModel'. – trashgod

+0

Acabo de recibir su publicación mientras 'googleando ', quería explicar en detalle. por favor haga que la publicación cuente, y ¡indíqueme si algo de lo que he descrito puede ser incorrecto! – Sage

Respuesta

4

Desde la documentación de JSlider y JComponent etc no mencionan el orden de escucha de notificaciones, yo dude en confiar en ella, al menos sin pruebas exhaustivas en cada versión subsiguiente del JRE.

Si realmente necesita confiar en la orden, considerar la creación de una cadena de oyentes, es decir, un oyente escucha notificará a dos etc.

+0

En general, en eventos de cambio de estado (en lugar de entrada) es más robusto ignorar por completo el objeto de evento. (No se deje confundir por el rendimiento: piense cuántos ciclos está usando en comparación con * millones * que una CPU promedio puede hacer en un milisegundo). –

+0

@Tom: ¿es un comentario sobre mi respuesta o su pregunta? – pstanton

+0

bien, su punto no está del todo claro. – pstanton

1

Un poco viejo y muy tarde para responder. Pero mi mente inestable me está forzando a entrar.

¿Puedo confiar en ese orden o debo organizar para enviar un evento diferente ?

yo creo que mantengan el orden, la documentación del componente no nos dice mucho, pero código fuente es siempre nuestro amigo. Partamos de addChangeListener(listener) función de JSlider:

PASO 1: llamando jSlider.addChangeListener(listener) añade el listener a un listener list.

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

PASO 2: código fuente de EvenListenerList: synchronized add(Class<T> t, T l): suma los oyentes y tipo correspondiente de tal manera que escucha nuevo se añade al final de la Object[] y para un índice i, Object[i] es tipo del oyente y Object[i+1] es la instancia del oyente.

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

PASO 3: La función de fireStateChanged()JSlider es responsable del envío de eventos para todos los oyentes de la lista. El código fuente nos dice que llama a la función stateChanged() de cada oyente visitándolas desde el final de la lista de oyentes.

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

veraniego: El mecanismo de (sincronizada) añadir y visitar de oyentes en la lista de oyentes nos dice que: se mantendrá la última orden AÑADIR primera visita. Es decir, el último oyente agregado (hijo) se va a llamar primero, luego el oyente anterior (principal) y así sucesivamente.El código de manejo de eventos Swing se ejecuta en EDT. Y como EventQueue distribuye el evento En el mismo orden en que son enqueued, el evento secundario se enviará antes del evento principal.

Así que creo que el pedido se está manteniendo.

+1

Si bien es un patrón de diseño interesante, es un detalle de implementación en el que soy reacio a confiar. – trashgod

+0

probablemente, pero para mí, llamar al mecanismo 'EventListListener' * no confiable * parece que lo regañamos :);) – Sage

+1

solo para enfatizar el comentario de @trashgod: el orden de notificación está explícitamente no especificado (ver f.i. la especificación de beans). Además, la orden puede cambiar durante la vida de un observable, f.i. eliminando/agregando oyentes en el cambio de LAF. Por lo tanto, como regla general ** no ** confíe en ninguna implementación concreta, ¡podría cambiar sin previo aviso! – kleopatra

Cuestiones relacionadas