2010-04-02 18 views
13

Según tengo entendido, si inicio otro hilo para realizar algunas acciones, necesitaría SwingUtilities.invokeAndWait o SwingUtilities.invokeLater para actualizar la GUI mientras estoy en dicho hilo. Por favor corrígeme si estoy equivocado.Swing Threading de Java

Lo que intento lograr es relativamente sencillo: cuando el usuario hace clic en enviar, quiero (antes de realizar cualquier acción) deshabilitar el botón Enviar, realizar la acción y, al final de la acción, volver a habilitar el botón. Mi método para realizar la acción actualiza la GUI directamente (muestra resultados) cuando recupera los resultados.

Esta acción básicamente consulta un servidor y obtiene algunos resultados.

Lo que tengo hasta ahora es:

boolean isRunning = false; 

synchronized handleButtonClick() { 
    if (isRunning == false) { 
    button.setEnabled(false); 
    isRunning = true; 
    doAction(); 
    } 
} 

doAction() { 
    new Thread() { 
    try { 
     performAction(); // Concern A 
    } catch (...) { 
     displayStackTrace(...); // Concern B 
    } finally { 
     SwingUtilities.invokeLater (/* simple Runnable to enable button */); 
     isRunning = false; 
    } 
    } 
} 

Para ambos de mis preocupaciones anteriores, no tendría que utilizar SwingUtilities.invokeAndWait ya que ambos van a actualizar la interfaz gráfica de usuario? Todas las actualizaciones GUI giran en torno a la actualización JTextPane. ¿Debo verificar mi hilo si estoy en EDT y, de ser así, puedo llamar a mi código (independientemente de si actualiza la GUI o no) y NO usar SwingUtilities.invokeAndWait?

EDIT: Esto es lo que estoy haciendo ahora:

handleButtonClick() { 
    if (isRunning == true) 
    return; 
    disable button; 
    SwingWorker task = new MyTask(); 
    task.execute(); 
} 

...inside MyTask 
doInBackground() { 
    return performAction(); 
} 

done() { 
    result = get(); 
    enable button; 
    isRunning = false; 
    interpret result (do most of the GUI updates here); 
} 

Mientras performAction() hace algunos cambios GUI, he envuelto aquellos en:

if (SwingUtil.isEDT()) 
    doGUIupdate() 
else 
    SwingUtil.invokeLater(new Runnable() { 
    run() { 
     doGUIupdate(); 
    } 
    }); 

Esperemos que este es un paso en la dirección correcta , por favor coméntenos si cree que hay mejores formas de manejar mi situación.

+1

Uso SwingWorker. http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html –

+0

Tenía la impresión de que SwingWorker debería usarse para algo "largo" mientras que SwingUtilities se usó para algo "rápido" ? – nevets1219

+0

Como SwingUtilities se ejecuta en el subproceso "UI", debería utilizarse para que algo rápido sea práctico; de lo contrario, podría bloquear la interfaz de usuario. Ninguno de los dos se ejecutará en "otro hilo". –

Respuesta

18

En mi opinión, casi nunca deberías usar invokeAndWait(). Si algo va a tomar un tiempo que bloqueará su UI.

Utilice un SwingWorker para este tipo de cosas. Eche un vistazo al Improve Application Performance With SwingWorker in Java SE 6.

+0

¡Excelente enlace, a mitad de camino y me ha revelado un poco! – nevets1219

+1

invokeAndWait() no bloquea la interfaz de usuario: bloquea el subproceso de ayuda hasta que la interfaz de usuario haya tenido la oportunidad de ejecutar el Runnable transferido. invokeAndWait() en realidad comprueba para asegurarse de que no está siendo llamado desde el EDT (que causaría el bloqueo). Por supuesto, debería decir que el uso de invokeAndWait() generalmente significa que el programador no está utilizando correctamente la programación basada en eventos (observador) ... –

+1

El uso de 'invokeAndWait' a menudo conduce a un interbloqueo. –

5

Debería considerar el uso de SwingWorker ya que no bloqueará el subproceso de interfaz de usuario, mientras que ambos métodos SwingUtilities se ejecutarán en el subproceso EDT, lo que bloquea la interfaz de usuario.

+1

SwingWorker ejecuta su método done() en el EDT. Es lo mismo que iniciar su propio hilo no EDT que llama a SwingWorker.invokeLater() para actualizar la interfaz de usuario cuando haya terminado. SwingWorker es un poco más cómodo de usar que tirarlo tú mismo. –

+0

Buen punto; Aun así, recomiendo usar 'SwingWorker'. –

+1

@Scott ¿te refieres a SwingUtilities? – nevets1219

0

me quedo con la sencilla Thread dentro EventQueue.invokeLater(...) y que funcionó sin problemas ...

java.awt.EventQueue.invokeLater(new Runnable() { 
    public void run(){ 

     new Thread(new Runnable(){ 
      public void run(){ 

       try{ 
        EdgeProgress progress = EdgeProgress.getEdgeProgress(); 
        System.out.println("now in traceProgressMonitor..."); 
        while(true){ 
         // here the swing update 
         if(monitor.getState() == ProgressMonitor.STATE_BUSY){ 
          System.out.println(monitor.getPercentDone()/2); 
          progress.setProgress(monitor.getPercentDone()/2); 
         }else{ 
          break; 
         } 
         Thread.sleep(5); 
        } 
       }catch(InterruptedException ie){} 

      } 
     }).start(); 

    } 
});