I have problem with handling threads in my application. It creates JFrame and starts a new Thread. Last one will execute external application and update GUI. Then
I have problem to make Main class to wait for second thread to finish, but also to update GUI simultaneously.
Here’s my example (shortened):
class Main {
public int status;
public Main() {
// Creating GUI etc.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JDialog id = new JDialog();
id.button.addMouseListener(new MouseListener()); // Calls generate() method
}
});
}
public void generate() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Make changes to GUI
}
});
GeneratorThread genTest = new GeneratorThread(this, 1, 1, 1);
genTest.start();
//while (status == 0);
System.out.println("Next step.");
}
}
And Thread class:
public class GeneratorThread extends Thread {
protected Main main;
protected int setSize, minValue, maxValue;
public GeneratorThread(Main main, int setSize, int minValue, int maxValue) {
this.main = main;
this.setSize = setSize;
this.minValue = minValue;
this.maxValue = maxValue;
}
public void run() {
// Execute program etc.
// Change GUI from main in the same time
// About 3 seconds
main.status = 1;
}
}
I’m in progress and I wanted to check how it works so far. While worked nice, but it locks Swing somehow and any changes are visible only when GeneratorThread finishes. I would like to update GUI in the real time.
I’ve tried join(), effects are the same. I also tried wait() (on Main), but then I got IllegalStateMonitorException.
Any hints?
Swing is a single threaded environment. That is, there is a single thread responsible for managing all the interactions and updates to the Swing UI – the Event Dispatching Thread.
Among the golden rules of Swing are…
Thread.sleep,Thread#join,Object#wait, block IO and/or time consuming tasks (among others) should never be called from within the EDT), doing so will stop the EDT from dispatching events and paint updates (amongst other things)This raises a question…how do you “wait” for a thread?
The best way is use an Observer pattern. Basically, you provide the
Threadwith some kind of reference that it will call to provide notification of events, such as errors and completion…This will require you to think very carefully about the design of your applications, as you can not rely on a simple A to B execution of your code.
For example…
Updating the UI from within a
Threadother then the EDT is, well, messy. An easier solution would actually be to use aSwingWorker. This has publish/process methods that make easy to update the UI and progress methods that can be used to provide feedback about the progress of the current task.You can use it’s
donemethod to notify interested parties when the worker has completed.