モーダル ダイアログを時々表示するアプリケーションがありますが、外部メッセージを受信した後、状況が変化し、最初のダイアログが適用されなくなったため、そのダイアログを削除して別のダイアログに置き換えたいと考えています。
ただし、2 番目のダイアログは正しく再描画されず、親ステージも再描画されません。
この問題は、jdk-8u11-windows-x64 でコントロール fx controlsfx-8.0.6 と controls-fx-8.20.8 で確認しました。アプリケーションの外でこの問題を再現することができました
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import org.controlsfx.dialog.Dialog;
public class NestedEventLoop extends Application {
private Dialog firstDialog;
private Object stage;
@Override
public void start(Stage stage) throws Exception {
Button button = new Button("press");
button.setOnAction((e) -> {
firstDialog = new Dialog(stage, "dialog", false);
firstDialog.setContent("Content...");
openAnotherDialogLater();
firstDialog.show();
});
stage.setScene(new Scene(button));
stage.show();
this.stage = stage;
}
private void openAnotherDialogLater() {
Runnable openDialog = () -> {
firstDialog.hide();
Dialog anotherDialog = new Dialog(stage, "anotherDialog", false);
anotherDialog.show();
};
Executors.newScheduledThreadPool(1).schedule(() -> {
Platform.runLater(openDialog);
}, 2, TimeUnit.SECONDS);
}
public static void main(String[] args) {
launch(args);
}
}
何が起こっているのかについての私の分析。
- 最初のダイアログが開かれると、JavaFX スレッドは「ネストされたイベント ループ」に入ります。
- 2 番目のダイアログが必要な場合、hide() の呼び出しによって最初のネストされたイベント ループが終了しない
- 最初のイベント ループの上に新しいネストされたイベント ループが作成されます。これが再描画の問題の原因のようです。
私の質問
- 2 番目のダイアログを開く前に、最初のダイアログを閉じて最初のネストされたループから抜け出すにはどうすればよいですか? - 任意のスリープなどなし
2 番目のダイアログが開いている間の jconsole からのスタック トレース。
com.sun.glass.ui.win.WinApplication._enterNestedEventLoopImpl(Native Method)
com.sun.glass.ui.win.WinApplication._enterNestedEventLoop(WinApplication.java:142)
com.sun.glass.ui.Application.enterNestedEventLoop(Application.java:500)
com.sun.glass.ui.EventLoop.enter(EventLoop.java:107)
com.sun.javafx.tk.quantum.QuantumToolkit.enterNestedEventLoop(QuantumToolkit.java:542)
javafx.stage.Stage.showAndWait(Stage.java:455)
org.controlsfx.dialog.HeavyweightDialog$1.showAndWait(HeavyweightDialog.java:87)
org.controlsfx.dialog.HeavyweightDialog.show(HeavyweightDialog.java:284)
org.controlsfx.dialog.Dialog.show(Dialog.java:384)
NestedEventLoop.lambda$1(NestedEventLoop.java:37)
NestedEventLoop$$Lambda$7/7730735.run(Unknown Source)
com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
java.security.AccessController.doPrivileged(Native Method)
com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
com.sun.glass.ui.win.WinApplication._enterNestedEventLoopImpl(Native Method)
com.sun.glass.ui.win.WinApplication._enterNestedEventLoop(WinApplication.java:142)
com.sun.glass.ui.Application.enterNestedEventLoop(Application.java:500)
com.sun.glass.ui.EventLoop.enter(EventLoop.java:107)
com.sun.javafx.tk.quantum.QuantumToolkit.enterNestedEventLoop(QuantumToolkit.java:542)
javafx.stage.Stage.showAndWait(Stage.java:455)
org.controlsfx.dialog.HeavyweightDialog$1.showAndWait(HeavyweightDialog.java:87)
org.controlsfx.dialog.HeavyweightDialog.show(HeavyweightDialog.java:284)
org.controlsfx.dialog.Dialog.show(Dialog.java:384)
NestedEventLoop.lambda$0(NestedEventLoop.java:24)
NestedEventLoop$$Lambda$1/12269754.handle(Unknown Source)
com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
javafx.event.Event.fireEvent(Event.java:204)
javafx.scene.Node.fireEvent(Node.java:8175)
javafx.scene.control.Button.fire(Button.java:185)
com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
javafx.event.Event.fireEvent(Event.java:204)
javafx.scene.Scene$MouseHandler.process(Scene.java:3746)
javafx.scene.Scene$MouseHandler.access$1800(Scene.java:3471)
javafx.scene.Scene.impl_processMouseEvent(Scene.java:1695)
javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2486)
com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:314)
com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:243)
java.security.AccessController.doPrivileged(Native Method)
com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:345)
com.sun.glass.ui.View.handleMouseEvent(View.java:526)
com.sun.glass.ui.View.notifyMouse(View.java:898)
com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
java.lang.Thread.run(Thread.java:745)
更新: この質問を書いて以来、runLater() を使用して最初のダイアログを閉じてから、別の runLater() で新しいダイアログを開くことで回避策を発見しました。私はまだこれに関する他の人々のアイデアに興味があります.
private void openAnotherDialogLater() {
Runnable closeDialog = () -> {
firstDialog.hide();
};
Runnable openDialog = () -> {
Dialog anotherDialog = new Dialog(stage, "anotherDialog", false);
anotherDialog.show();
};
Executors.newScheduledThreadPool(1).schedule(() -> {
Platform.runLater(closeDialog);
Platform.runLater(openDialog);
}, 2, TimeUnit.SECONDS);
}