web-dev-qa-db-ja.com

JavaFX:ステージクローズハンドラー

JavaFXアプリケーションを閉じる前にファイルを保存したい。

これは、Main::startでハンドラーを設定する方法です。

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

そして、ボタンが押されたときにStage::closeを呼び出すコントローラー:

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

ウィンドウの境界にある赤いXをクリックしてウィンドウを閉じると(通常の方法)、出力メッセージ "Stage is closing"が表示されます。これは望ましい動作です。

ただし、Controller::exitApplicationを呼び出すと、アプリケーションはハンドラーを呼び出さずに閉じます(出力はありません)。

primaryStageに追加したハンドラーをコントローラーで使用するにはどうすればよいですか?

43
Heine Frade

Applicationクラスの life-cycle を見ると:

JavaFXランタイムは、アプリケーションが起動されるたびに、次のことを順番に実行します。

  1. 指定されたApplicationクラスのインスタンスを構築します
  2. init()メソッドを呼び出します
  3. start(javafx.stage.Stage)メソッドを呼び出します
  4. 次のいずれかが発生すると、アプリケーションが終了するまで待機します。
    • アプリケーションはPlatform.exit()を呼び出します
    • 最後のウィンドウが閉じられ、implicitExitPlatform属性はtrueです
  5. stop()メソッドを呼び出します

つまり、コントローラーでPlatform.exit()を呼び出すことができます。

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

メインクラスのstop()メソッドをオーバーライドしてファイルを保存する限り。

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

ご覧のとおり、stop()を使用することにより、ファイルを保存するために閉じる要求をリッスンする必要がなくなります(ただし、ウィンドウが閉じないようにする場合はできます)。

82
José Pereda

ユーザーに作業を保存せずにアプリケーションを終了するかどうかを尋ねるとします。ユーザーが[いいえ]を選択した場合、stopメソッド内でアプリケーションが閉じることを避けることはできません。この場合、WINDOW_CLOSE_REQUESTイベントに対してEventFilterをウィンドウに追加する必要があります。

Startメソッドで次のコードを追加して、イベントを検出します。

Platform.exit()を呼び出します; WindowEvent.WINDOW_CLOSE_REQUESTイベントを発生させないことに注意してください、以下を参照して方法を確認してくださいカスタムボタンから手動でイベントを発生させるため)

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

次に、カスタムロジックを追加します。私の例では、アラートポップアップを使用して、ユーザーに保存せずにアプリケーションを閉じるかどうかを尋ねます。

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

event.consume()メソッドアプリケーションの終了を防止。明らかに、少なくともユーザーがアプリケーションを閉じることを許可するボタンを追加して、ユーザーによるアプリケーションの強制終了を回避する必要があります。場合によっては、データが破損する可能性があります。

最後に、カスタムの閉じるボタンからイベントを発生させるが必要な場合は、これを使用できます。

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

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

ああ、これはJavaFXの既知のバグであり、終了時にモーダルダイアログが存在する場合、ステージは閉じません。今日見たバグレポートにリンクします。 Ithinkこれは最新リリースで修正されています。

どうぞ:

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

8.4で解決しました。これはあなたが説明していることだと思います。

1
user9659191