java - event - SwingUtilities.invokeLater
javax swing swingutilities invokelater (5)
Mi pregunta esta vez está relacionada con
SwingUtilities.invokeLater
: ¿Cuándo debería usarlo?
Lo que es clave para comprender es que Java tiene un hilo separado (EDT) que maneja eventos relacionados con Swing.
Debería usar invokeLater()
para mostrar el JFrame
principal de una aplicación de escritorio (por ejemplo), en lugar de intentar hacerlo en el hilo actual. También creará el contexto para el cierre elegante de la aplicación más tarde.
Eso es todo para la mayoría de las aplicaciones.
¿Tengo que usar cada vez que necesito actualizar los componentes de la GUI? ¿Qué hace exactamente?
No. Si modifica un componente de la GUI, activará un evento que se registrará para su posterior envío por Swing. Si hay un oyente para este evento, el hilo EDT lo llamará en algún lugar en el futuro. No necesita usar invokeLater()
, simplemente configure sus oyentes en los componentes correctamente.
Tenga en cuenta que este hilo es el mismo hilo que dibuja marcos, etc ... en su pantalla. Por lo tanto, los oyentes no deben realizar tareas complejas / largas / intensivas en la CPU, de lo contrario su pantalla se congelará.
¿Hay alguna alternativa, ya que no suena intuitivo y agrega un código aparentemente innecesario?
No necesita escribir más código que mostrar su aplicación con invokeLater()
+ oyentes que le interesen en el componente. El resto lo maneja Swing.
Mi pregunta está relacionada con SwingUtilities.invokeLater
. ¿Cuándo debería usarlo? ¿Tengo que usar cada vez que necesito actualizar los componentes de la GUI? ¿Qué hace exactamente? ¿Hay alguna alternativa, ya que no suena intuitivo y agrega un código aparentemente innecesario?
¿Tengo que usar cada vez que necesito actualizar los componentes de la GUI?
No, no si ya está en el hilo de envío del evento (EDT), que siempre es el caso al responder a eventos iniciados por el usuario, como clics y selecciones. (Los métodos actionPerformed
, etc., siempre son llamados por el EDT).
Sin embargo, si no está en el EDT y desea hacer actualizaciones de la GUI (si desea actualizar la GUI a partir de un subproceso del temporizador, o de algún hilo de la red, etc.), tendrá que programar la actualización que realizará el EDT. . Para eso es este método.
Swing es básicamente inseguro. Es decir, toda la interacción con esa API debe realizarse en un único hilo (el EDT). Si necesita hacer actualizaciones de GUI desde otro hilo (hilo de temporizador, hilo de red, ...) necesita usar métodos como el que mencionó (SwingUtilities.invokeLater, SwingUtilities.invokeAndWait, ...).
Cada aplicación Swing tiene al menos 2 hilos:
- El hilo principal que ejecuta la aplicación
- El EDT (Event Dispatching Thread) es un hilo que actualiza la interfaz de usuario (para que la interfaz de usuario no se congele).
Si desea actualizar la UI, debe ejecutar el código dentro de EDT. Métodos como SwingUtilities.invokeLater, SwingUtilities.invokeAndWait, EventQueue.invokeLater, EventQueue.invokeAndWait le permiten ejecutar código mediante el EDT.
La mayoría de los eventos iniciados por el usuario (clics, teclado) ya estarán en el EDT, por lo que no tendrá que usar SwingUtilities para eso. Eso cubre una gran cantidad de casos, a excepción de su thread principal () y subprocesos de trabajo que actualizan el EDT.
Swing is single threaded and all changes to the GUI must be done on EDT
Uso básico para invokeLater()
Los métodos principales deben estar siempre envueltos en
invokeLater()
Acción / evento retrasado (pero asíncrono) al final de
EventQueue
,Si EDT no existe, entonces debe crear un EDT nuevo utilizando
invokeLater()
. Puedes probarlo conif (SwingUtilities.isEventDispatchThread()) {...
Existe
invokeAndWait()
, pero hasta el día de hoy I (solo mi vista) no puede encontrar una razón para usarinvokeAndWait()
vez deinvokeLater()
, excepto cambios duros en GUI (JTree & JTable), pero solo con Substance L & F (excelente para probar la consistencia de eventos en el EDT)Cosas básicas: concurrencia en Swing
Todos los resultados de las tareas en segundo plano deben estar envueltos en
invokeLater()