JavaFX: Stage-Close-Handler

Lesezeit: 4 Minuten

Ich möchte eine Datei speichern, bevor ich meine JavaFX-Anwendung schließe.

So richte ich den Handler ein Main::start:

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

Und der Controller ruft Stage::close wenn eine Taste gedrückt wird:

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

Wenn ich das Fenster schließe, indem ich auf das rote X am Fensterrand klicke (normalerweise), erhalte ich die Ausgabemeldung “Stage is closing“, was das gewünschte Verhalten ist.

Allerdings beim Anruf Controller::exitApplication Die Anwendung wird geschlossen, ohne den Handler aufzurufen (es gibt keine Ausgabe).

Wie kann ich den Controller dazu bringen, den von mir hinzugefügten Handler zu verwenden? primaryStage?

Benutzer-Avatar
José Pereda

Schaut man sich die an Lebenszyklus des Application Klasse:

Die JavaFX-Laufzeitumgebung führt bei jedem Start einer Anwendung der Reihe nach Folgendes aus:

  1. Erstellt eine Instanz der angegebenen Application-Klasse
  2. Ruft die an init() Methode
  3. Ruft die an start(javafx.stage.Stage) Methode
  4. Wartet, bis die Anwendung abgeschlossen ist, was geschieht, wenn einer der folgenden Fälle eintritt:
    • die Anwendung ruft Platform.exit()
    • das letzte Fenster wurde geschlossen und die implicitExit Attribut an Platform ist true
  5. Ruft die an stop() Methode

Das bedeutet, dass Sie anrufen können Platform.exit() auf deinem Controller:

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

solange Sie die überschreiben stop() -Methode in der Hauptklasse, um die Datei zu speichern.

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

Wie Sie sehen können, verwenden Sie stop() Sie müssen nicht mehr auf Schließanforderungen warten, um die Datei zu speichern (obwohl Sie dies tun können, wenn Sie das Schließen des Fensters verhindern möchten).

Benutzer-Avatar
Domenico

Angenommen, Sie möchten den Benutzer fragen, ob er die Anwendung beenden möchte, ohne die Arbeit zu speichern. Wenn der Benutzer Nein wählt, können Sie nicht verhindern, dass die Anwendung innerhalb der Stop-Methode geschlossen wird. In diesem Fall sollten Sie Fügen Sie Ihrem Fenster einen EventFilter hinzu für ein WINDOW_CLOSE_REQUEST-Ereignis.

Fügen Sie in Ihrer Startmethode diesen Code hinzu, um das Ereignis zu erkennen:

(Beachten Sie, dass Aufruf von Platform.exit(); löst das WindowEvent.WINDOW_CLOSE_REQUEST-Ereignis nicht aussiehe unten, um zu erfahren, wie das Ereignis manuell über eine benutzerdefinierte Schaltfläche ausgelöst wird)

// *** 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);

Fügen Sie dann Ihre benutzerdefinierte Logik hinzu. In meinem Beispiel verwende ich ein Alert-Popup, um den Benutzer zu fragen, ob er/sie die Anwendung ohne Speichern schließen möchte.

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

Das event.consume() Methode verhindert, dass die Anwendung geschlossen wird. Natürlich sollten Sie mindestens eine Schaltfläche hinzufügen, die es dem Benutzer ermöglicht, die Anwendung zu schließen, um zu vermeiden, dass der Benutzer das Schließen der Anwendung erzwingt, was in einigen Fällen Daten beschädigen kann.

Endlich, wenn es sein muss das Ereignis auslösen Von einer benutzerdefinierten Schaltfläche zum Schließen können Sie Folgendes verwenden:

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

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

  • Sehr nützlich für meinen Anwendungsfall, in dem ich einen einfachen Dialog habe und die Anwendungsklasse nicht untergliedere.

    – Joe Coder

    4. März 2019 um 6:38 Uhr

Ahh, dies ist ein bekannter Fehler in JavaFX, bei dem die Bühne nicht geschlossen wird, wenn zum Zeitpunkt des Schließens ein modales Dialogfeld vorhanden ist. Ich werde Sie auf den Fehlerbericht verlinken, den ich gerade heute gesehen habe. ich denken es ist in der neuesten Version behoben.

Bitte schön:

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

gelöst in 8.4 heißt es. Ich denke das was du beschreibst.

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

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

1054910cookie-checkJavaFX: Stage-Close-Handler

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy