Je souhaite enregistrer un fichier avant de fermer mon application JavaFX.
Voici comment je configure le gestionnaire dans Main::start
:
primaryStage.setOnCloseRequest(event -> {
System.out.println("Stage is closing");
// Save file
});
Et le contrôleur appelant Stage::close
lorsqu'un bouton est enfoncé:
@FXML
public void exitApplication(ActionEvent event) {
((Stage)rootPane.getScene().getWindow()).close();
}
Si je ferme la fenêtre en cliquant sur le X rouge sur le bord de la fenêtre (normalement), le message de sortie "Stage is closing
", qui est le comportement souhaité.
Cependant, lorsque vous appelez Controller::exitApplication
l'application se ferme sans appeler le gestionnaire (il n'y a pas de sortie).
Comment faire en sorte que le contrôleur utilise le gestionnaire que j'ai ajouté à primaryStage
?
Si vous regardez le cycle de vie de la classe Application
:
Le runtime JavaFX effectue les opérations suivantes, dans l'ordre, chaque fois qu'une application est lancée:
- Construit une instance de la classe d'application spécifiée
- Appelle la méthode
init()
- Appelle la méthode
start(javafx.stage.Stage)
- Attend la fin de l'application, ce qui se produit lorsque l'une des situations suivantes se produit:
- l'application appelle
Platform.exit()
- la dernière fenêtre a été fermée et l'attribut
implicitExit
dePlatform
esttrue
- Appelle la méthode
stop()
Cela signifie que vous pouvez appeler Platform.exit()
sur votre contrôleur:
@FXML
public void exitApplication(ActionEvent event) {
Platform.exit();
}
tant que vous remplacez la méthode stop()
sur la classe principale pour enregistrer le fichier.
@Override
public void stop(){
System.out.println("Stage is closing");
// Save file
}
Comme vous pouvez le constater, en utilisant stop()
, vous n'avez plus besoin d'écouter les demandes de fermeture pour enregistrer le fichier (vous pouvez le faire si vous souhaitez empêcher la fermeture de la fenêtre).
Supposons que vous souhaitiez demander à l'utilisateur s'il souhaite quitter l'application sans enregistrer le travail. Si l'utilisateur choisit non, vous ne pouvez pas empêcher l'application de se fermer dans la méthode d'arrêt. Dans ce cas, vous devriez ajouter un EventFilter à votre fenêtre pour un événement WINDOW_CLOSE_REQUEST.
Dans votre méthode de démarrage, ajoutez ce code pour détecter l'événement:
(Notez que l'appel de Platform.exit (); ne déclenche pas l'événement WindowEvent.WINDOW_CLOSE_REQUEST , voir ci-dessous pour savoir comment. déclencher l'événement manuellement à partir d'un bouton personnalisé)
// *** 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);
Ajoutez ensuite votre logique personnalisée. Dans mon exemple, j'utilise une alerte contextuelle pour demander à l'utilisateur s'il souhaite fermer l'application sans enregistrer.
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();
}
}
}
La méthode event.consume()
empêche la fermeture de l'application. Évidemment, vous devez ajouter au moins un bouton permettant à l'utilisateur de fermer l'application pour éviter l'application forcée de fermer par l'utilisateur, ce qui peut dans certains cas altérer les données.
Enfin, si vous devez déclencher l'événement à partir d'un bouton de fermeture personnalisé, vous pouvez utiliser ceci:
Window window = Main.getPrimaryStage() // Get the primary stage from your Application class
.getScene()
.getWindow();
window.fireEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));
Ahh c'est un bogue connu dans JavaFX où la scène ne se fermera pas si un dialogue modal est présent au moment de la fermeture. Je vous relierai au rapport de bogue que je viens de voir aujourd'hui. Je pense il est corrigé dans la dernière version.
Voici:
https://bugs.openjdk.Java.net/browse/JDK-8093147?jql=text%20~%20%22javafx%20re-entrant%22
résolu en 8.4 il dit. Je pense que ce que vous décrivez.