如何让我的程序等待JavaFX窗口关闭后再继续执行?

7

我有一个显示结果柱状图的程序。我希望等待用户关闭柱状图后再继续下一行代码,该行代码询问他们是否要为图表输入新信息。

Scene scene = BarGraph.getBarChart();
primaryStage.setScene(scene);
primaryStage.setTitle("Bar Chart");
primaryStage.show();

repeat = JOptionPane.showConfirmDialog(null, "Would you like to enter another number?");

正在发生的情况是柱状图场景将打开,但不会显示任何内容,立即弹出JOptionPane窗口询问。如果我选择“否”,则图表会显示,但程序会结束。如果我选择“是”,程序将循环回早期对话框窗口,但在其他对话结束之前不会显示图表。
我想等到用户关闭柱状图后再提示他们。我现在感到非常沮丧,甚至愿意加入人为的暂停,比如wait(5000)或类似的东西,但我也无法使其工作。
我已经阅读了很多资料,但尚未找到真正有效的解决方案。最接近的问题是这个:JavaFX等待直到舞台关闭 从我所读的内容中得知,我实际上无法使程序等待,但可以设置操作以在窗口关闭后发生。但是按照那里的建议只会导致舞台打开然后立即关闭。我已经走过了几个死胡同,但都没有结果。

这个有帮助吗?https://dev59.com/5WEh5IYBdhLWcg3wTB32 - Chris
1
注意:不要混用Swing和JavaFX(除非你真的必须这样做)。这段代码可能会在某些系统上挂起,因为你正在另一个线程上显示Swing窗口(JOptionPane),而不是AWT事件分派线程。改用Alert - James_D
@Chris,我已经找到了你建议的那个线程并在发布之前尝试过了。不幸的是,它没有做到我想要的。 - Crislips
2个回答

13

尝试使用Stage.showAndWait()代替Stage.show()

show()方法无论舞台的模态性如何,均会立即返回。如果需要阻塞调用者直到模态舞台隐藏(关闭),请使用showAndWait()方法。必须在舞台可见之前初始化模态性。

- JavaFX舞台文档

正如James_D所指出的那样,你需要先创建另一个舞台,在主舞台上使用此方法将导致错误。

该方法不能在主舞台或已经可见的舞台上调用。


4
您提供的文档页面链接说明,如果在主舞台上调用showAndWait()方法,则会抛出IllegalStateException异常。 - James_D
1
这实际上正是我一直在寻找的,我感到很傻,竟然找不到。我花了几个小时尝试许多不同、越来越复杂的可能解决方案,而这个改变却是如此简单。感谢您的建议!对于未来查看此内容的任何人,记录一下,我只是创建了另一个阶段而不是使用主要阶段。PrimaryStage会抛出异常。 - Crislips

4
就像所有的UI工具包一样,JavaFX是事件驱动的。这意味着你通常不编写循环执行UI任务的代码,而是编写事件处理程序来响应用户事件(包括关闭窗口)。这基本上就是你在问题中正确概括的内容:
“我从阅读中得出的结论是,我实际上不能让程序等待,但可以设置在窗口关闭后执行操作。”
你应该通过创建一个警报框(不要在JavaFX应用程序中使用Swing的JOptionPane),并为主舞台和警报框注册'onHidden'监听器来解决这个问题。主舞台的'onHidden'处理程序将显示警报框。警报框的'onHidden'处理程序将在用户选择“是”时显示主舞台(可能需要先重置一些数据)。代码示例:
Scene scene = BarGraph.getBarChart();
primaryStage.setScene(scene);
primaryStage.setTitle("Bar Chart");

Alert alert = new Alert(AlertType.CONFIRMATION);
alert.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO);
alert.setContentText("Would you like to enter another number?");

// when alert closes, if user chose "YES", reshow the primary stage:
alert.setOnHidden(e -> {
    if (alert.getResult() == ButtonType.YES) {
        primaryStage.show();
    }
});

// when the primary stage is closed, show the alert asking if the user 
// wants to show another chart:
primaryStage.setOnHidden(e -> alert.show());

primaryStage.show();

这是一个简化但完整的示例(即没有条形图):

下面是示例代码:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ReshowStageAlert extends Application {

    @Override
    public void start(Stage primaryStage) {

        VBox root = new VBox(5, new Label("Enter a number"), new TextField());
        root.setAlignment(Pos.CENTER);
        Scene scene = new Scene(root, 400, 400);
        primaryStage.setScene(scene);

        Alert alert = new Alert(AlertType.CONFIRMATION);
        alert.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO);
        alert.setContentText("Would you like to enter another number?");
        alert.setOnHidden(e -> {
            if (alert.getResult() == ButtonType.YES) {
                primaryStage.show();
            }
        });
        primaryStage.setOnHidden(e -> alert.show());

        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接