Wie Sie aus dem letzten Post wissen, ist es keine gute Idee, länger andauernde Aufgaben auf dem EDT auszuführen. Um Ihre Anwendung nicht zu blockieren, lagern Sie entsprechende Codeteile stattdessen in einen eigenen Thread aus. Wie so etwas aussehen kann, demonstriert Better. Hierbei handelt es sich praktisch um einen Klon von Bad. Nur die Implementierung der Methode actionPerformed() habe ich ausgetauscht.

void actionPerformed(ActionEvent e) {
    Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            for (int i = 1; i <= 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
            }
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    button.setEnabled(true);
                }
            });
        }
    });
    button.setEnabled(false);
    t.start();
}

Zugegebenermaßen sieht das etwas komplizierter aus. Lassen Sie uns deshalb überlegen, was alles ausgeführt werden soll.

1) Deaktivieren der Schaltfläche
2) 10 Sekunden warten
3) Aktivieren der Schaltfläche

Da die Punkte 1) und 3) Swing-Komponenten manipulieren, müssen die entsprechenden Anweisungen auf dem EDT ablaufen. In Bezug auf 1) ist keine entsprechende Vorkehrung erkennbar, in Bezug auf Punkt 3) aber schon. Mit SwingUtilities.invokeLater() sorgen Sie dafür, dass Anweisungsfolgen Swing-gerecht auf dem EDT ausgeführt werden. Punkt 2) repräsentiert ja gerade die Hintergrundverarbeitung und soll deshalb auf einem eigenen Thread abgearbeitet werden. Tauschen Sie doch einmal die Methodenimplementierung aus und starten das Programm. Während in der (Eclipse-)Konsole von 1 bis 10 gezählt wird, können Sie problemlos die Größe des Fensters verändern. Auch die Schaltfläche wird korrekt (de)aktiviert. Also alles in Ordnung. …oder?

Wie Sie wissen, habe ich beim Deaktivieren der Schaltfläche nicht ausdrücklich sichergestellt, dass die Manipulation der Komponente auf dem EDT stattfindet. Offenbar klappt das aber sehr gut. Bitte packen Sie in die main()-Methode der Klasse mal folgende Anweisung: System.out.println(EventQueue.isDispatchThread());

Wenn Sie die Anwendung erneut starten, sehen Sie sehr wahrscheinlich den Wert false. Dass das Programm also gut funktioniert, ist mehr oder weniger Zufall. Auch die Initialisierung des Fensters muss auf dem EDT laufen! Deshalb gehört ein einsprechender invokeLater()-Aufruf als erste und einzige Anweisung in die main()-Methode.

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            Toolkit.getDefaultToolkit().setDynamicLayout(true);
            System.out.println(EventQueue.isDispatchThread());
            new Better().setVisible(true);
        }
    });
}

Merke: nur weil es den EDT gibt, bedeutet dies nicht, dass ein Programm darauf läuft.


This is a (slightly updated) repost of a piece I published on my blog Tommi’s Blog. I deleted the blog in the wake of the GDPR, so the original version is no longer available, or only through the WayBack Machine of the Internet Archive. Please note: code usually has not been updated, so language feature reflect the time the original post was written.