JavaFX: Stage close handler

Heine Frade picture Heine Frade · Oct 28, 2014 · Viewed 94.8k times · Source

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

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

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

And the controller calling Stage::close when a button is pressed:

@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.

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

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

Answer

José Pereda picture José Pereda · Oct 29, 2014

If you have a look at the life-cycle of the Application class:

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 implicitExit attribute on Platform is true
  5. Calls the stop() method

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

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

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

@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).