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

发布于 2024-10-13 01:26:12 字数 699 浏览 2 评论 0原文

我有以下 fun ,它将由非事件调度线程执行。在线程中间,我想要

  1. 弹出一个确认框。线程暂停其执行。
  2. 用户做出选择。
  3. 线程将获得选择并继续执行。

但是,我发现以线程安全的方式做到这一点并不容易,因为对话框应该由事件调度线程显示。我尝试

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;
}

当然这不会工作,因为选择是最终的,并且我无法将对话框的返回值分配给它。

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

I have the following fun which will be executed by non event dispatching thread. In the middle of thread, I want a

  1. A confirmation box pop up. Thread suspend its execution.
  2. User makes a choice.
  3. Thread will get the choice and continue execution.

However, I find out it is not easy to do it in thread safety way, as dialog box should be shown by event dispatching thread. I try

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;
}

Of course this won't work as choice is final, and I cannot assign the returned value from dialog to it.

What is the correct way to achieve the above 3 objectives?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

像你 2024-10-20 01:26:12

你有没有尝试过:

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];
}

Have you tried:

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];
}
梦魇绽荼蘼 2024-10-20 01:26:12

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

对 JOptionPane 的 showXXXDialog() 之一的调用将被阻塞,直到用户选择“确定”/“取消”等。一般来说,您通常不会将如此缓慢的阻塞指令放在事件调度线程 (EDT) 上,因为每个其他 GUI 组件都会冻结。因此,不把它放在 EDT 上的直觉是好的,但也是错误的。原因如其他一些人所述,该方法创建 GUI 组件,并且这应该始终在 EDT 上完成。但是阻塞又如何呢?您会注意到,即使您在 EDT 上运行它,它也能正常工作。原因在源码中找到。 JOptionPane 类创建一个 Dialog 对象,然后调用 show(),然后调用 dispose(),第一个函数会阻塞线程。如果您阅读注释(或 javadoc),您会看到它是关于该方法的:

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

因此,尽管 JOptionPane 会阻塞,但在 EDT 上运行 JOptionPane 是完全安全的。显然,在 EDT 之外调用 Dialog 的 show() 方法是安全的,但对于 JOptionPane 则不然,因为它的方法正在创建 GUI 组件、添加侦听器、在模态时访问其他容器以及阻止对它们的输入等。希望所有这些都在 EDT 之外完成,因为它不是线程安全的并且可能会出现问题。诚然,在 EDT 之外使用 JOptionPane 时我从未见过问题,因此可能性似乎很低,但它们肯定是有可能的。为对话框的容器传递 null 并仅将不可变对象(如字符串)作为字段的参数将显着减少(据我所知甚至可能消除)发生不良情况的可能性,因为所有相关的 GUI 组件都已制作并在同一线程中访问,而它们不可见。但是,为了安全起见,您应该将其放在 EDT 上。调用 SwingUtilities.invokeAndWait() 并不困难。

I am a bit tired of people saying things are one way or another but without actually knowing what they are talking about. I came here wondering which thread JOptionPane should be run on but I get conflicting answers with no real evidence to support either point. Well, I researched it myself and I am well satisfied with this answer so I will share.

A call to one of JOptionPane's showXXXDialog() is BLOCKING until the user selects ok/cancel/etc. In general you do not put such slow blocking insturctions on the Event Dispatch Thread (EDT) as a rule because every single other GUI component will freeze. So, a gut instinct to not put it on the EDT is good, but it is also wrong. The reason is as stated by some others, the method creates GUI components and this should always be done on the EDT. But what about the blocking? You will notice that even if you do run it on the EDT, it works fine. The reason is found inside the source code. The JOptionPane class creates a Dialog object and then calls show() followed by dispose(), the first of which is what blocks the thread. If you read the comments (or javadoc), you will see that it says this about the method:

If the dialog is modal and is not already visible, this call will not
return until the dialog is hidden by calling hide or dispose. It is
permissible to show modal dialogs from the event dispatching thread
because the toolkit will ensure that another event pump runs while the
one which invoked this method is blocked.

So, it is perfectly safe to run JOptionPane on the EDT despite it blocking. Obviously, it is safe to call Dialog's show() method off the EDT but the same is not true for JOptionPane because its methods are creating GUI components, adding listeners, accessing other containers when modal and blocking input to them, etc. You do not want all of this done off the EDT because it is not thread-safe and there could be problems. Admittedly, I have never seen problems when using JOptionPane off the EDT and so the chances seem low, but they are most certainly possible. Passing in a null for the container of the dialog and only giving immutable objects (like Strings) as arguments to the fields will significantly reduce (maybe even eliminate as far as I know) the chance of something bad happening because all relevant GUI components are made and accessed within the same thread while they are not visible. But, you should just be safe and put it on the EDT. It is not that difficult to call SwingUtilities.invokeAndWait().

成熟的代价 2024-10-20 01:26:12
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);
    }
  }
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);
    }
  }
我的鱼塘能养鲲 2024-10-20 01:26:12

与普遍的看法相反,您不需要分派到 AWT(EventQueue)线程来显示对话框。所以就展示一下吧。

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

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

Contrary on the popular belief you dont need to dispatch to AWT (EventQueue) thread to show the dialog. So just show it.

When you do JOptionPane,showMessge() your thread (Thread.currentThread()) is going to do wait(), and the dialog will pop up. Use the result after showMessage and you're good to go.

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

回梦 2024-10-20 01:26:12

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

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

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

May be I do not understand the question, but I do not get the answers either... if you want the calling thread to block on the call to fun(), why display the JOptionPane in a new (parallel) Thread? Shouldn't this be sufficient?

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

PS How do you define a non event dispatching thread?

心在旅行 2024-10-20 01:26:12

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

public int fun()
{
    FutureTask<Integer> dialogTask = new FutureTask<Integer>(new Callable<Integer>() 
    {
        @Override public Integer call() 
        {
            return JOptionPane.showConfirmDialog(SaveToCloudJDialog.this, message, title, JOptionPane.YES_NO_OPTION);
        }
    });
    SwingUtilities.invokeLater(dialogTask);
    int choice  = dialogTask.get();
}

感谢 jtahlborn
如何将 EDT 的结果传递回不同的线程线程?

Launch the JOptionPane from the EDT, and pass the value back with a FutureTask.

public int fun()
{
    FutureTask<Integer> dialogTask = new FutureTask<Integer>(new Callable<Integer>() 
    {
        @Override public Integer call() 
        {
            return JOptionPane.showConfirmDialog(SaveToCloudJDialog.this, message, title, JOptionPane.YES_NO_OPTION);
        }
    });
    SwingUtilities.invokeLater(dialogTask);
    int choice  = dialogTask.get();
}

Credit to jtahlborn
How to pass results from EDT back to a different thread?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文