invokeAndWait を使用して Swing から値を返す
-
18-09-2019 - |
質問
私は次のアプローチを使用してコンポーネントを作成し、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];
}
ローカルの長さ 1 の配列は、内部から「結果」を転送するために使用されます。 Runnable
, 、EDT で呼び出されます。そうですね、それは「少し」ハックっぽいので、私の質問は次のとおりです。
- これには意味がありますか?他にこのようなことをしている人はいますか?
- 長さ 1 の配列は結果を転送する良い方法ですか?
- もっと簡単な方法はありますか?
解決
- 例外をログに記録することなく飲み込む: 悪い!! - 2 時間のバグ探しの後にそのようなものに遭遇したら、自分自身が嫌いになるでしょう
- いいえ、配列は良い方法ではありません。まず、呼び出し元のコードが EDT スレッドが実行するのを待つ簡単な方法が提供されていません。
Runnable
結果を取得する前に - この種のもののために明示的に設計されたクラスがあります。
SwingWorker
他のヒント
この方法は状況によっては意味があるかもしれませんが、ほとんどの場合は役に立ちません。
その理由は、コンポーネントのほとんど (すべてではないにしても) の作成が、常に EDT から実行されるユーザー アクション (メニュー項目またはボタンのクリック) の結果として EDT から行われるためです。
パネルを作成する前に大規模な作業を実行する必要があり、EDT をブロックしたくない場合は、他の人が提案したように、長いタスクのサポートを提供する SwingWorker または Swing フレームワークを使用する必要があります (通常は、とにかく内部的には SwingWorker ですが、必ずしもそうとは限りません)。
質問 2 については、残念ながら、それを行う方法はあまりありません。
- あなたがしたように1項目アレイを使用してください、それは最も簡単であり、最もgliい解決策でもあります
- 私の意見では、ほぼ同じで、もう少し作業が必要で、よりクリーンなアイテムホルダークラス(以下を参照)を作成します。
- 最後に、java.util.concurrent施設(将来および呼び出し可能)を使用します。それは私が思う最も清潔ですが、それは最も努力する必要があります
これは、ItemHolder クラスを簡略化したものです。
public class ItemHolder<T> {
public void set(T item) {...}
public T get() {...}
private T item;
}
- a) それは理にかなっています。b) 私が知っているわけではありません。
- どれも同じくらい良いです。
- JPanel を外部に作成します。
invokeAndWait
電話
//この行はマークダウンを緩和するために追加されました
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;
}
あなたは簡単に現在のスレッドがEDTであるかどうかを確認してから、その文脈で正しく、より簡単に実行することができます。戻り値を取得するため、最終的な配列を使用するためとして、それはあなたがこのように匿名の内部クラスを使用する必要が最も簡単な方法です。
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];
}
}