I have tried a lot, but can\'t seem to get it to work.
I was told to use EDT with the following example.
SwingUtilities.invokeLater(new Runnable(
So there is an EDT (Event Dispatch Thread). All actions that appear on your screen are executed by the EDT. There is only one EDT per Swing application.
You are in some arbitrary thread and you want to update the GUI through that thread? Well like I said there is only one EDT for each swing application, so you have to tell that EDT to display the label (or whatever context you want).
The idea here, is you push this Runnable onto a queue that the EDT pulls from. Eventually, your runnable will be processed by the EDT when all other actions before it are completed.
I recommend you get the book Filthy Rich Clients. There's a chapter where they explain Swing's threading model to great detail.
Basically in Swing, any code that modifies the GUI should be executed in the Event Dispatcher Thread. The SwingUtilities
class that you are using there provides you with an easy way to post events to the event queue that is then dispatched by the EDT. That's what the invokeLater
method does, it takes a new Runnable()
as argument which is ultimately executed on the EDT.
From the book:
The invokeLater() implementation takes care of creating and queuing a special event that contains the Runnable. This event is processed on the EDT in the order it was received, just like any other event. When its time comes, it is dispatched by running the Runnable’s run() method.
If you're all looking to do is update the UI on a known schedule, try something like the following. This assumes that a JFrame
is the component you wish to update every 1 second.
private static final int WAIT_LENGTH = 1000; // 1 second
private JFrame frame = new JFrame();
// Thread will update the UI (via updateUI() call) about every 1 second
class UIUpdater extends Thread {
@Override
void run() {
while (true) {
try {
// Update variables here
}
catch (Exception e) {
System.out.println("Error: " + e);
}
finally {
frame.repaint();
Thread.sleep(WAIT_LENGTH);
}
}
}
}
To start this thread:
UIUpdater t = new UIUpdater();
t.start();
This is a pretty common element of all GUI programming. You have one thread that handles drawing the GUI, getting input, and running callbacks. If another thread tries to change the GUI related objects, it will conflict with the GUI thread. Say, for example, it was half way through drawing something and you change the color from a different thread.
All invokeLater does is queue up something for the GUI thread to run. By "later" it's really runs almost instantly but the current thread doesn't have to wait for it. The GUI thread may be doing a draw or waiting for a callback to return which would delay executing the code you gave it.
Needs to be a member so we can change it and still use it from an inner class
protected long secret=0;
... this needs to be in your code somewhere it'll get run...
JFrame f = new JFrame("foo");
new Thread(){
public void run() {
for(;;){
try {
sleep(1000);
} catch Interrupted (Exception ix){
return;
}
// TODO update your secret key here
// please don't use random()
SwingUtilities.invokeLater(new Runnable() {
public void run() {
f.setTitle("secret "+x);
}
});
}
}
}).start();
....
Only ever update Swing from the EDT so that it paints properly.
When you are in the EDT ( running code in an event handler) you can call paintImmediately() if you really must.