My Swing GUI is being blocked when the application runs
Hi,
I've got this weird problem that whenever I press 'run' button to execute the program, the GUI gets locked up. i.e. it refuses to allow me press any other buttons (e.g. 'pause') and doesn't refresh the graph (e.g. some dynamic output that should be displayed while the underneath program is running).
I've read about people saying you should use SwingUtilities.invokeLater method, but I think I am using it given the code generated by Visual Editor in eclipse:
publicstaticvoid main(String[] args)
{
SwingUtilities.invokeLater(
new Runnable()
{
publicvoid run()
{
GameGui application =new GameGui();
application.getJFrame().setVisible(true);
}
}
);
}
Can someone please point me to the right direction to solve this problem as I'm not very familiar with threading concept in Swing? Many thanks.
Message was edited by:
cyaevan
Message was edited by:
cyaevan
Message was edited by:
cyaevan
[1465 byte] By [
cyaevana] at [2007-11-26 20:07:52]

http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html
Using invokeLater to initialise the GUI is the recomended way, but what's important to understand is the way things like the actionListener of your "Run" button work.
There's a single thread, the Dispatcher thread, that does all the GUI stuff, and that includes calling actionPerformed methods and the like. So the GUI won't do anything while your actionPerformed method is running, and therefore actionPerformed should always return within a fraction of a second (the only exception being if it uses a modal dialog). If you want your Run button to start a long-running process it needs to start another thread to do the process, then exit.
Thanks for the advice.
Do you mean something like this:
Thread t = new Thread()
{
public void run()
{
// run the underlying program here
}
};
t.start();
but I wonder how I properly terminate this thread. Thanks.
Message was edited by:
cyaevan
If you want to launch a long running action from Swing, and perhaps updateyour GUI at the end of it, check out SwingWorker, as mentioned in the tutorialentry, linked above.
Thanks DrLaszloJamf, I have had a look at that SwingWorker class, but it seems it's a new class in 1.6, but I'm currently developing with 1.5, which means I may have to migrate all my codes to comply with 1.6 to make use of it.
Not necessarily. Versions of SwingWorker have been floating around for years: https://swingworker.dev.java.net/
Huh, thanks a lot. I didn't know it existed way before 1.6 came out.
It looks like the proper implementation to solve my program, please correct me if I get this wrong:
Once a SwingWorker instance executes done() method, the Worker thread (i.e. created by this SwingWorker instance) is terminated automatically.
Many thanks.
It works almost perfectly with SwingWorker now, but one more question I've got is that, with SwingWorker, how do you do pause/resume on the current Worker thread?
> It works almost perfectly with SwingWorker now, but
> one more question I've got is that, with SwingWorker,
> how do you do pause/resume on the current Worker
> thread?
What you do is to use a boolean flag which you test in your thread's main loop, and which your GUI, or whatever, sets and clears.
You use wait and notify to cause the worker thread to wait for the flag to be cleared.
I never bothered with SwingWorker myself, but you do something like this:
// in worker thread
private boolean pause;
while(....) {
synchonized(this) {
while(pause) // if pause is set suspend processing
wait();
}
...
public synchronized setPause(boolean pause) {
this.pause = pause;
notify();
}
> What you do is to use a boolean flag which you test
> in your thread's main loop, and which your GUI, or
> whatever, sets and clears.
>
> You use wait and notify to cause the worker thread to
> wait for the flag to be cleared.
>
> I never bothered with SwingWorker myself, but you do
> something like this:
>
> > // in worker thread
> private boolean pause;
>
> while(....) {
>synchonized(this) {
> while(pause) // if pause is set suspend
> processing
>wait();
>
> ...
>
>
> public synchronized setPause(boolean pause) {
>this.pause = pause;
> notify();
>}
>
Thanks malcolmmc, but my problem is that I don't have such a loop structure in my worker thread. It just call a method on an object, and that method does everything (which may take long time to execute depending on the parameters passed in)
so if I do sth like:
while (...)
{
synchonized(this)
{
while(pause)
wait();
}
// call the method and do stuff here
}
that method will be called multiple times, so the underneath program will execute many times in one thread, which is certainly not what I intend to.
Please correct me if I get any concept wrong or I'm missing anything here. Thanks.
A long running task almost always has a main loop. It might be IO based, reading a series of lines or database records, or it might be some kind of itterative algorithm. If it's inside the method, that's where you need to put your test and wait.
If the method you're calling is in some kind of third party class where you don't have source access then it's a bit of a problem. The suspend, resume and stop methods of Thread are deprecated with good reason (see the Javadoc). These days we don't suspend a thread, we ask the thread politely to suspend itself.
> A long running task almost always has a main loop. It
> might be IO based, reading a series of lines or
> database records, or it might be some kind of
> itterative algorithm. If it's inside the method,
> that's where you need to put your test and wait.
>
> If the method you're calling is in some kind of third
> party class where you don't have source access then
> it's a bit of a problem. The suspend, resume and stop
> methods of Thread are deprecated with good reason
> (see the Javadoc). These days we don't suspend a
> thread, we ask the thread politely to suspend itself.
Thanks for the advice. I've tried out the following, but it seems it's blocking my GUI again even though I'm using SwingUtilities.invokeLater.
SwingUtilities.invokeLater(
new Runnable()
{
public void run()
{
synchronized(gameWorker)
{
try
{
gameWorker.wait(); // invoke wait() on the Worker thread
}
catch(InterruptedException e)
{
}
}
}
}
);
I wonder what causes the blocking here? Thanks.
> but it seems it's blocking my GUI again even though I'm using SwingUtilities.invokeLater.
Any code in the invokeLater executes in the GUI event Thread. So if you tell the GUI thread to wait, well it waits?
The code in the invokeLater should be simple code that updates the state of the GUI somehow.
Here is my attempt at a simple example showing the use of invokeLater with the ability to cancel the thread:
http://forum.java.sun.com/thread.jspa?forumID=57&threadID=621226
When the wait is alone in the synchronized block then you're usually using it wrong.It should be synchronize - test - wait.synchronize - set - notify.