views:

193

answers:

2

My understanding is that if I start up another thread to perform some actions, I would need to SwingUtilities.invokeAndWait or SwingUtilities.invokeLater to update the GUI while I'm in said thread. Please correct me if I'm wrong.

What I'm trying to accomplish is relatively straightforward: when the user clicks submit, I want to (before performing any actions) disable the submit button, perform the action, and at the end of the action re-enable the button. My method to perform the action updates the GUI directly (displays results) when it gets the results back.

This action basically queries a server and gets some results back.

What I have so far is:

boolean isRunning = false;

synchronized handleButtonClick() {
  if ( isRunning == false ) {
    button.setEnabled( false );
    isRunning = true;
    doAction();
  }
}

doAction() {
  new Thread() {
    try {
      performAction(); // Concern A
    } catch ( ... ) {
      displayStackTrace( ... ); // Concern B
    } finally {
      SwingUtilities.invokeLater ( /* simple Runnable to enable button */ );
      isRunning = false;
    }
  }
}

For both of my concerns above, do I would have to use SwingUtilities.invokeAndWait since they both will update the GUI? All GUI updates revolve around updating JTextPane. Do I need to in my thread check if I'm on EDT and if so I can call my code (regardless of whether it updates the GUI or not) and NOT use SwingUtilities.invokeAndWait?

EDIT: Here is what I am doing now:

handleButtonClick() {
  if ( isRunning == true )
     return;
  disable button;
  SwingWorker task = new MyTask();
  task.execute();
}

...inside MyTask
doInBackground() {
  return performAction();
}

done() {
  result = get();
  enable button;
  isRunning = false;
  interpret result (do most of the GUI updates here);
}

While performAction() does some GUI updates, I have wrapped those in:

if ( SwingUtil.isEDT() )
  doGUIupdate()
else
  SwingUtil.invokeLater( new Runnable() {
    run() {
      doGUIupdate();
    }
  } );

Hopefully this is a step in the right direction, please comment if you believe there are better ways to handle my situation.

+4  A: 

You should consider using SwingWorker since it will not block the UI thread, whereas both SwingUtilities methods will execute on the EDT thread, thus blocking the UI.

Justin Ethier
SwingWorker executes its done() method on the EDT. It's the same as starting your own non-EDT thread which calls SwingWorker.invokeLater() to update the UI when you're done. SwingWorker is just a little more convenient to use than rolling it yourself.
Scott Stanchfield
Good point; I still recommend using `SwingWorker` though.
Justin Ethier
@Scott did you mean SwingUtilities?
nevets1219
D'oh! That should be SwingUtilities.invokeLater(). Thanks for the catch. I do agree that SwingWorker is preferred now though.
Scott Stanchfield
+13  A: 

In my opinion you should almost never use invokeAndWait(). If something is going to take awhile that will lock your UI.

Use a SwingWorker for this kind of thing. Take a look at Improve Application Performance With SwingWorker in Java SE 6.

cletus
Great link, half way through and it has revealed quite a bit to me!
nevets1219
invokeAndWait() doesn't block the UI - it blocks the helper thread until the UI has had a chance to run the passed-in Runnable.invokeAndWait() actually checks to be sure it's not being called from the EDT (which would cause the lock).Of course I should say that use of invokeAndWait() usually means the programmer isn't properly using event-driven (observer) programming...
Scott Stanchfield
Using `invokeAndWait` often leads to deadlock.
Tom Hawtin - tackline