tags:

views:

50

answers:

3

How can I know, whether I should make a function call within GUI thread.

if (SwingUtilities.isEventDispatchThread()) {
    // ...
} else {

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            // ...
        }
    });
}

For example

// Should I call this within GUI thread?
jTable.getModel().setValueAt(...

Or

// Should I call this within GUI thread?
jComboBox.showPopup();

As I know, making operation in incorrect thread, may yield problem which is not easy to be detected. Hence, quite difficult for me to verify whether I am doing the correct stuff.

Currently, what I am doing is, If I am not sure, I will just call them in GUI thread

Not sure whether this is the best way, or there is a reliable way to figure out?

A: 

Actually

if (SwingUtilities.isEventDispatchThread()) {
  // just do it, you're already in EDT
} else {
  SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        // ...
    }
  });
}

All the code that involves Swing or AWT components/classes should be run in the EDT, ie. using SwingUtilities.invokeLater(Runnable) helper.

You can configure your app using Substance Look&Feel for testing purposes. It throws an exception if UI related code is run outside of EDT.

Boris Pavlović
Mixed up the logic. Let me fix my question.
Yan Cheng CHEOK
A: 

Almost all Swing methods needs to be executed on the UI thread. There are a few exceptions (such as some setMethods). These exceptions are documented in the API docs (usually says something like "this method is thread safe"). The general rule however, is that all GUI updates should take place on the UI thread.


In most situations you should know which thread you're currently in. It's ofter quite easy to tell. All call-backs triggered by GUI events are executed on the UI thread, and the actions in the main thread and all other threads you've started are not on the UI thread.

If you however do call code from your own threads sometimes and from the UI thread other times, you could, as you've shown in your question, determine if you're on the UI thread by calling EventQueue.isDispatchThread().

I would put the code to be executed in a separate method, updateGuiComponent(...) and do

if (EventQueue.isDispatchThread())
    updateGuiComponent(...);
else
    SwingUtilities.invokeLater(new Runnable() {          // or invokeAndWait
        public void run() { updateGuiComponent(...); }
    });
aioobe
A: 

If you really need some ultra-generic thing "invoke ASAP" functionality, a helper like this is useful:

void invokeAsSoonAsPossible(Runnable action) {
    if (SwingUtilities.isEventDispatchThread())
        action.run();
    else SwingUtilities.invokeLater(action);
}

// Usage:
invokeAsSoonAsPossible(new Runnable(){
    @Override
    public void run() {
        jTable.getModel().setValueAt(...
    }
});

But my experience tells me that it's a far better strategy to structure and document your code so that it gets easier to keep track of what is running where. If you've got a public method in a class which should be run on the EDT, JavaDoc is a good friend:

/**
 * Blah blah blah, describe the method's purpose.
 * <p>
 * <strong>Note:</strong> This method should always be 
 * invoked on the Swing event dispatch thread.
 */
public Pony calulateValue() {
    // go ahead and touch the components any way you please
}

You can also add an assertion in EDT-only methods as a kind of executable documentation:

assert SwingUtilities.isEventDispatchThread();

In short: If you have a hard time keeping track of which thread you're in, your code is probably so crufty that you have a hard time keeping track of anything, and you should worry about refactoring your code, not which thread you're on.

gustafc