Wie MadProgrammer wies darauf hin, Sie SwingWorker
verwenden könnte diese Art von Verhalten zu erleichtern. Ich habe jedoch ein kleines Beispiel (nicht speziell für Ihr Programm) vorgestellt, das demonstriert, wie diese Delegierung an Hintergrundthreads und die Aktualisierung der GUI für den Ereignisversand-Thread (EDT) funktionieren kann.
Hinweis, dies ist nur eine Methode, die Sie übernehmen könnten.
Das Beispiel enthält zwei Klassen, GuiWorker
wo die ganze Thread-Behandlung auftritt, und ExampleFrame
, die GuiWorker
verwendet, um ein Beispiel zu geben.
GuiWorker
Dies ist eine abstrakte Klasse, die den Ausführungsprozess definiert, auf dem richtigen Thread die relevent Aufgaben ausgeführt wird. Es hat zwei abstrakte Methoden backgroundProcess()
und postExecute()
, die implementiert werden müssen.
backgroundProcess()
wird nicht auf dem EDT, sondern ein Hintergrund-Thread ausgeführt werden. Dies wird ausgeführt, bevor postExecute()
postExecute()
auf dem EDT ausgeführt wird und wo die GUI aktualisiert wird, nachdem die Hintergrundaufgabe beendet wurde, sollte ausgeführt werden.
import javax.swing.SwingUtilities;
public abstract class GuiWorker {
public abstract void backgroundProcess(); // method called on background thread
public abstract void postExecute(); // method called on EDT
public void execute() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Running backgroundProcess() on EDT: " + SwingUtilities.isEventDispatchThread());
// Execute backgroundProcess() on this background thread
backgroundProcess();
// When backgroundProcess() pops, run postExecute() on the EDT
System.out.println("End of background process.");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("Running postExecute() on EDT: " + SwingUtilities.isEventDispatchThread());
postExecute();
}
});
}
}).start(); // start background thread
}
}
ExampleFrame
Dies ist nur eine kleine (und unscheinbar!) GUI mit einem Label. Die Methode main(String[] args)
ist hier ebenfalls definiert, um die Anzahl der Klassen in diesem Beispiel zu reduzieren.
Der main(String args)
Methode (Eintrittspunkt) wird eine neue Instanz auf dem ExampleFrame
EDT konstruiert SwingUtilities.invokeLater(Runnable)
Einfachheit halber alles verwendet, ist in dem Konstruktor durchgeführt. Einrichten und zeigt die GUI mit einem einzigen JLabel
output
genannt, die zunächst den Text ‚Initial‘ sowie mit GuiWorker
hat einige Hintergrundaufgabe zu tun. In diesem Fall führt es 10 Wiederholungen einer while-Schleife aus und gibt i
an die Konsole aus (die sich bei jeder Iteration um 1 erhöht). Jede Wiederholung hat eine kurze Pause im Hintergrund-Thread von 500ms. Sobald dies abgeschlossen ist, die so genannte JLabel
output
zu sagen aktualisiert werden ‚ Finished‘.
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class ExampleFrame extends JFrame {
private JLabel output = new JLabel("Initial");
public static void main(String[] args) {
// Construct and show a new JFrame (ExampleFrame) on the EDT
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ExampleFrame();
}
});
}
public ExampleFrame() {
System.out.println("Running ExampleFrame() constructor on EDT: " + SwingUtilities.isEventDispatchThread());
// Setup GUI
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(output);
pack();
setVisible(true);
// Implement the abstract methods of GuiWorker and invoke execute() to run
new GuiWorker() {
@Override
public void backgroundProcess() {
// To be run on a background thread
int i = 0;
// iterate 10 times, sleeping for 500 ms
// printing i to the console
while (i < 10) {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(i);
i++;
}
}
@Override
public void postExecute() {
// when the backgroundProcess has finished
// update the output JLabel on the EDT
output.setText("Finished");
}
}.execute(); // invoke execute to start the worker
}
}
Wenn Daten während der Ausführung der Hintergrundaufgabe für das GUI-Update erforderlich ist, Sie immer Klassenmitgliederfelder einführen können, wenn GuiWorker
als eine anonyme Klasse Umsetzung oder auf andere Weise, die dann von postExecute()
zugänglich wären. Alternativ kann GuiWorker
nachbearbeitet werden, damit backgroundProcess()
einige Daten zurückgeben kann, die dann als Parameter an postExecute()
übergeben werden.
Ich bin nicht 100% sicher, was Sie erreichen möchten, oder genauer gesagt, warum Sie einen Thread zum Schlafen benötigen und den beabsichtigten Ablauf von Ereignissen. Der Aufruf von 'Thread.run()' plant jedoch nicht, dass ein neuer Thread erstellt wird, und führt dann die Task für diesen Thread aus. Stattdessen wird nur der Thread ausgeführt, von dem die 'Thread.run()' -Methode aufgerufen wurde. Deshalb schließt Ihr Programm im Wesentlichen. Sie sollten stattdessen 'Thread.start()' verwenden, während Sie immer noch die 'run() 'Methode überschreiben oder eine' Runnable'-Implementierung an den 'Thread (Runnable)' -Konstruktor übergeben (und immer noch 'Thread.start()' verwenden). –
Beachten Sie auch, dass Swing nicht threadsicher ist. Sie sollten keine Änderungen an der Benutzeroberfläche oder den Daten vornehmen, auf die sie basieren, und zwar außerhalb des EDT-Kontextes. Verwenden Sie stattdessen einen 'SwingWorker', der Funktionen zum Synchronisieren von Aktualisierungsaufrufen mit dem EDT bietet – MadProgrammer