2015-05-08 19 views
7

Als ich versuchte zu sehen, ob ich this question earlier today beantworten konnte. Ich erkannte, dass ich die Event Dispatch Thread (EDT) nicht vollständig verstehe. Googling beide bestätigten und halfen damit und verdeutlichten why I don't. (This könnte auch für das Verständnis relevant sein.)Wie ermöglicht das Ignorieren des Ereignisversand-Threads, dass dieses Programm funktioniert?

Der Code erstellt eine GUI und später (wie in der früheren Frage) aktualisiert ein Textfeld, bis ein Flag nicht festgelegt ist.

Ich habe mehrere Fragen/Wünsche.

  • Bitte beschreiben Sie den Code unten in Ordnung läuft, wenn beide Anrufe (zu swingInit und doIt) außerhalb des invokeLater Block sind (wie dargestellt), da beide Anrufe beeinflussen oder die GUI abfragen noch weder auf dem EDT ausgeführt werden (sind sie?). Ist das nicht einladender Misserfolg?

  • -Code läuft auch, wenn Aufruf swingInit innen und außen doItinvokeLater. Also swingInit wird auf dem EDT ausgeführt, sollte aber nicht doIt auf dem EDT nicht ein Problem sein? (Ich war überrascht, dass das funktionierte Sollte ich gewesen sein.?)

  • Ich glaube, ich verstehe, warum es hängt, wenn doIt innen invokeLater ist unabhängig davon, wo swingInit ist: der Zweck invokeLater ist NUR initialisieren die GUI (Recht?).

  • Sollte doIt nur (von einem Ereignis eventuell auftretende) initiiert werden auf dem EDT aber sicherlich nicht innerhalb invokeLater Block?

(Die Geschichte des EDT-Konzept ist interessant. Es ist nicht immer so war. Link Siehe oben "warum ich nicht" verstehen.)

import static java.awt.EventQueue.invokeLater; 
import java.awt.event.*; 
import javax.swing.*; 

public class Whatever 
{ 
    static boolean flag = true; 
    static JTextField tf = new JTextField("Hi",20); 
    static JPanel p = new JPanel(); 
    static JFrame f = new JFrame(); 
    static JButton b = new JButton("End"); 

    public static void main(String[] args) 
    { 
    swingInit(); 

    invokeLater 
    (
     new Runnable() 
     { 
     @Override 
     public void run() 
     { 
    // swingInit(); 
    // doIt(); 
     } 
     } 
    ); 
    doIt();  
    } 

    static void swingInit() 
    { 
    b.addMouseListener 
    (
     new MouseAdapter() 
     { 
      @Override 
      public void mouseClicked(MouseEvent e) 
      { 
      flag = false; 
      JOptionPane.showMessageDialog(null,"Clicked... exiting"); 
      System.exit(0); 
      } 
     } 
    ); 

    p.add(tf); 
    p.add(b); 
    f.add(p); 
    f.setVisible(true); 
    f.pack(); 
    f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
    } 

    static String getInfo(){ 
    return "Hello... " + Math.random(); 
    } 

    static void doIt(){ 
    while(flag)  
     tf.setText(getInfo()); 
    }; 
} 
+1

Wie ich denke, Sie verstehen, sollten Sie die GUI nicht von anderen Threads als der EDT aktualisieren - jedoch nicht * unbedingt * scheitern - es ist nur sehr riskant. Seien Sie also nicht überrascht, wenn ein solcher Code manchmal zu funktionieren scheint. – DNA

Antwort

3

jedes Ihrer Aufzählungszeichen Punkt:

  • Der Code wird auf dem Hauptthread gestartet - das EDT wird parallel laufen. swingInit kehrt nach der UI-Konstruktion, die dann von der EDT unter Kontrolle, dotIt erlaubt sein Ding parallel auf dem Haupt-Thread wie oben

  • ähnliche Situation zu tun, aber hier gibt es auf dem Aufbau der Benutzeroberfläche ist garantiert EDT (wie von Oracle empfohlen).

  • Eine lange laufende Aufgabe wird auf dem EDT platziert, um zu verhindern, dass er angezeigt wird (wenn vor swingIt platziert) oder Malen und Interagieren (wenn danach platziert). the purpose of invokeLater is ONLY to initialize the GUI Der Zweck ist, nicht-Thread-sichere Swing-Aufrufe auf dem EDT zu platzieren. Wenn innerhalb der Hauptmethode würde ich empfehlen, SwingUtilities.invokeAndWait

  • zu verwenden Wenn Sie die Benutzeroberfläche wie folgt aktualisieren möchten, können Sie dies mit einer SwingTimer tun.

Lauf EDT spezifischen, nicht-Thread-sicheren Code außerhalb des EDT garantiert nicht Ausfall, aber es funktioniert Ausfall (über Konflikte einladen, wenn zwei (oder mehr) Threads versuchen, Daten an die aktualisieren gleiche Zeit).

Ich verbrachte Stunden stundenlanges Aufspüren eines mysteriösen NullPointerException, nur um zu bemerken, dass es ein LookAndFeel Problem war, dessen Anrufe nicht auf dem EDT waren. Lektion gelernt.

+0

@ copeg - Danke für die gründliche Antwort. Nur eine Frage: Sollte nicht "die Konstruktion der UI auf dem EDT (* good practice *)" "auf dem EDT (* wie vom Sun/Java Edikt praktisch gefordert, dass Swing nicht threadsicher ist *)" lauten? – DSlomer64

+0

Gern geschehen - ich hoffe, es klärt die Dinge für Sie ... Antwort bearbeitet basierend auf Ihrer Empfehlung – copeg

+0

Clarity kommt. – DSlomer64

2
static void doIt(){ 
    while(flag)  
    tf.setText(getInfo()); 
}; 

Das beschäftigt -loop inside doIt bindet den GUI-Thread (der sich in dieser Schleife dreht), wodurch die GUI hängen bleibt.

Sie haben nicht wirklich erklärt, was Sie mit "läuft gut" meinen, aber ich nehme an, dass das das Problem ist, das Sie sehen.

Sie könnten ein Swing Timer verwenden, um etwas zu tun, was Sie in der Schleife tun.

+0

Danke. "Läuft gut" bedeutet, dass das Textfeld kontinuierlich "wie erwartet" aktualisiert wird, wobei sichtbare Änderungsergebnisse angezeigt werden, bis auf die Schaltfläche "Ende" geklickt wird. Der Code sollte unverändert laufen, wenn Sie sehen möchten, was passiert. – DSlomer64