2010-09-03 12 views
9

He leído que todo el código que construye los componentes Swing y maneja los eventos debe ser ejecutado por el hilo de envío del evento. Entiendo cómo se logra esto al usar el método SwingUtilities.invokeLater(). Considere el siguiente código donde la inicialización interfaz gráfica de usuario se realiza en el método en sí main¿Cómo se llama la secuencia de envío del evento?

public class GridBagLayoutTester extends JPanel implements ActionListener { 
    public GridBagLayoutTester() { 
     setLayout(new GridBagLayout()); 
     GridBagConstraints gbc = new GridBagConstraints(); 

     JButton button = new JButton("Testing"); 
     gbc.fill = GridBagConstraints.HORIZONTAL; 
     gbc.anchor = GridBagConstraints.WEST; 
     gbc.gridx = 0; 
     gbc.gridy = 0; 
     gbc.gridwidth = 1; 
     button.addActionListener(this); 
     add(button, gbc); 
    } 

    public void actionPerformed(ActionEvent e) { 
     System.out.println("event handler code"); 
    } 

    public static void main(String[] args) { 
     JFrame frame = new JFrame("GridBagLayoutDemo"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
     Container contentPane = frame.getContentPane(); 
     contentPane.setLayout(new BorderLayout()); 
     contentPane.add(new GridBagLayoutTester(), BorderLayout.CENTER); 
     frame.setSize(800, 600); 
     frame.pack(); 
     frame.setVisible(true); 
     System.out.println("Exiting"); 
    } 
} 

¿Cómo es que este código funciona perfectamente? Estamos construyendo JFrame y llamando a un host de otros métodos en el hilo principal. No entiendo dónde está exactamente el EDT entrando en la imagen aquí (¿qué código está ejecutando?). El constructor de la clase GridBagLayoutTester también se llama desde el método main, lo que significa que EDT no lo está ejecutando.

En resumen

  1. Cuando se está iniciando la EDT? (¿la JVM inicia el EDT junto con el método principal si en todo el EDT se inicia al ejecutar este código?)
  2. ¿Se ejecuta el código del controlador de eventos para el botón en el EDT?

Respuesta

12

El código funciona perfectamente porque está construyendo el marco en el hilo principal, antes de que el EDT tenga la oportunidad de interactuar con él. Técnicamente, no deberías hacer esto nunca, pero técnicamente puedes bajo esta circunstancia específica porque no puedes interactuar con el JFrame hasta que se vuelva visible.

El punto principal a saber es que los componentes Swing no son seguros para subprocesos. Esto significa que no se pueden modificar desde más de un hilo al mismo tiempo. Esto se resuelve al garantizar que todas las modificaciones provengan del EDT.

El EDT es un hilo dedicado a la interacción del usuario. Cualquier evento generado por el usuario siempre se ejecuta en el EDT. Cualquier actualización de interfaz de usuario se ejecuta en el EDT. Por ejemplo, cuando llama al Component.repaint(), puede llamarlo desde cualquier conversación. Esto simplemente establece un indicador para marcar que el componente necesita pintura, y el EDT lo hace en su próximo ciclo.

El EDT se inicia automáticamente y está muy relacionado con la implementación del sistema. Se maneja bien dentro de la JVM. Por lo general, se correlaciona con un único hilo en el sistema de ventanas que maneja la interacción del usuario. Por supuesto, esto es bastante dependiente de la implementación. Lo bueno es que no tienes que preocuparte por esto. Solo tienes que saber: si interactúas con cualquier componente de Swing, hazlo en el EDT.

Del mismo modo, hay otra cosa que es importante. Si vas a hacer un procesamiento o bloqueo de larga duración de un recurso externo, y lo vas a hacer en respuesta a un evento generado por el usuario, debes programarlo para que se ejecute en su propio subproceso fuera del EDT. Si no lo hace, hará que la interfaz de usuario se bloquee mientras espera a que se ejecute el procesamiento de larga duración. Ejemplos excelentes son cargar archivos, leer desde una base de datos o interactuar con la red. Puede probar para ver si está en el EDT (útil para crear métodos neutros que pueden invocarse desde cualquier subproceso) con el método SwingUtilities.isEventDispatchThread().

Éstos son dos fragmentos de código que uso con bastante frecuencia al escribir la programación oscilación hacer frente a la EDT:

 
void executeOffEDT() { 
    if (SwingUtilities.isEventDispatchThread()) { 
    Runnable r = new Runnable() { 
     @Override 
     public void run() { 
     OutsideClass.this.executeOffEDTInternal(); 
     } 
    }; 
    new Thread(r).start(); 
    } else { 
    this.executeOffEDTInternal(); 
    } 
} 

void executeOnEDT() { 
    if (SwingUtilities.isEventDispatchThread()) { 
    this.executeOnEDTInternal(); 
    } else { 
    Runnable r = new Runnable() { 
     @Override 
     public void run() { 
     OutsideClass.this.executeOnEDTInternal(); 
     } 
    }; 
    SwingUtilities.invokeLater(r); 
    } 
} 
+0

En cuanto Component.repaint() Dudo que esto sólo "establece una bandera", en realidad se pone en cola un evento de pintura (que luego serán procesados ​​por el EDT). – jfpoilpret

+1

El patrón es el mismo. No necesita conocer los aspectos internos de la forma en que se maneja esto para utilizar el EDT con éxito. –

+0

para que la llamada frame.setVisible() se ejecute en el EDT? – Stormshadow

1

1) No sé si en new JFrame o en setVisible pero Initialize en la demanda y eso es lo que al final del método principal (sobre el hilo principal del proceso) no termina el proceso. el EDT se lanzó y está bloqueado esperando el próximo evento.

2) Definitivamente. Ese bucle recibe del OS el evento, encuentra el JButton y le dice que el evento se disparó. El botón luego llama a los oyentes. Todo lo que sucede en el EDT.

Puede revisar el código de Swing que llama cuando quiere matar el proceso (o cerrar la ventana principal) para ver dónde termina el EDT ... eso puede darle una pista (lo haré más tarde) ! :)

3

El subproceso de envío de evento, como su nombre lo indica, es llamado por Swing cada vez que un evento necesita ser procesado.

En el ejemplo que proporcionó, el botón "Prueba" llamará automáticamente al método actionPerformed cuando se necesite procesar un evento de acción. Por lo tanto, el contenido de su método actionPerformed será invocado por el hilo de envío del evento.

para responder a sus dos preguntas finales:

  • La EDT se inicia automáticamente cuando se carga el marco Swing. No tiene que preocuparse por comenzar este hilo, el JRE maneja esta tarea por usted.
  • El EDT ejecuta el código del controlador de eventos. Todos los eventos que genere su interfaz Swing se agrupan y el EDT es responsable de ejecutarlos.
Cuestiones relacionadas