首页 文章

JavaFX:阶段关闭处理程序

提问于
浏览
36

我想在关闭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 的处理程序?

3 回答

  • 76

    如果你看一下 Application 类的life-cycle

    每当启动应用程序时,JavaFX运行时按顺序执行以下操作:构造指定Application类的实例调用init()方法调用start(javafx.stage.Stage)方法等待应用程序完成,当出现以下任何一种情况时发生:应用程序调用Platform.exit()最后一个窗口已关闭且Platform上的implicitExit属性为true调用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() ,您不再需要侦听关闭请求来保存文件(尽管如果您想要阻止窗口关闭,您可以这样做) .

  • 0

    假设您想要询问用户是否要退出应用程序而不保存工作 . 如果用户选择“否”,则无法避免应用程序在stop方法中关闭 . 在这种情况下,您应该 add an EventFilter to your window 用于WINDOW_CLOSE_REQUEST事件 .

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

    (注意 calling Platform.exit(); doesn't fire the WindowEvent.WINDOW_CLOSE_REQUEST event ,请参阅下文,了解如何从自定义按钮手动触发事件)

    // *** 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);
    

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

    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() 方法 prevents the application from closing . 显然,您应该添加至少一个允许用户关闭应用程序的按钮,以避免用户强行关闭应用程序,在某些情况下可能会损坏数据 .

    最后,如果您必须从自定义关闭按钮 fire the event ,您可以使用:

    Window window = Main.getPrimaryStage()  // Get the primary stage from your Application class
                    .getScene()
                    .getWindow();
    
    window.fireEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));
    
  • 0

    啊,这是JavaFX中的已知错误,如果在关闭时存在模态对话框,则舞台不会关闭 . 我会将您链接到我刚才看到的错误报告 . 我认为它已在最新版本中修复 .

    干得好:

    https://bugs.openjdk.java.net/browse/JDK-8093147?jql=text%20~%20%22javafx%20re-entrant%22

    它在8.4中解决了 . 我认为这就是你所描述的 .

相关问题