2011-10-25 13 views
8

Aprendí cómo el swing no es seguro para hilos. Profundizando más, descubrí que cada modificación de un componente de oscilación debe hacerse en el subproceso de envío de evento para evitar varios problemas asociados con el multihilo. Sin embargo, la información parecía detenerse por completo allí. No parece haber un buen tutorial que explique cómo hacer esto en cualquier lugar accesible en Internet.¿Cómo se usa el subproceso de distribución de eventos?

parches acumular información de código publicado en relación con otras cuestiones, parecía que iba a tener que poner un bloque desordenado de código en cada modificación de oscilación sola en mi programa (como en este ejemplo de mi propio código):

try { 
     SwingUtilities.invokeAndWait(new Runnable() { 

      public void run() { 
       setTitle("Frame title"); 
       setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       setVisible(true); 

       setSize(800, 480); 
       setLocationRelativeTo(null); 
       setIconImage(Toolkit.getDefaultToolkit().createImage(ClassLoader.getSystemResource("Frame icon.png"))); 
      } 
     }); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

Básicamente, ¿es esto correcto? ¿Tengo que poner ese código (o el equivalente con invokeLater) en cada modificación de un componente Swing en mi código?

Además, ¿por qué Swing no hace esto automáticamente?

Respuesta

6

El truco es que cuando el columpio lo llama SIEMPRE estará en el EDT, por lo que no tiene que preocuparse por ello.

Sin embargo, si tiene un temporizador o una acción desencadenada por otro evento externo, el hilo principal o cualquier otro hilo que haya creado, entonces sí, tiene que usar invokeLater o invokeAndWait.

En otras palabras, sí, el swing lo hace "eso" automáticamente. Necesitar usar invokeXx es tan raro que si swing lo hiciera internamente, perdería demasiado tiempo.

Muchos programadores de Java nunca se dan cuenta de esto y puede causar algunos problemas bastante desagradables difíciles de encontrar al dibujar su GUI. Ojalá Swing lanzara una excepción cuando lo llamaste no usar el EDT - Java tendría una mejor reputación cuando se tratara de GUIs profesionales si lo hiciera porque habría menos basura ahí fuera.

+0

no es tan bueno como lo desees, pero puedes instalar el código de detección de violación Swing/EDT automático y cometen bastantes errores (no tienes ningún enlace a mano pero hay bastantes). – TacticalCoder

+0

Microsoft en la era de Windows 3.0/3.1 tenía "binarios de depuración" que harían este tipo de comprobación para que no tenga que reiniciar cada vez que envíe argumentos incorrectos. Siempre me molestaba que Java no tuviera lo mismo, especialmente porque es lo suficientemente inteligente como para poder compilarlo en un conmutador de línea de comandos. –

+1

Solía ​​ponerlo siempre "en" la aplicación Java, reemplazando los gestores de repintado con * CheckThreadViolationRepaintManager *. Recuerdo que funcionó bastante bien:) – TacticalCoder

3

Básicamente, no dibuja ni actualiza la GUI desde fuera del EDT. Utiliza SwingUtilitis.invokeLater() de otro subproceso para garantizar que el dibujo de la GUI o el código de actualización se ejecute en el EDT.

+0

¿Solo el código de dibujo? ¿Puedo deshacerme de la falta de limpieza en cosas como setSize() y setVisible()? – Tharwen

+0

al dibujar código, implica cualquier actualización de los componentes de la GUI, así que sí, setSize() y setVisible() es parte del código drawin. – Zaki

+0

Consulte http://stackoverflow.com/q/7196889/100836 – Zaki

4

nota de que cualquier código que se ejecuta a partir de controladores de eventos que ya se ejecuta en el EDT (el evento en sus siglas inglesas)

esto significa que para uso general (mientras no se metan con swingworkers y threadpools y tal) que está siempre dentro de la EDT

y siempre se puede consultar si se encuentra en la EDT con SwingUtilities.isEventDispatchThread()

también en cuenta que en el código de la llamada a invokeAndWait fallará y emite un error cuando se está en la EDT ya

3

No todo su código de UI debe ser parte de un ejecutable en una llamada invokeLater. Eso es simplemente porque una gran parte de tu programa se ejecutará en el EDT de todos modos. Debe enviar mensajes al EDT solo cuando se encuentre en un hilo diferente.

Cuestiones relacionadas