El subproceso de despacho de eventos (EDT) es un subproceso de fondo utilizado en Java para procesar eventos de la cola de eventos de la interfaz gráfica de usuario de Abstract Window Toolkit (AWT) . Es un ejemplo del concepto genérico de programación impulsada por 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 vuelvan a dibujar, o eventos de entrada de dispositivos de entrada como el mouse o el teclado. El AWT utiliza un modelo de pintura de un solo subproceso en el que todas las actualizaciones de pantalla deben realizarse desde un solo subproceso. El hilo de distribución 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 de otros subprocesos es la fuente de muchos errores comunes en los programas Java que usan Swing . [1] El hilo de distribución de eventos se denomina trabajador primordial en Adobe Flash y elHilo de UI en SWT , .NET Framework y Android .
Bucle de mensajes para serializar accesos GUI
Una aplicación de software normalmente consta de varios subprocesos y una única estructura de datos GUI . Esto significa que la GUI es una estructura de datos compartida y se necesita cierta sincronización para garantizar que solo un subproceso acceda a ella a la vez. Aunque AWT y Swing exponen los métodos ( subprocesos inseguros ) para crear y acceder a los componentes de la GUI y estos métodos son visibles para todos los subprocesos de la aplicación, del mismo modo en otros marcos de la GUI, solo un subproceso de envío de eventos tiene derecho a ejecutar estos métodos. [2] [3] [4] Dado que los programadores a menudo pasan por alto este requisito, Look and Feels de terceros , como Substance, van tan lejos como para negarse a crear una instancia de cualquier componente Swing cuando no se ejecuta dentro del subproceso de envío de eventos, [5] para evitar tal error de codificación. El acceso a la GUI se serializa y otros subprocesos pueden enviar algún código para que se ejecute en el EDT a través de una cola de mensajes EDT .
Es decir, del mismo modo en otros marcos de GUI, el subproceso de despacho de eventos pasa su vida bombeando mensajes: mantiene una cola de mensajes de acciones que se realizarán a través de la GUI. Estas solicitudes se envían a la cola por sistema y cualquier hilo de aplicación. EDT los consume uno tras otro y responde actualizando los componentes de la GUI. Los mensajes pueden ser acciones conocidas o implicar devoluciones de llamada, las referencias a métodos de usuario que deben ejecutarse mediante EDT.
El requisito importante que se impone a todos los mensajes es que deben ejecutarse rápidamente para que la 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 varias 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 GUI admiten las listas de devoluciones de llamada, denominadas Listeners, que normalmente se rellenan cuando se crean los componentes. EDT ejecuta los oyentes cuando el usuario excita los componentes de alguna manera (se hace clic en el botón, se mueve el mouse, se selecciona el elemento, se pierde el foco, se cambia el tamaño del componente, etc.).
Temporizador
Para tareas breves que deben acceder / modificar la GUI periódicamente o en un momento específico, javax.swing.Timer
se utiliza. Puede considerarse como un componente de GUI invisible, cuyos oyentes están registrados para disparar 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 algún código para que se ejecute en el subproceso de despacho de eventos mediante SwingUtilities
clases auxiliares (o EventQueue
si está haciendo AWT ). El código enviado debe estar envuelto con un Runnable
objeto. Dos métodos de estas clases permiten:
- ejecución de código sincrónico (
SwingUtilities.invokeAndWait(Runnable)
oEventQueue.invokeAndWait(Runnable)
) - y ejecución de código asincrónico (
SwingUtilities.invokeLater(Runnable)
oEventQueue.invokeLater(Runnable)
)
desde el hilo de despacho de eventos.
El método invokeAndWait()
nunca debe llamarse desde el subproceso de despacho de eventos; arrojará una excepción . Se puede llamar al método SwingUtilities.isEventDispatchThread()
o EventQueue.isDispatchThread()
para determinar si el hilo actual es el hilo de despacho de eventos.
El código suministrado mediante el invokeLater
y invokeAndWait
al EDT debe ser lo más rápido posible para evitar la congelación. Normalmente están destinados a entregar el resultado de un largo cálculo a la GUI (usuario).
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 del trabajador . La javax.swing.SwingWorker
clase, desarrollada por Sun Microsystems , es una implementación del patrón de diseño del trabajador y, a partir de Java 6, es parte de la distribución estándar de Swing. SwingWorker normalmente se invoca desde el Listener de eventos ejecutado por EDT para realizar una tarea larga con el fin de no bloquear el EDT.
Muestras
SwingWorker < documento , vacío > trabajador = nuevo SwingWorker < documento , vacío > () { documento público doInBackground () lanza IOException { return loadXML (); // tarea pesada } public void done () { try { Document doc = get (); display ( doc ); } captura ( Excepción ex ) { ex . printStackTrace (); } } }; trabajador . ejecutar ();
Si utiliza maravilloso y groovy.swing.SwingBuilder
, puede utilizar doLater()
, doOutside()
y edt()
. Entonces puedes escribirlo de manera más simple 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
SwingWorker normalmente se crea para tareas largas por EDT mientras maneja eventos de devolución de llamada (Listener). Al generar un hilo de trabajo, EDT continúa manejando el mensaje actual sin esperar que el trabajador lo complete. A menudo, esto no es deseable.
A menudo, su EDT maneja una acción del componente GUI, que exige que el usuario haga una elección por medio de otro cuadro de diálogo, como JFileChooser, que aparece, permanece receptivo mientras el usuario elige su opción y la acción continúa con el archivo seleccionado solo después del botón "Aceptar". se presiona. Verá, esto lleva tiempo (el usuario responde en cuestión de segundos) y necesita una interfaz gráfica de usuario receptiva (los mensajes todavía se bombean en EDT) durante todo este tiempo mientras EDT está bloqueando (no maneja mensajes más nuevos, por ejemplo, JFileChooser, en el cola antes de que se cierre el cuadro de diálogo y finalice la acción del componente actual). El círculo vicioso se rompe cuando EDT ingresa a un nuevo bucle de mensajes, que envía los mensajes como de costumbre hasta que llega el "diálogo modal" y el procesamiento normal de mensajes se reanuda desde la posición bloqueada en la acción del componente.
El proyecto Foxtrot de código abierto emula el bombeo de bucle de mensajes Swing para proporcionar el mecanismo de ejecución "síncrono" para tareas de usuario arbitrarias, que procede solo después de que el trabajador completa la tarea.
botón . addActionListener ( new ActionListener () { public void actionPerformed ( ActionEvent e ) { button . setText ( "Durmiendo ..." ); Texto de cadena = nulo ; intente { text = ( String ) Worker . post ( new Task () { public Object run () lanza Exception { Thread . sleep ( 10000 ); return "Dormido!" ; } }); } captura ( Excepción x ) ...botón . setText ( texto );somethingElse (); } });
Desde Java 1.7, Java proporciona una solución estándar para bucles de mensajes secundarios personalizados al exponer createSecondaryLoop () en el sistema EventQueue ().
Ver también
- Kit de herramientas de ventana abstracta (AWT)
- Columpio (Java)
- SwingWorker
- ComponentUpdateThread
Referencias
- ^ Este problema no es específico de Java Swing . Existe el mismo problema en la mayoría de los kits de herramientas de widgets , como por ejemplo Windows Forms , donde laclase BackgroundWorker realiza el mismo propósito que SwingWorker en Java.
- ^ "El hilo de envío de eventos" . Sun Microsystems . Consultado el 2 de octubre de 2011 .
- ^ "Depurar Swing: ¿es realmente difícil?" . Alexander Potochkin . Archivado desde el original el 5 de agosto de 2011 . Consultado el 2 de octubre de 2011 . Enlace externo en
|publisher=
( ayuda ) - ^ "Hilos iniciales" . Sun Microsystems . Consultado el 2 de octubre de 2011 .
- ^ http://www.pushing-pixels.org/?p=368
enlaces externos
javax.swing
( Documentación de Swing API Javadoc )java.awt
( Documentación de AWT API Javadoc )- Documentación de la API de swing
- El hilo de envío de eventos
- Descripción de SwingWorker del tutorial de Swing
- Artículo sobre manejo de eventos AWT / Swing sobre bombeo, despacho y procesamiento de eventos, y el EDT
- Página de inicio del proyecto Foxtrot