stringtranslate.com

Hilo de envío de eventos

El subproceso de distribución de eventos (EDT) es un subproceso 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 basada en 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 a sí mismos, 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 subproceso de envío de eventos es el único subproceso válido para actualizar el estado visual de los componentes de la interfaz de usuario visibles. La actualización de los componentes visibles desde otros subprocesos es la fuente de muchos errores comunes en los programas Java que usan Swing . [1] El subproceso de envío de eventos se denomina trabajador primordial en Adobe Flash y subproceso de UI en SWT , .NET Framework y Android .

Bucle de mensajes para serializar accesos a la GUI

Una aplicación de software normalmente consta de varios subprocesos y una única estructura de datos GIT. Esto significa que GIT 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 ( inseguros para subprocesos ) para crear y acceder a los componentes de la GUI y estos métodos son visibles para todos los subprocesos de la aplicación, de la misma manera en otros marcos de GUI, solo un único subproceso 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 al extremo de negarse a instanciar cualquier componente Swing cuando no se ejecuta dentro del subproceso de despacho de eventos, [5] para evitar tal error de codificación. El acceso a la GUI está serializado 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, al igual que en otros marcos de GUI, el subproceso de envío de eventos pasa su vida enviando mensajes: mantiene una cola de mensajes de acciones que se deben realizar a través de la GUI. Estas solicitudes son enviadas a la cola por el sistema y cualquier subproceso de aplicación. EDT las consume una tras otra y responde actualizando los componentes de la GUI. Los mensajes pueden ser acciones conocidas o involucrar devoluciones de llamadas, las referencias a métodos de usuario que deben ejecutarse por medio de 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 de 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 (escuchadores)

Los componentes de la GUI admiten listas de devoluciones de llamadas, llamadas Listeners, que normalmente se completan cuando se crean los componentes. EDT ejecuta los listeners cuando el usuario activa los componentes de alguna manera (se hace clic en un botón, se mueve el mouse, se selecciona un elemento, se pierde el foco, se cambia el tamaño del componente, etc.).

Minutero

Se utiliza para tareas breves que deben acceder o modificar la GUI periódicamente o en un momento específico javax.swing.Timer. Se puede considerar como un componente de GUI invisible, cuyos oyentes están registrados para activarse en momentos específicos.

Equivalentes

Solicitudes de otros hilos

Otros subprocesos de la aplicación pueden pasar algún código para que se ejecute en el subproceso de envío de eventos mediante SwingUtilitiesclases auxiliares (o EventQueuesi está haciendo AWT ). El código enviado debe estar envuelto con un Runnableobjeto. Dos métodos de estas clases permiten:

del hilo de envío de eventos.

El método invokeAndWait()nunca debe llamarse desde el hilo que distribuye el evento, ya que generará una excepción . El método SwingUtilities.isEventDispatchThread()o EventQueue.isDispatchThread()puede llamarse para determinar si el hilo actual es el hilo que distribuye el evento.

El código suministrado mediante invokeLatery invokeAndWaital EDT debe ser lo más rápido posible para evitar que se bloquee. Normalmente, su finalidad es entregar el resultado de un cálculo largo 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 la EDT se pueden combinar mediante el patrón de diseño worker . La javax.swing.SwingWorkerclase, desarrollada por Sun Microsystems , es una implementación del patrón de diseño worker y, a partir de Java 6, forma parte de la distribución Swing estándar. SwingWorker se invoca normalmente desde el evento ejecutado por la EDT Listener para realizar una tarea larga con el fin de no bloquear la EDT.

Muestras

SwingWorker < Documento , Void > trabajador = nuevo SwingWorker < Documento , Void > () { público Documento doInBackground () lanza IOException { devolver loadXML (); // tarea pesada } público void hecho () { intentar { Documento doc = obtener (); mostrar ( doc ); } atrapar ( Excepción ex ) { ex . printStackTrace (); } } }; trabajador . ejecutar ();                                     

Si usas Groovy y groovy.swing.SwingBuilder, puedes usar doLater(), doOutside(), y edt(). Luego puedes escribirlo de forma más sencilla, así:

doOutside { def doc = loadXML () // tarea pesada edt { display ( doc ) } }          

Equivalentes

Ejecución modal

Normalmente, EDT crea SwingWorker para tareas extensas mientras maneja eventos de devolución de llamada (Listener). Al generar un subproceso de trabajo, EDT procede a manejar el mensaje actual sin esperar a que el trabajador termine. A menudo, esto no es deseable.

A menudo, su EDT maneja una acción de componente GUI, que exige que el usuario haga una elección por medio de otro cuadro de diálogo, como JFileChooser, que aparece, permanece responsivo mientras el usuario elige su opción y la acción continúa con el archivo seleccionado solo después de presionar el botón "Aceptar". Verá, esto lleva tiempo (el usuario responde en cuestión de segundos) y necesita una GUI responsiva (los mensajes aún se envían a EDT) durante todo este tiempo mientras EDT está bloqueado (no maneja mensajes más nuevos, por ejemplo, JFileChooser, en la 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 en un nuevo bucle de mensajes, que envía los mensajes de manera normal hasta que llega el "diálogo modal terminado" y el procesamiento normal de mensajes se reanuda desde la posición bloqueada en la acción del componente.

El proyecto de código abierto Foxtrot emula el bombeo de bucle de mensajes Swing para proporcionar el mecanismo de ejecución "sincrónico" para tareas de usuario arbitrarias, que continúa solo después de que el trabajador completa la tarea.

 botón .addActionListener ( new ActionListener () { público void actionPerformed ( ActionEvent e ) { botón .setText ( " Durmiendo..." ) ;       Cadena texto = null ; try { texto = ( Cadena ) Trabajador.post ( nueva Tarea () { objeto público ejecutar () lanza Excepción { Hilo.sleep ( 10000 ) ; devolver " ¡Durmió!" ; } } ) ; } catch ( Excepción x ) ...                      botón .setText ( texto ) ;algoMás (); } });  

Desde Java 1.7, Java proporciona una solución estándar para bucles de mensajes secundarios personalizados al exponer createSecondaryLoop () en el sistema EventQueue ().

Véase también

Referencias

  1. ^ 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 la clase BackgroundWorker realiza el mismo propósito que SwingWorker en Java.
  2. ^ "El hilo de envío de eventos". Sun Microsystems . Consultado el 2 de octubre de 2011 .
  3. ^ "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 .
  4. ^ "Hilos iniciales". Sun Microsystems . Consultado el 2 de octubre de 2011 .
  5. ^ "Controles más estrictos sobre las violaciones de EDT en Substance · Pushing Pixels".

Enlaces externos