[英]How to prompt a confirmation dialog box in the middle of non event dispatching thread
我有以下fun
,將由非事件派發線程執行。 在線程中間,我想要一個
但是,我發現以線程安全方式執行它並不容易,因為對話框應該由事件調度線程顯示。 我試試
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.