El hilo de despacho de eventos (EDT) es un hilo en segundo plano que se utiliza en Java para procesar eventos de la cola de eventos de la interfaz gráfica de usuario Abstract Window Toolkit (AWT) . Es un ejemplo del concepto genérico de programación orientada a eventos , que es popular en muchos otros contextos además de Java, por ejemplo, navegadores web o servidores web .
Los eventos son principalmente eventos de actualización que hacen que los componentes de la interfaz de usuario se redibujen, o eventos de entrada de dispositivos de entrada como el ratón o el teclado. AWT utiliza un modelo de dibujo de un solo hilo en el que todas las actualizaciones de pantalla deben realizarse desde un solo hilo. El hilo de despacho de eventos es el único hilo válido para actualizar el estado visual de los componentes visibles de la interfaz de usuario. La actualización de componentes visibles desde otros hilos es la fuente de muchos errores comunes en programas Java que utilizan Swing . [ 1 ] El hilo de despacho de eventos se llama trabajador primordial en Adobe Flash y el hilo de la interfaz de usuario en SWT , .NET Framework y Android .
Bucle de mensajes para serializar los accesos a la interfaz gráfica de usuario.
Una aplicación de software normalmente consta de múltiples hilos y una única estructura de datos GIT. Esto significa que GIT es una estructura de datos compartida y se necesita cierta sincronización para asegurar que solo un hilo acceda a ella a la vez. Aunque AWT y Swing exponen los métodos ( no seguros para hilos ) para crear y acceder a los componentes de la GUI y estos métodos son visibles para todos los hilos de la aplicación, de manera similar en otros marcos de GUI, solo un único hilo de despacho de eventos tiene derecho a ejecutar estos métodos. [ 2 ] [ 3 ] [ 4 ] Dado que los programadores a menudo pasan por alto este requisito, los Look and Feels de terceros , como Substance, llegan incluso a negarse a instanciar cualquier componente Swing cuando no se ejecuta dentro del hilo de despacho de eventos, [ 5 ] para evitar tal error de codificación. El acceso a la GUI es serializado y otros hilos pueden enviar algún código para ser ejecutado en el EDT a través de una cola de mensajes EDT .
Es decir, al igual que en otros marcos de trabajo de interfaz gráfica de usuario (GUI), el hilo de despacho de eventos (EDT) se dedica a gestionar mensajes: mantiene una cola de mensajes con las acciones que deben realizarse en la GUI. Estas solicitudes son enviadas a la cola por el sistema y cualquier hilo de la aplicación. El EDT las procesa una tras otra y responde actualizando los componentes de la GUI. Los mensajes pueden ser acciones conocidas o incluir llamadas de retorno, es decir, referencias a métodos de usuario que deben ejecutarse mediante el EDT.
El requisito fundamental para todos los mensajes es que deben ejecutarse rápidamente para que la interfaz gráfica de usuario (GUI) siga respondiendo. De lo contrario, el bucle de mensajes se bloquea y la GUI se congela.
Envío del código de usuario al EDT
Existen diversas soluciones para enviar código al EDT y realizar tareas largas sin bloquear el bucle.
Controladores de eventos de componentes (oyentes)
Los componentes de la interfaz gráfica de usuario (GUI) admiten listas de funciones de devolución de llamada, denominadas oyentes, que normalmente se rellenan al crear los componentes. EDT ejecuta los oyentes cuando el usuario interactúa con los componentes (se hace clic en un botón, se mueve el ratón, se selecciona un elemento, se pierde el foco, se cambia el tamaño del componente, etc.).
Minutero
Se utiliza para tareas breves que requieren acceder o modificar la interfaz gráfica de usuario periódicamente o en momentos específicos javax.swing.Timer. Puede considerarse como un componente invisible de la interfaz gráfica, cuyos detectores se registran para activarse en momentos específicos.
Equivalentes
System.Windows.Forms.Timer- .NET Frameworkflash.utils.Timer- Adobe Flash
Solicitudes de otros hilos
Otros subprocesos de la aplicación pueden pasar código para que se ejecute en el subproceso de despacho de eventos mediante SwingUtilitiesclases auxiliares (o EventQueuesi se utiliza AWT ). El código enviado debe estar encapsulado en un Runnableobjeto. Dos métodos de estas clases permiten:
- ejecución de código síncrona (
SwingUtilities.invokeAndWait(Runnable)oEventQueue.invokeAndWait(Runnable)) - y ejecución de código asíncrona (
SwingUtilities.invokeLater(Runnable)oEventQueue.invokeLater(Runnable))
desde el hilo de despacho de eventos.
Este método invokeAndWait()nunca debe llamarse desde el hilo de distribución de eventos , ya que generará una excepción . El método SwingUtilities.isEventDispatchThread()puede EventQueue.isDispatchThread()utilizarse para determinar si el hilo actual es el hilo de distribución de eventos.
El código proporcionado a través de invokeLatery invokeAndWaital EDT debe ser lo más rápido posible para evitar bloqueos. Normalmente, están diseñados para entregar el resultado de un cálculo extenso a la interfaz gráfica de usuario (GUI).
Patrón de diseño de trabajador
Tanto la ejecución de una tarea en otro hilo como la presentación de los resultados en el EDT se pueden combinar mediante el patrón de diseño Worker . La javax.swing.SwingWorkerclase, desarrollada por Sun Microsystems , es una implementación de este patrón y, desde Java 6, forma parte de la distribución estándar de Swing. SwingWorker se invoca normalmente desde un oyente de eventos ejecutado en el EDT para realizar una tarea larga y así evitar que el EDT se bloquee.
Muestras
SwingWorker < Document , Void > worker = new SwingWorker < Document , Void > () { public Document doInBackground () throws IOException { return loadXML (); // tarea pesada } public void done () { try { Document doc = get (); display ( doc ); } catch ( Exception ex ) { ex . printStackTrace (); } } }; worker . execute ();Si usas Groovy y groovy.swing.SwingBuilder, puedes usar doLater(), doOutside(), y edt(). Entonces puedes escribirlo de forma más sencilla así:
doOutside { def doc = loadXML () // tarea pesada edt { display ( doc ) } }Equivalentes
System.ComponentModel.BackgroundWorker- .NET Frameworkflash.system.Worker- Adobe Flashandroid.os.AsyncTask- Android
Ejecución modal
Normalmente, EDT crea un SwingWorker para tareas largas mientras gestiona eventos de devolución de llamada (Listener). Al generar un hilo de trabajo, EDT procesa el mensaje actual sin esperar a que el hilo finalice. Esto suele ser indeseable.
A menudo, su EDT gestiona una acción de componente de GUI que requiere que el usuario seleccione una opción mediante otro cuadro de diálogo, como JFileChooser, que aparece y permanece activo mientras el usuario elige su opción. La acción continúa con el archivo seleccionado solo después de presionar el botón "Aceptar". Como puede ver, esto lleva tiempo (el usuario responde en cuestión de segundos) y necesita una GUI activa (los mensajes siguen procesándose en EDT) durante todo este tiempo mientras EDT está bloqueado (no procesa mensajes más recientes, como los de JFileChooser, en la cola antes de que se cierre el cuadro de diálogo y finalice la acción del componente actual). Este círculo vicioso se rompe cuando EDT entra en un nuevo bucle de mensajes, que los procesa con normalidad hasta que llega el mensaje "el cuadro de diálogo modal ha finalizado" y se reanuda el procesamiento normal de mensajes desde la posición bloqueada en la acción del componente.
El proyecto de código abierto Foxtrot emula el bucle de mensajes de Swing para proporcionar un mecanismo de ejecución "síncrona" para tareas de usuario arbitrarias, que se ejecuta solo después de que el trabajador complete la tarea.
botón . addActionListener ( new ActionListener () { public void actionPerformed ( ActionEvent e ) { botón . setText ( "Durmiendo..." );String texto = null ; try { texto = ( String ) Worker.post ( new Task ( ) { public Object run () throws Exception { Thread.sleep ( 10000 ); return "¡Dormió!" ; } } ) ; } catch ( Exception x ) ...botón.setText ( texto ) ;algo más (); } });Desde Java 1.7, Java proporciona una solución estándar para bucles de mensajes secundarios personalizados al exponer createSecondaryLoop () en system EventQueue ().
Véase también
Referencias
- ↑ Este problema no es exclusivo de Java Swing . Existe el mismo problema en la mayoría de los kits de herramientas de widgets , como por ejemplo Windows Forms , donde la clase BackgroundWorker realiza la misma función que SwingWorker en Java.
- ↑ "El hilo de despacho de eventos" . Sun Microsystems . Consultado el 2 de octubre de 2011 .
- ↑ "¿Depurar Swing es realmente difícil?" . Alexander Potochkin. Archivado del original el 5 de agosto de 2011. Consultado el 2 de octubre de 2011 .
- ↑ "Hilos iniciales" . Sun Microsystems . Consultado el 2 de octubre de 2011 .
- ↑ "Controles más estrictos sobre las violaciones de EDT en Substance · Pushing Pixels" .
Enlaces externos
javax.swing( Documentación Javadoc de la API de Swing )java.awt(Documentación Javadoc de la API AWT )- Documentación de la API de Swing
- El hilo de despacho de eventos
- Descripción de SwingWorker del tutorial de Swing
- Artículo de AWT/Swing sobre el manejo de eventos, el bombeo, el despacho y el procesamiento de eventos, y el EDT.
- Página principal del proyecto Foxtrot
- Componentes JDK