2011-12-31 18 views
10

ho letto da qualche parte che per tutti i thread che colpisce le immagini della GUI che dovrebbe essere eseguito nella EDT utilizzando SwingUtilities.invokeAndWait/invokeLaterQuando usare SwingUtilies.invokeAndWait/invokeLater

Per una GUI di base, è necessario per inserire qualcosa come new SwingGUI().setVisible(true); nella riga di EDT usando invokeAndWait? Solo per visualizzare?

Conta questo?

risposta

3

Sì, se si tocca un oggetto Swing, è necessario farlo sull'EDT. Nella maggior parte dei casi sei già lì, ma in caso contrario, utilizza le classi SwingUtilities. La ragione di ciò è che le classi Swing non sono multi-thread, quindi è probabile che si verifichino problemi fastidiosi se si accede ad altri thread. E potrebbe essere che setVisible() stia facendo un sacco di cose sotto le copertine per far visualizzare qualcosa (come ri-sistemare le cose). Meglio essere al sicuro.

+0

Quando non sono in esecuzione sotto EDT? Quindi cosa intendi se faccio un thread per cambiare qualcosa dovrei eseguirlo con uno di questi metodi giusto? Ma non sto facendo un altro thread, sto solo correndo sul thread predefinito giusto? Quindi non renderebbe setVisible in invokeAndWait inutile? –

+2

Se lo si sta eseguendo sul thread "predefinito" (principale), allora * non * è in EDT. – Darkhogg

+0

Dai uno sguardo ai link nella risposta di @ Robin. Il thread principale non è lo stesso del thread EDT, ma spesso il codice che stai usando con Swing è codice per gestire un evento e quindi su EDT. –

9

La risposta breve alla tua domanda è: sì, anche chiamare setVisible dovrebbe avvenire sull'EDT. Per scoprire se il thread corrente è l'EDT, è possibile utilizzare il metodo EventQueue#isDispatchThread

Alcuni link di riferimento:

Edit: dopo leggendo i link che ho fornito, sembra che alcuni degli articoli sul sito Oracle siano obsoleti come nel loro documento ancora è possibile creare componenti Swing su un altro thread. C'è uno stackoverflow question su questo che contiene alcune belle risposte e link a blog e articoli sulla politica 'nuova' (nuovi come in pochi anni)

-1

Tutto ciò che accede agli oggetti Swing dovrebbe farlo tramite il thread di invio eventi (EDT). C'è una piccola eccezione a questa (che menzionerò più avanti). Lo scopo di EDT è di elaborare qualsiasi evento che possa verificarsi a causa di eventi I/O (mouse e tastiera). Molto spesso questo può significare alterare il layout della tua GUI. Swing non è stato sviluppato per essere thread-safe, nel senso che se due thread tentano di modificare lo stesso componente nello stesso momento, si può finire con una GUI corrotta. Poiché esiste già un thread noto per accedere ai componenti di Swing (EDT), nessun altro thread dovrebbe tentare di modificarli o persino leggere il loro stato.

Ora, nel caso eccezionale in cui è possibile manipolare oggetti Swing al di fuori dell'EDT. Prima che tutti i componenti siano diventati visibili non è possibile che IO stia attivando eventi. Pertanto, il thread principale può configurare una GUI Swing e quindi impostare una singola JFrame per essere visibile. Poiché ora esiste un frame visibile, possono verificarsi eventi I/O e il thread principale non dovrebbe provare a modificare altri componenti Swing. Dovrebbe usare questa opzione solo per avviare una GUI, e in realtà solo con problemi di giocattoli.

Quello che sto dicendo è che quanto segue va bene e non causerà problemi se si sta solo giocando con roba del genere.

public static void main(String[] args) { 
    // create components 
    JFrame f = new JFrame(); 
    ... 

    // do layout and other bits of setup 


    // show gui to user 
    f.setVisible(true); 
} 
+3

-1: le regole di threading Swing sono state aggiornate. È necessario accedere a tutti i componenti su EDT, anche quando non sono visibili. Vedi http://stackoverflow.com/questions/491323/is-it-safe-to-construct-swing-awt-widgets-not-on-the-event-dispatch-thread/491377#491377 – Robin

0

Tutto ciò che viene chiamato dal

public static void main(String[] agrs) { 

direttamente (senza deposizione delle uova un altro thread o utilizzando invokeLater) è in esecuzione sul thread principale.

L'accesso agli oggetti GUI con il thread principale mentre è possibile che si acceda (simultaneamente) dall'EDT (che viene attivato dall'input dell'utente) può causare problemi di threading. Chiamando invokeLater, le attività (eseguibili) vengono eseguite sull'EDT, impedendo l'accesso simultaneo da parte di altre attività EDT, ad es. pressioni dei pulsanti, ecc.

Se si è certi che EDT non è occupato (prima che la prima finestra sia impostata su SetVisible (true)) è possibile accedere alla GUI dal thread principale. Se si può essere sicuri che EDT non abbia alcun riferimento al componente su cui si sta lavorando (è fuori dall'ambito di EDT) vale a dire. prima di essere aggiunto a qualsiasi contenitore, è possibile accedervi dal thread principale senza che l'EDT lo acceda contemporaneamente, poiché l'EDT non ha modo di raggiungerlo.

+0

No. Even is not visibile ancora, è necessario accedere a una finestra dall'EDT. Vedi il commento di Robin sulla risposta di Dunes. –