Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning values from Swing using invokeAndWait

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:

  1. Does this make sense? Is anybody else doing something like this?
  2. Is the 1-length array a good way of transferring the result?
  3. Is there an easier way to do this?
like image 618
Joonas Pulakka Avatar asked Jan 21 '26 18:01

Joonas Pulakka


2 Answers

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:

  • Use a 1-item array as you did, that's the easiest but also ugliest solution
  • Create a ItemHolder class (see below) that does almost the same, requires a bit more work and is cleaner, in my opinion
  • Last, use java.util.concurrent facilities (Future and Callable); that would be the cleaniest I think, but also it requires the most effort

Here is, simplified, the ItemHolder class:

public class ItemHolder<T> {
    public void set(T item) {...}
    public T get() {...}
    private T item;
}
like image 182
jfpoilpret Avatar answered Jan 23 '26 06:01

jfpoilpret


  • Swallowing exceptions without even logging them: bad!! - you will hate yourself when you come upon something like that after a 2 hours bug-hunt
  • No, the array is not a good way; for one thing, it offers no easy method for the calling code to wait for the EDT thread to execute the Runnable before fetching the result
  • There's a class designed explicitly for this kind of thing: SwingWorker
like image 20
Michael Borgwardt Avatar answered Jan 23 '26 08:01

Michael Borgwardt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!