簡體   English   中英

如何在非事件派發線程中提示確認對話框

[英]How to prompt a confirmation dialog box in the middle of non event dispatching thread

我有以下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;
}

當然這不會起作用,因為choice是最終的,我無法將對話框的返回值分配給它。

實現上述3個目標的正確方法是什么?

你有沒有嘗試過:

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

與流行的看法相反,您不需要調度到AWT(EventQueue)線程來顯示對話框。 所以只是展示它。

當您執行JOptionPane時,showMessge()您的線程(Thread.currentThread())將執行wait(),並彈出對話框。 在showMessage之后使用結果,你很高興。

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

我有些厭倦了人們說事情是這樣或那樣的,但實際上並不知道他們在談論什么。 我來到這里想知道應該運行哪個線程JOptionPane但是我得到了相互矛盾的答案,沒有真正的證據支持任何一點。 好吧,我自己研究過,我很滿意這個答案所以我會分享。

對一個JOptionPane的showXXXDialog()的調用是阻塞,直到用戶選擇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()並不困難。

可能是我不明白這個問題,但是我也沒有得到答案......如果你想讓調用線程阻塞對fun()的調用,為什么要在一個新的(並行)線程中顯示JOptionPane? 這不應該足夠嗎?

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

PS如何定義非事件調度線程?

從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的結果傳遞回另一個線程?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM