JTabbedPane を使用していくつかの異なるタブを表示するアプリケーションがあります。これらのタブの 1 つには、その内容を表示するためのスレッドが実行されています。タブが表示されていないときにスレッドを停止する ComponentListener を既に実装しています。予想通り、タブが選択されるとスレッドがアクティブになり、非表示になるとスレッドが停止することがわかります。
スレッドのあるタブが選択されていないときにアプリケーションを閉じると、すべてがうまくいき、アプリケーションが閉じます。スレッドのあるタブが表示されているときにアプリケーションを閉じると、タブは ComponentEvent を受信しないため、スレッドはアクティブなままになり、アプリケーションを手動で強制終了する必要があります (Eclipse のコンソールの [Terminate] ボタンを使用)。
System.exit() メソッドを使用してアプリケーションを閉じるのではなく、すべてのスレッドを停止してすべてのウィンドウを破棄することを好みます。これは、スレッドのあるこの 1 つのタブを除いて、魅力のように機能しています。
ウィンドウまたは removeAll() を破棄する前に、JTabbedPane を非表示に設定しようとしました。どちらも期待した結果にはなりませんでした。removeAll() は反対の結果さえも持っていました。タブがアクティブでない場合、表示されたことを示す ComponentEvent を受け取ります (componentShown) (実際には、すべてのタブが順番にイベントを受け取りますが、componentHidden を受け取るものはありません)。
明らかに、ファイル メニューを介してウィンドウを閉じたとき (いくつかの制御があり、removeAll メソッドと setVisible(false) メソッドをテストした場所) と、ユーザーがクリックしたためにウィンドウが破棄されたときの両方で、スレッドを停止する必要があります。窓の隅の十字架に。
アップデート
問題を引き起こしていると思われるスレッドを、提案されているようにデーモン スレッドとして実行する方法を見つけました。しかし、これは予期せぬ問題を引き起こしました。問題のあるスレッドを開始したクラスは、私が使用している JUNG ソフトウェア パッケージの VisRunner クラスでした。スレッドが開始されるメソッド「relax」が含まれています。
@Override
public void relax() {
// in case its running
stop();
stop = false;
thread = new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
MyVisRunner クラスを作成しました。
import edu.uci.ics.jung.algorithms.layout.util.VisRunner;
import edu.uci.ics.jung.algorithms.util.IterativeContext;
public class MyVisRunner extends VisRunner {
public MyVisRunner(final IterativeContext process) {
super(process);
}
@Override
public void relax() {
// in case it's running
Log.d("Relaxing");
stop();
stop = false;
thread = new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.setDaemon(true);
thread.start();
}
}
リラクサーを次のようにロードします。
visModel = new DefaultVisualizationModel<>(layout);
visModel.setRelaxer(new MyVisRunner(layout));
これで問題が解決すると思っていましたが、問題が増えるだけです。ソフトウェアを起動すると、問題のあるタブが表示されていなくても停止しません (タブは作成されていますが、表示されていません)。その場合、MyVisRunner のリラックス メソッドは呼び出されていません。スレッドは、VisRunner クラスの他の場所では初期化されません。setRelaxer 行をコメントアウトすると、この追加の問題が解決されます (明らかに元の問題は残ります)。
更新 2
私は最終的に問題を解決しました。自分のリラクサーをセットした時、すでにリラクサーが走っていることに気が付きませんでした。コードを次のように調整しました。
visModel = new DefaultVisualizationModel<>(layout);
visModel.getRelaxer().stop();
visModel.setRelaxer(new MyVisRunner(layout));
これにより、追加の問題と元の問題の両方が解決されました。