3

我一直在使用以下方法来创建组件并从 Swing 向/从 EDT 外部返回值。例如,以下方法可以是 , 的扩展JFrame,以创建 aJPanel并将其添加到 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];
}

本地 1 长度数组用于从RunnableEDT 中调用的内部传输“结果”。好吧,它看起来“有点” hacky,所以我的问题是:

  1. 这有意义吗?还有其他人在做这样的事情吗?
  2. 1-length 数组是传输结果的好方法吗?
  3. 有没有更简单的方法来做到这一点?
4

4 回答 4

3

尽管该方法在某些情况下可能有意义,但大多数时候它是无用的。

原因是大多数(如果不是全部)组件的创建将始终从 EDT 进行,这是始终从 EDT 执行的用户操作(单击菜单项或按钮)的结果。

如果您在创建面板之前有大量工作要执行并且您不想阻止 EDT,那么您应该按照其他人的建议使用 SwingWorker 或为长任务提供支持的 Swing 框架(通常基于SwingWorker 无论如何在内部,但不一定)。

关于你的问题2,不幸的是你没有很多方法可以做到这一点:

  • 像你一样使用 1-item 数组,这是最简单但也是最丑陋的解决方案
  • 在我看来,创建一个几乎相同的 ItemHolder 类(见下文),需要更多的工作并且更清洁
  • 最后,使用 java.util.concurrent 设施(Future 和 Callable);那将是我认为最干净的,但也需要最大的努力

这是简化的 ItemHolder 类:

public class ItemHolder<T> {
    public void set(T item) {...}
    public T get() {...}
    private T item;
}
于 2010-03-09T00:25:40.473 回答
1
  • 吞下异常而不记录它们:糟糕!- 当你在 2 小时的 bug-hunt 之后遇到类似的事情时,你会恨自己
  • 不,数组不是一个好方法;一方面,它没有为调用代码提供简单的方法来等待 EDT 线程Runnable在获取结果之前执行
  • 有一个专门为这种事情设计的类:SwingWorker
于 2010-03-08T13:45:08.867 回答
0
  1. a) 这是有道理的。b) 不是我所知道的。
  2. 和任何一样好。
  3. invokeAndWait在调用之外创建 JPanel

//添加此行以安抚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;
}
于 2010-03-08T13:40:40.950 回答
0

您可以轻松检查当前线程是否为 EDT,然后在该上下文中正确且更简单地执行。至于使用最终数组获取返回值,当你必须使用这样的匿名内部类时,这是最简单的方法。

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];
    }
}
于 2010-03-09T06:10:01.990 回答