2010-04-02 11 views
13

La mia comprensione è che se avvio un altro thread per eseguire alcune azioni, avrei bisogno di SwingUtilities.invokeAndWait o SwingUtilities.invokeLater per aggiornare la GUI mentre sono in detto thread. Per favore correggimi se sbaglio.Java's Swing Threading

Quello che sto cercando di realizzare è relativamente semplice: quando l'utente fa clic su Invia, voglio (prima di eseguire qualsiasi azione) disabilitare il pulsante di invio, eseguire l'azione, e al termine dell'azione riabilitare il pulsante. Il mio metodo per eseguire l'azione aggiorna direttamente la GUI (mostra i risultati) quando restituisce i risultati.

Questa azione interroga fondamentalmente un server e ottiene alcuni risultati.

Quello che ho finora è:

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; 
    } 
    } 
} 

Per entrambe le mie preoccupazioni di cui sopra, non avrei dovuto usare SwingUtilities.invokeAndWait poiché entrambi aggiornerà la GUI? Tutti gli aggiornamenti della GUI ruotano attorno all'aggiornamento JTextPane. Devo controllare nel mio thread se sono su EDT e in tal caso posso chiamare il mio codice (indipendentemente dal fatto che aggiorni la GUI o meno) e NON usare SwingUtilities.invokeAndWait?

EDIT: Ecco quello che sto facendo ora:

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); 
} 

Mentre performAction() fa alcuni aggiornamenti GUI, ho avvolto quelli di:

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

Speriamo che questo sia un passo nella giusta direzione , per favore commenta se credi che ci siano modi migliori per gestire la mia situazione.

+1

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

+0

Ho avuto l'impressione che SwingWorker debba essere usato per qualcosa di "lungo" mentre SwingUtilities è stato usato per qualcosa di "veloce" ? – nevets1219

+0

Poiché SwingUtilities viene eseguito sul thread "UI", dovrebbe essere utilizzato per rendere la pratica veloce; altrimenti potrebbe bloccare l'interfaccia utente. Né verrà eseguito in "un altro thread". –

risposta

18

A mio parere non si dovrebbe quasi mai usare invokeAndWait(). Se qualcosa richiederà un po 'di tempo, bloccherà la tua interfaccia utente.

Utilizzare un SwingWorker per questo genere di cose. Dai un'occhiata a Improve Application Performance With SwingWorker in Java SE 6.

+0

Ottimo link, a metà e mi ha rivelato un bel po '! – nevets1219

+1

invokeAndWait() non blocca l'interfaccia utente: blocca il thread di supporto finché l'interfaccia utente non ha la possibilità di eseguire Runnable passato. invokeAndWait() verifica effettivamente che non venga chiamato dall'EDT (che causerebbe il blocco). Ovviamente dovrei dire che l'uso di invokeAndWait() in genere significa che il programmatore non sta utilizzando correttamente la programmazione event-driven (observer) ... –

+1

L'uso di 'invokeAndWait' porta spesso a deadlock. –

5

Si consiglia di utilizzare SwingWorker poiché non bloccherà il thread dell'interfaccia utente, mentre entrambi i metodi SwingUtilities verranno eseguiti sul thread EDT, bloccando così l'interfaccia utente.

+1

SwingWorker esegue il suo metodo done() sull'EDT. È come avviare il proprio thread non-EDT che chiama SwingWorker.invokeLater() per aggiornare l'interfaccia utente quando hai finito. SwingWorker è solo un po 'più comodo da usare rispetto a rotolare da soli. –

+0

Buon punto; Consiglio comunque di usare 'SwingWorker'. –

+1

@Scott intendevi SwingUtilities? – nevets1219

0

tengo la semplice Thread all'interno EventQueue.invokeLater(...) e che ha funzionato senza intoppi ...

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(); 

    } 
});