如何在非事件派发线程中提示确认对话框

时间:2011-01-20 16:59:11

标签: java multithreading swing event-dispatch-thread

我有以下fun,它将由非事件派发线程执行。在线程中间,我想要一个

  1. 弹出确认框。线程暂停执行。
  2. 用户做出选择。
  3. 线程将获得选择并继续执行。
  4. 但是,我发现以线程安全方式进行操作并不容易,因为对话框应该由事件调度线程显示。我试试

    public int fun()
    {
        // The following code will be executed by non event dispatching thread.
        final int choice;
        SwingUtilities.invokeAndWait(new Runnable() {
    
            @Override
            public void run() {
                // Error.
                choice = JOptionPane.showConfirmDialog(SaveToCloudJDialog.this, message, title, JOptionPane.YES_NO_OPTION);
            }            
        });
        return choice;
    }
    

    当然这不会起作用,因为choice是最终的,我无法将对话框中返回的值分配给它。

    实现上述3个目标的正确方法是什么?

6 个答案:

答案 0 :(得分:5)

你试过了吗?

public int fun()
{
    // The following code will be executed by non event dispatching thread.
    final int[] choice = new int[1];
    SwingUtilities.invokeAndWait(new Runnable() {
        @Override
        public void run() {
            // Error.
            choice[0] = JOptionPane.showConfirmDialog(SaveToCloudJDialog.this, message, title, JOptionPane.YES_NO_OPTION);
        }            
    });
    return choice[0];
}

答案 1 :(得分:2)

public int fun() throws InterruptedException, InvocationTargetException {
    // The following code will be executed by non event dispatching thread.
    ChoiceRunnable runabble = new ChoiceRunnable();
    SwingUtilities.invokeAndWait(runabble);

    return runabble.choice;
  }

  class ChoiceRunnable implements Runnable {
    private int choice;

    public void run() {
      choice = JOptionPane.showConfirmDialog(SaveToCloudJDialog.this, message, title, JOptionPane.YES_NO_OPTION);
    }
  }

答案 2 :(得分:2)

与流行的看法相反,您不需要调度到AWT(EventQueue)线程来显示对话框。所以只是展示它。

当您执行JOptionPane时,showMessge()您的线程(Thread.currentThread())将执行wait(),并且会弹出对话框。在showMessage之后使用结果,你就可以了。

因此:
  choice = JOptionPane.showConfirmDialog(this, message, title, JOptionPane.YES_NO_OPTION);

答案 3 :(得分:1)

可能是我不明白这个问题,但是我也没有得到答案...如果你想让调用线程阻塞对fun()的调用,为什么要在一个新的(并行)线程中显示JOptionPane ?这不应该足够吗?

public int fun() {
    return JOptionPane.showConfirmDialog(null, message, title, JOptionPane.YES_NO_OPTION);
} 

PS如何定义非事件调度线程?

答案 4 :(得分:1)

我有些厌倦了人们说事情是这样或那样的,但实际上并不知道他们在谈论什么。我来到这里想知道应该运行哪个线程JOptionPane但是我得到了相互矛盾的答案,没有真正的证据支持任何一点。好吧,我自己研究过,我对这个答案很满意,所以我会分享。

对一个JOptionPane的showXXXDialog()的调用是BLOCKING,直到用户选择ok / cancel / etc.通常,您不会在事件调度线程(EDT)上放置这种缓慢阻塞的指令,因为每个其他GUI组件都会冻结。所以,直觉不要把它放在EDT上是好的,但这也是错误的。原因如其他一些人所述,该方法创建GUI组件,这应始终在EDT上完成。但阻止怎么样?您会注意到,即使您在EDT上运行它,它也能正常工作。原因在源代码中找到。 JOptionPane类创建一个Dialog对象,然后调用show(),然后调用dispose(),第一个是阻塞线程。如果您阅读了评论(或javadoc),您会看到它说明了这个方法:

  

如果对话框是模态的并且尚未显示,则此调用不会   返回,直到通过调用hide或dispose隐藏对话框。它是   允许从事件调度线程显示模态对话框   因为工具包将确保另一个事件泵运行时   调用此方法的一个被阻止。

因此,尽管它阻塞了,但在EDT上运行JOptionPane是完全安全的。显然,从EDT调用Dialog的show()方法是安全的,但是对于JOptionPane也是如此,因为它的方法是创建GUI组件,添加监听器,在模态时访问其他容器并阻止对它们的输入等。你不是希望所有这些都在EDT之外完成,因为它不是线程安全的,并且可能存在问题。不可否认,在EDT上使用JOptionPane时我从来没有遇到过问题,因此机会似乎很低,但它们肯定是可能的。为对话框的容器传入一个null并且只给出不可变对象(比如字符串)作为字段的参数将显着减少(甚至可能消除据我所知)发生错误的可能性,因为所有相关的GUI组件都是并且在它们不可见时在同一个线程中访问。但是,你应该安全并把它放在EDT上。调用SwingUtilities.invokeAndWait()并不困难。

答案 5 :(得分:0)

从EDT启动JOptionPane,并使用FutureTask传回值。

))))

归功于jtahlborn How to pass results from EDT back to a different thread?