2011-10-25 4 views
8

Ho imparato a sapere come lo swing non è sicuro per i thread. Scavando più a fondo, ho scoperto che ogni modifica a un componente swing deve essere eseguita sul thread di invio eventi per evitare vari problemi associati al multithreading. Tuttavia, le informazioni sembravano fermarsi completamente lì. Non sembra essere un buon tutorial che spiega come farlo ovunque sia accessibile su Internet.Come si usa il thread di invio eventi?

Patching insieme le informazioni dal codice scritto in relazione ad altre questioni, sembrava che avrei dovuto mettere un blocco disordinato di codice intorno ad ogni singola modifica oscillazione nel mio programma (come in questo esempio dal mio proprio codice):

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

Fondamentalmente, è giusto? Devo inserire quel codice (o l'equivalente di invokeLater) attorno ad ogni modifica di un componente Swing nel mio codice?

Inoltre, perché Swing non lo fa automaticamente?

risposta

6

Il trucco è che quando lo swing ti chiama sarà SEMPRE nell'EDT, quindi non devi preoccuparti di questo.

Tuttavia se si è in un timer o un'azione innescata da qualche altro evento esterno, il thread principale o qualsiasi altro thread che si è creato allora sì, è necessario utilizzare invokeLater o invokeAndWait.

In altre parole, sì swing lo fa "automaticamente" automaticamente. Avere bisogno di usare invokeXx è così raro che se lo swing lo facesse internamente perderebbe troppo tempo.

Molti programmatori Java non riescono mai a capirlo e questo può causare alcuni problemi piuttosto difficili da trovare con il disegno della GUI. Desidero che lo swing abbia generato un'eccezione quando l'hai chiamato non usando l'EDT - Java avrebbe avuto una migliore reputazione quando si trattava di GUI professionali se lo avesse fatto perché ci sarebbe stata meno schifo là fuori.

+0

non è buono come quello che desideri, ma puoi installare il codice di rilevamento automatico delle violazioni Swing/EDT e riscuotono un sacco di errori (non hai alcun collegamento a portata di mano ma ce ne sono alcuni). – TacticalCoder

+0

Microsoft nell'era di Windows 3.0/3.1 aveva "Debug Binaries" che eseguivano questo tipo di controllo in modo da non dover riavviare ogni volta che si inviavano argomenti non validi. Mi ha sempre infastidito il fatto che Java non avesse lo stesso, specialmente perché è abbastanza intelligente da essere in grado di compilarlo su un interruttore della riga di comando. –

+1

L'ho sempre usato per mettere "in" l'app Java, sostituendo il/i gestore/i ridisegno con * CheckThreadViolationRepaintManager *. Ricordo che funzionava abbastanza bene:) – TacticalCoder

3

Fondamentalmente, non si disegna o si aggiorna la GUI dall'esterno di EDT. È possibile utilizzare SwingUtilitis.invokeLater() da un altro thread per garantire che il disegno o il codice di aggiornamento della GUI venga eseguito sull'EDT.

+0

Solo il codice di disegno? Posso liberarmi della disordinatezza attorno a cose come setSize() e setVisible()? – Tharwen

+0

disegnando il codice, implica qualsiasi aggiornamento ai componenti della GUI, quindi sì, setSize() e setVisible() fanno parte del codice drawin. – Zaki

+0

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

4

nota che qualsiasi codice eseguito da gestori di eventi è già eseguito nel EDT (l'evento nella sigla)

questo significa che per uso generale (anche se non si scherza con swingworkers e threadpools e simili) si sei sempre all'interno del EDT

e si può sempre query se si è in EDT con SwingUtilities.isEventDispatchThread()

notare, inoltre, che nel codice la chiamata a invokeAndWait fallirà e gettare un errore quando si è in EDT già

3

Non tutto il codice UI deve essere parte di un eseguibile in una chiamata invokeLater. Questo è semplicemente perché gran parte del tuo programma verrà comunque eseguito su EDT. È necessario inviare messaggi all'EDT solo quando si è su un thread diverso.