JavaFX:阶段关闭处理程序

2022-08-31 16:35:45

我想在关闭 JavaFX 应用程序之前保存一个文件。

这就是我在中设置处理程序的方式:Main::start

primaryStage.setOnCloseRequest(event -> {
    System.out.println("Stage is closing");
    // Save file
});

当按下按钮时控制器调用:Stage::close

@FXML
public void exitApplication(ActionEvent event) {
    ((Stage)rootPane.getScene().getWindow()).close();
}

如果我关闭窗口,单击窗口边框上的红色X(正常方式),那么我会收到输出消息“”,这是所需的行为。Stage is closing

但是,在调用应用程序时,关闭时不调用处理程序(没有输出)。Controller::exitApplication

如何使控制器使用我添加到的处理程序?primaryStage


答案 1

如果你看一下这个类的生命周期Application

每当启动应用程序时,JavaFX 运行时都会按顺序执行以下操作:

  1. 构造指定应用程序类的实例
  2. 调用该方法init()
  3. 调用该方法start(javafx.stage.Stage)
  4. 等待应用程序完成,当发生以下任一情况时,将发生这种情况:
    • 应用程序调用Platform.exit()
    • 最后一个窗口已关闭,并且 上的属性为implicitExitPlatformtrue
  5. 调用该方法stop()

这意味着您可以调用控制器:Platform.exit()

@FXML
public void exitApplication(ActionEvent event) {
   Platform.exit();
}

只要重写主类上的方法即可保存文件。stop()

@Override
public void stop(){
    System.out.println("Stage is closing");
    // Save file
}

如您所见,通过使用,您不再需要监听关闭请求来保存文件(尽管如果您想防止窗口关闭,则可以这样做)。stop()


答案 2

假设您要询问用户是否要在不保存工作的情况下退出应用程序。如果用户选择“否”,则无法避免应用程序在 stop 方法中关闭。在这种情况下,您应该将事件筛选器添加到WINDOW_CLOSE_REQUEST事件的窗口中

在 start 方法中添加以下代码以检测事件:

(请注意,调用 Platform.exit(); 不会触发 WindowEvent.WINDOW_CLOSE_REQUEST 事件,请参阅下文了解如何从自定义按钮手动触发事件)

// *** Only for Java >= 8 ****
// ==== This code detects when an user want to close the application either with
// ==== the default OS close button or with a custom close button ====

primaryStage.getScene().getWindow().addEventFilter(WindowEvent.WINDOW_CLOSE_REQUEST, this::closeWindowEvent);

然后添加自定义逻辑。在我的例子中,我使用警报弹出窗口询问用户是否要关闭应用程序而不保存。

private void closeWindowEvent(WindowEvent event) {
        System.out.println("Window close request ...");

        if(storageModel.dataSetChanged()) {  // if the dataset has changed, alert the user with a popup
            Alert alert = new Alert(Alert.AlertType.INFORMATION);
            alert.getButtonTypes().remove(ButtonType.OK);
            alert.getButtonTypes().add(ButtonType.CANCEL);
            alert.getButtonTypes().add(ButtonType.YES);
            alert.setTitle("Quit application");
            alert.setContentText(String.format("Close without saving?"));
            alert.initOwner(primaryStage.getOwner());
            Optional<ButtonType> res = alert.showAndWait();

            if(res.isPresent()) {
                if(res.get().equals(ButtonType.CANCEL))
                    event.consume();
            }
        }
    }

该方法可防止应用程序关闭。显然,您应该至少添加一个按钮,允许用户关闭应用程序,以避免用户强制关闭应用程序,在某些情况下可能会损坏数据。event.consume()

最后,如果必须从自定义关闭按钮触发事件,则可以使用以下命令:

Window window = Main.getPrimaryStage()  // Get the primary stage from your Application class
                .getScene()
                .getWindow();

window.fireEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));

推荐