Reputation: 36577
I've been using the following approach to create components and return values from Swing to/from outside the EDT. For instance, the following method could be an extension to JFrame
, to create a JPanel
and add it to the parent JFrame
:
public JPanel threadSafeAddPanel() {
final JPanel[] jPanel = new JPanel[1];
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
jPanel[0] = new JPanel();
add(jPanel[0]);
}
});
} catch (InterruptedException ex) {
} catch (InvocationTargetException ex) {
}
return jPanel[0];
}
The local 1-length array is used to transfer the "result" from inside the Runnable
, which is invoked in the EDT. Well, it looks "a bit" hacky, and so my questions:
Upvotes: 3
Views: 2431
Reputation: 8944
You can easily check to see if the current thread is the EDT and then execute correctly and more simply in that context. As for using the final array for getting the return value, that is the easiest way when you have to use an anonymous inner class like this.
public JPanel threadSafeAddPanel() throws InterruptedException,
InvocationTargetException {
if (EventQueue.isDispatchThread()) {
JPanel panel = new JPanel();
add(panel);
return panel;
} else {
final JPanel[] jPanel = new JPanel[1];
EventQueue.invokeAndWait(new Runnable() {
public void run() {
jPanel[0] = new JPanel();
add(jPanel[0]);
}
});
return jPanel[0];
}
}
Upvotes: 0
Reputation: 10519
Although that method may make sense in some situations, it will be useless most of the time.
The reason is that the creation of most (if not all) of your components will always occur from the EDT, as a result of a user action (menu item or button clicked) which are always executed from the EDT.
In cases where you have big work to perform before creating your panel and you don't want to block the EDT, then you should, as suggested by someone else, use SwingWorker or a Swing framework that offer support for long tasks (generally based on SwingWorker internally anyway, but not necessarily).
Regarding your question 2, unfortunately you don't have many ways to do that:
Here is, simplified, the ItemHolder class:
public class ItemHolder<T> {
public void set(T item) {...}
public T get() {...}
private T item;
}
Upvotes: 3
Reputation: 346317
Runnable
before fetching the resultSwingWorker
Upvotes: 1
Reputation: 12901
invokeAndWait
call//This line added to appease markdown
public JPanel threadSafeAddPanel() {
final JPanel jPanel = new JPanel();
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
add(jPanel);
}
});
} catch (InterruptedException ex) {
} catch (InvocationTargetException ex) {
}
return jPanel;
}
Upvotes: 0