Frage

Ich habe die folgende Vorgehensweise wurde unter Verwendung von Komponenten zu erstellen und Rückgabewerte von Swing / von außerhalb des EDT. Zum Beispiel könnte das folgende Verfahren eine Erweiterung JFrame, sein ein JPanel zu erstellen und an der Mutter JFrame hinzufügen:

public JPanel threadSafeAddPanel() {

    final JPanel[] jPanel = new JPanel[1];

    try {
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                jPanel[0] = new JPanel();
                add(jPanel[0]);
            }
        });
    } catch (InterruptedException ex) {
    } catch (InvocationTargetException ex) {
    }

    return jPanel[0];
}

Das lokale 1-length-Array wird verwendet, um das „Ergebnis“ aus dem Innern des Runnable zu übertragen, die in der EDT aufgerufen wird. Nun, es sieht "ein bisschen" Hacky, und so meine Fragen:

  1. Ist das sinnvoll? Ist jemand anderes so etwas wie dies zu tun?
  2. Ist die 1-Array mit der Länge ein guter Weg, um das Ergebnis der Übertragung?
  3. Gibt es einen einfacheren Weg, dies zu tun?
War es hilfreich?

Lösung

  • Ausnahmen Swallowing, ohne sie sogar Anmeldung: schlecht !! - Sie werden sich hassen, wenn Sie kommen auf etwas wie das nach einer 2 Stunden Bug-Jagd
  • Nein, das Array ist kein guter Weg; für eine Sache, bietet es keine einfache Methode für den anrufenden Code für den EDT Thread zu warten, um die Runnable vor dem Abruf des Ergebnisses
  • auszuführen
  • Es gibt eine Klasse explizit für diese Art der Sache entworfen:

Andere Tipps

Obwohl diese Methode Sinn in einigen Situationen machen kann, wird es die meiste Zeit nutzlos sein.

Der Grund dafür ist, dass die Schaffung der meisten (wenn nicht alle) Ihre Komponenten werden immer aus dem EDT auftreten, als Ergebnis einer Benutzeraktion (Menüpunkt oder Button geklickt), die immer aus dem EDT ausgeführt.

In Fällen, in denen Sie große Arbeit zu verrichten haben, bevor Ihr Panel zu schaffen und Sie wollen nicht den EDT blockieren, dann sollten Sie, wie von jemand anderem vorgeschlagen, verwenden Swingworker oder einen Swing-Framework, das für lange Aufgaben Unterstützung bieten ( basieren in der Regel auf Swingworker intern sowieso, aber nicht unbedingt).

In Bezug auf Ihre Frage 2, leider haben Sie nicht viele Möglichkeiten, dies zu tun:

  • Verwenden Sie eine 1-Punkt-Array wie du, das ist die einfachste, aber auch hässlichste Lösung
  • Erstellen Sie eine ItemHolder Klasse (siehe unten), die fast das gleiche tut, erfordert eine Arbeit Bit und ist Reiniger, meiner Meinung nach
  • Letzte, Verwendung java.util.concurrent Einrichtungen (Zukunft und Callable); das wäre die saubersten Ich denke, aber auch sie erfordert den meisten Aufwand

Hier heißt vereinfacht, die ItemHolder Klasse:

public class ItemHolder<T> {
    public void set(T item) {...}
    public T get() {...}
    private T item;
}
  1. a) Es macht Sinn. b) nicht, dass ich wüsste.
  2. So gut wie jeder andere.
  3. Erstellen Sie die JPanel außerhalb des invokeAndWait Anruf

// Diese Zeile hinzugefügt Abschlag zu beschwichtigen

public JPanel threadSafeAddPanel() {
    final JPanel jPanel = new JPanel();
    try {
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                add(jPanel);
            }
        });
    } catch (InterruptedException ex) {
    } catch (InvocationTargetException ex) {
    }
    return jPanel;
}

Sie können leicht überprüfen, um zu sehen, ob der aktuelle Thread die EDT ist und führen Sie dann richtig und einfacher in diesem Zusammenhang. Da für die endgültige Anordnung für das Erhalten des Rückgabewertes verwenden, das ist der einfachste Weg, wenn Sie eine anonyme innere Klasse wie folgt verwenden.

public JPanel threadSafeAddPanel() throws InterruptedException, 
        InvocationTargetException {
    if (EventQueue.isDispatchThread()) {
        JPanel panel = new JPanel();
        add(panel);

        return panel; 
    } else {
        final JPanel[] jPanel = new JPanel[1];
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                jPanel[0] = new JPanel();
                add(jPanel[0]);
            }
        });

        return jPanel[0];
    }
}
scroll top