3

私は次のアプローチを使用してコンポーネントを作成し、Swing から EDT の外部へ/から値を返します。たとえば、次のメソッドは を拡張してJFrame、 を作成し、JPanelそれを親に追加できJFrameます。

public JPanel threadSafeAddPanel() {

    final JPanel[] jPanel = new JPanel[1];

    try {
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                jPanel[0] = new JPanel();
                add(jPanel[0]);
            }
        });
    } catch (InterruptedException ex) {
    } catch (InvocationTargetException ex) {
    }

    return jPanel[0];
}

Runnableローカルの長さ 1 の配列は、EDT で呼び出される内から「結果」を転送するために使用されます。まあ、それは「少し」ハックに見えるので、私の質問:

  1. これは理にかなっていますか?他の誰かがこのようなことをしていますか?
  2. 長さ 1 の配列は、結果を転送する良い方法ですか?
  3. これを行う簡単な方法はありますか?
4

4 に答える 4

3

この方法は状況によっては理にかなっている場合もありますが、ほとんどの場合は役に立ちません。

その理由は、常に EDT から実行されるユーザー アクション (メニュー項目またはボタンのクリック) の結果として、ほとんど (すべてではないにしても) のコンポーネントの作成が常に EDT から行われるためです。

パネルを作成する前に実行する大きな作業があり、EDT をブロックしたくない場合は、他の誰かが提案したように、長いタスクをサポートする SwingWorker または Swing フレームワークを使用する必要があります (通常はとにかく内部的に SwingWorker ですが、必ずしもそうとは限りません)。

質問 2 に関しては、残念ながら、それを行う方法はあまりありません。

  • あなたがしたように1項目の配列を使用してください。これは最も簡単ですが、最も醜い解決策です
  • 私の意見では、ほとんど同じことを行い、もう少し作業が必要で、よりクリーンな ItemHolder クラス (以下を参照) を作成します。
  • 最後に、java.util.concurrent 機能 (Future および Callable) を使用します。それは私が思うに最もクリーンですが、最も努力が必要です

以下は、簡素化された ItemHolder クラスです。

public class ItemHolder<T> {
    public void set(T item) {...}
    public T get() {...}
    private T item;
}
于 2010-03-09T00:25:40.473 に答える
1
  • ログに記録することさえせずに例外を飲み込む:悪い!! - 2時間のバグハントの後、そのようなものに出くわしたとき、あなたは自分自身を憎むでしょう.
  • いいえ、配列は良い方法ではありません。Runnable1 つには、呼び出し元のコードが結果をフェッチする前にEDT スレッドが実行されるのを待つ簡単な方法が提供されないことです。
  • この種のもののために明示的に設計されたクラスがあります:SwingWorker
于 2010-03-08T13:45:08.867 に答える
0

現在のスレッドが EDT であるかどうかを簡単に確認し、そのコンテキストで正しく、より簡単に実行できます。戻り値を取得するための final 配列の使用に関しては、このような匿名の内部クラスを使用する必要がある場合は、これが最も簡単な方法です。

public JPanel threadSafeAddPanel() throws InterruptedException, 
        InvocationTargetException {
    if (EventQueue.isDispatchThread()) {
        JPanel panel = new JPanel();
        add(panel);

        return panel; 
    } else {
        final JPanel[] jPanel = new JPanel[1];
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                jPanel[0] = new JPanel();
                add(jPanel[0]);
            }
        });

        return jPanel[0];
    }
}
于 2010-03-09T06:10:01.990 に答える
0
  1. a) 理にかなっています。b) 私が知っていることではありません。
  2. どれも同じくらい良い。
  3. invokeAndWait呼び出しの外で JPanel を作成する

//この行は、マークダウンを緩和するために追加されました

public JPanel threadSafeAddPanel() {
    final JPanel jPanel = new JPanel();
    try {
        EventQueue.invokeAndWait(new Runnable() {
            public void run() {
                add(jPanel);
            }
        });
    } catch (InterruptedException ex) {
    } catch (InvocationTargetException ex) {
    }
    return jPanel;
}
于 2010-03-08T13:40:40.950 に答える