替换打开的模式对话框时出现的JavaFX问题

替换打开的模式对话框时出现的JavaFX问题,javafx,javafx-8,controlsfx,Javafx,Javafx 8,Controlsfx,我有一个应用程序,它有时会显示一个模式对话框,但是在收到一条外部消息后,我希望删除该对话框并用另一个对话框替换它,因为情况已经改变,第一个对话框不再适用 但是,第二个对话框不能正确重新绘制,父阶段也不能正确重新绘制 我在jdk-8u11-windows-x64上看到过这个问题,它带有controls-fx-8.0.6和controls-fx-8.20.8。我已设法在我的应用程序之外重新创建此问题 import java.util.concurrent.Executors; import jav

我有一个应用程序,它有时会显示一个模式对话框,但是在收到一条外部消息后,我希望删除该对话框并用另一个对话框替换它,因为情况已经改变,第一个对话框不再适用

但是,第二个对话框不能正确重新绘制,父阶段也不能正确重新绘制

我在jdk-8u11-windows-x64上看到过这个问题,它带有controls-fx-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线程进入“嵌套事件循环”
  • 当需要第二个对话框时,对hide()的调用不会导致第一个嵌套事件循环退出
  • 在第一个循环的基础上创建了一个新的嵌套事件循环-这似乎是重新绘制问题的原因
我的问题

  • 如何在打开第二个对话框之前关闭第一个对话框并退出第一个嵌套循环没有随意的睡眠等
当第二个对话框打开时,从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);
}

不管我怎么说,我建议使用JDK8U40中的新版本。您可以在第一个对话框的结果类型中表示外部消息的到达,如果消息到达,则在处理第一个对话框的结果时打开第二个对话框:

enum Result { MSG_ARRIVED, ... }

Dialog<Result> firstDialog = ...;

firstDialog.showAndWait().ifPresent(res -> {
    if(res == Result.MSG_ARRIVED) {
        anotherDialog = ...;
        anotherDialog.show();
    }
});

在原始代码中,第一个嵌套事件循环没有机会退出,因为在第一个嵌套循环上调用了
另一个对话框.show()
,直到关闭
另一个对话框为止。尽管如此,重绘问题可能是JavaFX中的一个bug,因为“阶段可能以任何顺序隐藏”。只需在
Platform.runLater()
中包装
anotherDialog.show()
,就足以让您的原始代码正常工作。谢谢,我喜欢这个想法。不幸的是,更新到8u40不是我的项目的选项。您仍然可以使用JDK8作为库。
Platform.runLater(() -> {
    firstDialog.setResult(Result.MSG_ARRIVED);
    firstDialog.hide();
});