JavaFX:阶段关闭处理程序

时间:2014-10-28 22:24:15

标签: java javafx handler javafx-8

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

4 个答案:

答案 0 :(得分:80)

如果您查看Application课程的life-cycle

  

JavaFX运行时按顺序执行以下操作   应用程序启动:

     
      
  1. 构造指定Application类的实例
  2.   
  3. 调用init()方法
  4.   
  5. 调用start(javafx.stage.Stage)方法
  6.   
  7. 等待应用程序完成,当发生以下任一情况时会发生:      
        
    • 应用程序调用{​​{1}}
    •   
    • 最后一个窗口已关闭且Platform.exit()上的implicitExit属性为Platform
    •   
  8.   
  9. 调用true方法
  10.   

这意味着您可以在控制器上拨打stop()

Platform.exit()

只要覆盖主类上的@FXML public void exitApplication(ActionEvent event) { Platform.exit(); } 方法以保存文件即可。

stop()

正如您所看到的,通过使用@Override public void stop(){ System.out.println("Stage is closing"); // Save file } ,您不再需要收听关闭请求以保存文件(尽管如果您想要阻止关闭窗口,可以执行此操作)。

答案 1 :(得分:2)

假设您要询问用户是否要退出应用程序而不保存工作。如果用户选择否,则无法避免应用程序在stop方法内关闭。在这种情况下,您应该将EventFilter添加到窗口中以进行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));

答案 2 :(得分:1)

啊,这是JavaFX中的一个已知错误,如果在关闭时出现模式对话框,则舞台不会关闭。我将把您链接到我今天看到的错误报告。我认为它已在最新版本中修复。

您在这里:

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

在8.4中解决。我认为这就是您所描述的。

答案 3 :(得分:-1)

public Stage getParentStage() {
    return (Stage) getFxmlNode().getScene().getWindow();
}

btnCancel.setOnAction(e -> {
    getParentStage().close();
});