5

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 つの目的を達成するための正しい方法は何ですか?

4

6 に答える 6

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];
}
于 2011-01-20T17:04:30.297 に答える
3

私は、彼らが何について話しているのかを実際には知らずに、物事が何らかの形であると言っている人々に少しうんざりしています. どのスレッドで JOptionPane を実行する必要があるのか​​ 疑問に思ってここに来ましたが、どちらの点もサポートする実際の証拠がなく、矛盾する答えが得られます。まあ、私はそれを自分で調査しましたが、この答えに満足しているので、共有します.

JOptionPane の showXXXDialog() の 1 つへの呼び出しは、ユーザーが OK/Cancel/etc を選択するまでブロックされます。一般に、イベント ディスパッチ スレッド (EDT) には、他のすべての GUI コンポーネントがフリーズするため、このようなスロー ブロッキング命令は原則として配置しません。したがって、EDT を使用しないという本能は良いことですが、間違っていることもあります。その理由は、他の人が述べているように、メソッドは GUI コンポーネントを作成し、これは常に EDT で行う必要があります。しかし、ブロッキングはどうですか?EDT で実行しても、正常に動作することがわかります。理由はソースコード内にあります。JOptionPane クラスは Dialog オブジェクトを作成し、次に show() を呼び出し、続いて dispose() を呼び出します。最初のものがスレッドをブロックします。コメント (または javadoc) を読むと、メソッドについて次のように書かれていることがわかります。

ダイアログがモーダルで、まだ表示されていない場合、hide または dispose を呼び出してダイアログを非表示にするまで、この呼び出しは戻りません。ツールキットは、このメソッドを呼び出したイベント ポンプがブロックされている間、別のイベント ポンプが確実に実行されるようにするため、イベント ディスパッチ スレッドからモーダル ダイアログを表示することができます。

そのため、EDT がブロックされていても、EDT で JOptionPane を実行しても完全に安全です。明らかに、Dialog の show() メソッドを EDT から呼び出すのは安全ですが、JOptionPane のメソッドは GUI コンポーネントの作成、リスナーの追加、モーダル時の他のコンテナーへのアクセス、それらへの入力のブロックなどを行っているため、同じことは当てはまりません。 EDT はスレッドセーフではなく、問題が発生する可能性があるため、これらすべてを EDT から実行する必要があります。確かに、EDT 以外で JOptionPane を使用したときに問題が発生したことはありません。ダイアログのコンテナにnullを渡し、フィールドへの引数として不変オブジェクト(文字列など)のみを与えると、関連するすべてのGUIコンポーネントが作成されるため、何か悪いことが起こる可能性が大幅に減少します(私が知る限り、排除することさえあります)それらが表示されていない間、同じスレッド内でアクセスされます。ただし、安全にEDTに入れる必要があります. SwingUtilities.invokeAndWait() を呼び出すのはそれほど難しくありません。

于 2012-07-21T04:55:44.527 に答える
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);
    }
  }
于 2011-01-20T17:06:17.537 に答える
2

ダイアログを表示するために AWT (EventQueue) スレッドにディスパッチする必要がないという一般的な信念に反します。だから見せるだけ。

JOptionPane,showMessge() を実行すると、スレッド (Thread.currentThread()) が wait() を実行し、ダイアログがポップアップします。showMessage の後に結果を使用すると、準備完了です。

したがって:
choice = JOptionPane.showConfirmDialog(this, message, title, JOptionPane.YES_NO_OPTION);

于 2011-01-20T20:51:59.680 に答える
1

私は質問を理解していないかもしれませんが、答えも得られません... fun() の呼び出しで呼び出しスレッドをブロックする場合、JOptionPane を新しい (並列) スレッドで表示するのはなぜですか? これで十分ではないでしょうか。

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

PS 非イベントディスパッチスレッドをどのように定義しますか?

于 2011-01-20T17:39:30.480 に答える