2011-02-07 15 views
8

Qual è il modo corretto di aggiornare l'interfaccia utente dopo aver eseguito alcune operazioni su Swing?Swing, come aggiornare correttamente l'interfaccia utente

Ad esempio, dopo aver fatto clic su un pulsante, viene chiamato un metodo che può essere quasi istantaneo o richiedere alcuni secondi. Di fatto, tutta la logica dell'application viene eseguita a distanza tramite un servizio Web, quindi è normale attendere un po 'affinché l'applicazione risponda.

mio EventHandler per un pulsante può apparire come questi:

myButton.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(java.awt.event.ActionEvent evt) { 
     //callWebService(); 
     //do stuff 
     //updateUI(); // <----- repaint? revalidate? what? 
    } 
}); 

Il mio attuale implementazione chiama il metodo updateUI che chiamano internamente validate() e riverniciare() per la componente principale che contiene l'interfaccia utente. Funziona, ma a volte riesco a vedere lo sfarfallio dello schermo. Sto sbagliando? C'è un modo migliore per farlo?

+0

http://en.wikipedia.org/wiki/SwingWorker – qwerty

+0

A quanto ho capito, questa domanda riguarda l'aggiornamento dell'interfaccia utente dopo aver fatto qualcosa, non di fare cose in un altro thread per mantenere l'interfaccia utente reattiva. Non capisco proprio perché il tempo di esecuzione del metodo è stato menzionato nella domanda, però. –

+0

Ho menzionato il tempo di esecuzione perché sembra che Swing si comporti in modo un po 'diverso quando si tenta di caricare i componenti e il carico impiega troppo tempo, quindi potrebbe essere necessario ridisegnare lo schermo. – Hectoret

risposta

0

Normalmente non si dovrebbe fare nulla: se si usano i metodi dei componenti swing oi metodi del loro modello, gli eventi necessari vengono attivati ​​e la GUI dovrebbe aggiornarsi automaticamente.

Questo non sarà il caso se si definisce i propri modelli (e dimenticare di sparare gli eventi necessari, ma poi è un bug nei modelli, e dovrebbe essere fissato lì.

+0

Quindi, se chiamo, ad esempio, il metodo JSpinner.setValue() nel thread di elaborazione degli eventi della GUI, dovrebbe aggiornare automaticamente l'interfaccia utente? Ricordo che non lo faceva a volte in una delle mie applicazioni. Se avessi spostato la finestra o avessi fatto qualcosa che lo avrebbe invalidato (come temporaneamente oscurato qualche altra finestra), allora si aggiornerebbe. Era un bug nel JRE? –

+0

Sì, ti dovrebbe aggiornare automaticamente la GUI (una volta che non c'è nient'altro da fare nel thread di invio eventi (EDT)) e se si è sicuri di chiamare il metodo nell'EDT. Non posso dire perché non ha funzionato in una delle tue app, ma dovrebbe. –

1

Prendere la lunga esecuzione Invia ad altri eventi il ​​thread di invio eventi (EDT) per aggiornare la GUI con java.awt.EventQueue.invokeLater.

5

Il modo corretto sarebbe utilizzare SwingWorker, ma se vuoi farlo manualmente avrai per implementare il seguente schema:

@Override public void actionPerformed(java.awt.event.ActionEvent evt) { 
    new Thread() { 
    @Override public void run() { 
     //callWebService(); 
     //do stuff 
     SwingUtilities.invokeLater(new Runnable(){ 
     @Override public void run() { 
      //updateUI(); // <----- repaint? revalidate? what? 
     } 
     }); 
    } 
    }.start(); 
} 

Per la domanda di riverniciatura/riconvocazione, chiamare normalmente revalidate() quindi repaint(). questo è, ovviamente, valido solo per il componente che disegni manualmente. Per i componenti che riutilizzi, chiama semplicemente i loro metodi di modifica del valore.

+0

Perché non si utilizza SwingWorker come "corretto" per farlo? Fornisce un'interfaccia piacevole e facile da usare che gestisce tutti gli elementi di callback per te e fornisce un modo semplice per aggiornare l'interfaccia utente quando l'attività è completa. – berry120

+2

@berry, ho pensato che "senza SwingWorker, che è il modo giusto per farlo" era inteso come "usare Swing worker è il modo giusto, ma se vuoi farlo senza usarlo ..." –

+1

Ah, capisco - un po 'ambiguo, penso che possa essere preso in entrambi i modi! – berry120

4

io personalmente uso SwingWorker per questo, nonostante alcuni degli altri commenti/risposte:

  • Nonostante il fatto mantenendo l'interfaccia utente sensibile non è parte della domanda originale, è buona norma fare questo comunque (non riesco a pensare a una sola buona ragione per bloccare l'EDT con elaborazione lunga.)
  • Fornisce un metodo done() che può essere implementato che verrà eseguito sull'EDT di default quando l'attività è completa, salvando la necessità di avvolgere manualmente le cose in invokeLater()
  • È più ex Tensibile, fornendo la struttura per consentire l'aggiunta di informazioni come il progresso in un secondo momento, se lo si desidera.

Ho visto un sacco di odio SwingWorker in generale di recente, e non capisco perché. Si tratta di una classe estensibile e ben progettata appositamente per scopi come questo che funziona bene. Sì, puoi avvolgere le cose nei thread e lanciarli e farli avvolgere altri metodi in invokeLater(), ma perché reinventare la ruota quando ce n'è una migliore disponibile gratuitamente?

Problemi correlati