JavaFX:舞台关闭处理程序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26619566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 02:57:11  来源:igfitidea点击:

JavaFX: Stage close handler

javajavafxhandlerjavafx-8

提问by Heine Frade

I want to save a file before closing my JavaFX application.

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

This is how I'm setting up the handler in Main::start:

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

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

And the controller calling Stage::closewhen a button is pressed:

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

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

If I close the window clicking the red X on the window border (the normal way) then I get the output message "Stage is closing", which is the desired behavior.

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

However, when calling Controller::exitApplicationthe application closes without invoking the handler (there's no output).

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

How can I make the controller use the handler I've added to primaryStage?

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

采纳答案by José Pereda

If you have a look at the life-cycleof the Applicationclass:

如果你看一下在生命周期中的Application类:

The JavaFX runtime does the following, in order, whenever an application is launched:

  1. Constructs an instance of the specified Application class
  2. Calls the init()method
  3. Calls the start(javafx.stage.Stage)method
  4. Waits for the application to finish, which happens when either of the following occur:
    • the application calls Platform.exit()
    • the last window has been closed and the implicitExitattribute on Platformis true
  5. Calls the stop()method

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

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

This means you can call Platform.exit()on your controller:

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

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

as long as you override the stop()method on the main class to save the file.

只要你覆盖stop()主类上的方法来保存文件。

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

As you can see, by using stop()you don't need to listen to close requests to save the file anymore (though you can do it if you want to prevent window closing).

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

回答by Domenico

Suppose you want to ask the user if he want to exit the application without saving the work. If the user choose no, you cannot avoid the application to close within the stop method. In this case you should add an EventFilter to your windowfor an WINDOW_CLOSE_REQUEST event.

假设您想询问用户是否要退出应用程序而不保存工作。如果用户选择否,则无法避免应用程序在 stop 方法中关闭。在这种情况下,您应该为 WINDOW_CLOSE_REQUEST 事件向窗口添加一个 EventFilter

In your start method add this code to detect the event:

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

(Note that calling Platform.exit(); doesn't fire the WindowEvent.WINDOW_CLOSE_REQUEST event, see below to know how to fire the event manually from a custom button)

(请注意,调用 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);

Then add your custom logic. In my example i use an Alert popup to ask the user if he/she want to close the application without saving.

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

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();
            }
        }
    }

The event.consume()method prevents the application from closing. Obviously you should add at least a button that permit the user to close the application to avoid the force close application by the user, that in some cases can corrupt data.

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

Lastly, if you have to fire the eventfrom a custom close button, you can use this :

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

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

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

回答by user9659191

Ahh this is a known bug in JavaFX where the Stage will not close if a modal dialog is present at the time of closing. I will link you to the bug report which I just saw today. I thinkit is fixed in the latest release.

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

Here you go:

干得好:

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

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

resolved in 8.4 it says. I think this what you are describing.

它说在 8.4 中解决了。我想这就是你所描述的。