JavaFX: Stage close handler

Chcę zapisać plik przed zamknięciem aplikacji JavaFX.

Tak ustawiam Handlera w Main::start:

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

I wywołanie kontrolera Stage::close po naciśnięciu przycisku:

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

Jeśli zamknę okno klikając czerwony znak X na ramce okna (w normalny sposób), wtedy otrzymuję komunikat wyjściowy "Stage is closing", który jest pożądanym zachowaniem.

Jednak podczas wywoływania Controller::exitApplication aplikacja zamyka się bez wywoływania obsługi (nie ma wyjście).

Jak sprawić, by kontroler korzystał z funkcji obsługi, którą dodałem do primaryStage?

Author: Heine Frade, 2014-10-29

3 answers

Jeśli spojrzeć na cykl życia klasy Application:

Środowisko uruchomieniowe JavaFX wykonuje następujące czynności, w kolejności, gdy uruchomienie aplikacji:

  1. konstruuje instancję podanej klasy aplikacji
  2. wywołuje metodę init()
  3. wywołuje metodę start(javafx.stage.Stage)
  4. czeka na zakończenie aplikacji, co dzieje się, gdy wystąpi jedna z poniższych sytuacji:
    • wywołanie aplikacji Platform.exit()
    • ostatnie okno zostało zamknięte, a atrybut implicitExit na Platform to true
  5. wywołuje metodę stop()

Oznacza to, że możesz wywołać Platform.exit() na kontrolerze:

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

Tak długo, jak nadpisujesz metodę stop() na głównej klasie, aby zapisać plik.

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

Jak widzisz, używając stop() nie musisz już nasłuchiwać żądań zamknięcia, aby zapisać plik (chociaż możesz to zrobić, jeśli chcesz zapobiec zamknięciu okna).

 72
Author: José Pereda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-23 18:57:43

Załóżmy, że chcesz zapytać użytkownika, czy chce zamknąć aplikację bez zapisywania pracy. Jeśli użytkownik wybierze opcję Nie, Nie można uniknąć zamknięcia aplikacji w metodzie stop. W tym przypadku powinieneś Dodać EventFilter do okna dla zdarzenia WINDOW_CLOSE_REQUEST.

W metodzie start dodaj ten kod, aby wykryć Zdarzenie:

(zauważ, że / align = "left" / exit (); nie uruchamia WindowEvent.WINDOW_CLOSE_REQUEST event, Zobacz poniżej 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);

Następnie dodaj własną logikę. W moim przykładzie używam wyskakującego alertu, aby zapytać użytkownika, czy chce zamknąć aplikację bez zapisywania.

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

Metoda event.consume() zapobiega zamknięciu aplikacji . Oczywiście należy dodać co najmniej przycisk, który pozwala użytkownikowi zamknąć aplikację, aby uniknąć wymusić zamknięcie aplikacji przez użytkownika, że w niektórych przypadkach może uszkodzić dane.

Wreszcie, jeśli musisz odpalić Zdarzenie z niestandardowego przycisku zamykania, możesz użyć tego:

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

window.fireEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));
 0
Author: Domenico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-08 10:42:15

Ahh jest to znany błąd w JavaFX, gdzie scena nie zostanie zamknięta, jeśli w momencie zamykania jest obecne okno modalne. Podlinkuję Cię do raportu o błędzie, który właśnie dziś widziałem. I think {[2] } it is fixed in the latest release.

Proszę bardzo:

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

Rozwiązany w 8.4 jest napisane. Myślę, że to właśnie opisujesz.

 0
Author: user9659191,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-08 14:02:12