JavaFX: Stage close handler
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 window for an WINDOW_CLOSE_REQUEST event.
In your start method add this code to detect the event:
(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)
// *** 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.
Lastly, if you have to fire the event from 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));
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 think it is fixed in the latest release.
Here you go:
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.
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:
- Constructs an instance of the specified Application class
- Calls the
init()
method- Calls the
start(javafx.stage.Stage)
method- 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 onPlatform
istrue
- 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).