JavaFX - Make any other stages close when the main

2019-08-12 07:26发布

问题:

Let us say I have the following code for a second window I'm creating:

    stage.initModality(Modality.NONE);
    stage.initOwner(coreController.getStage());

If I do this, it will close when my main window closes.

If I comment out stage.initOwner(coreController.getStage());, then it will be able to be hidden behind the main panel, but it will not close.

Is there any way to get it to close when I kill the main stage... without writing code to track every single new window created? So far it seems my only option is to register each new window in a list, and when the main window has a 'close event' fired, I also fire this for all the other windows. Is there a way to do it without me having to go in and wire everything together like that?

Edit: I used Modality.NONE so that no events will be blocked by the window, I don't know if this is relevant to the question however.

Edit 2: I would like to have all the windows close upon exiting the main window (it would be a bonus if I could intercept the close events and do cleanup too).

回答1:

If you just want to close all the child windows, but keep the application running for some other reason (e.g. you have sibling windows open, etc...) then I think you have to manage that yourself as you suggested in the question (keep a list of windows and call hide() on them individually, etc).

If you are actually planning to exit the application, then you can just do:

mainWindow.setOnHidden(e -> Platform.exit());

That will cause the JavaFX system to gracefully exit (which of course will cause each of the other windows to close).

If you need to clean up resources, you can override stop() in your application subclass and clean up the resources in that method. stop() will be called for you when closing the application via Platform.exit() (but note it will not be called if you do a System.exit(...)).

If you need to clean up resources on a per-window basis, then you can register onHidden() handlers with each window to do so. Note that if you subsequently show() the same window instance after it has been hidden, this means you may need to reinstate those resources. This use case is pretty untypical though.

Here's a barebones example:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class ExitOnMainWindowClose extends Application {

    @Override
    public void start(Stage primaryStage) {
        Button newWindowButton = new Button("New Window");
        newWindowButton.setOnAction(e -> showNewWindow());
        primaryStage.setScene(new Scene(new StackPane(newWindowButton), 120, 75));
        primaryStage.setOnHidden(e -> Platform.exit());
        primaryStage.show();
    }

    @Override
    public void stop() {
        System.out.println("Application-level cleanup...");
    }

    private void showNewWindow() {
        Stage stage = new Stage();
        stage.setScene(new Scene(new StackPane(new Label("New Window")), 180, 60));
        stage.setOnHidden(e -> System.out.println("Window-level cleanup..."));
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}


回答2:

If i correctly understand the question, you may call initOwner(mainStage) for every stage you need to close when the main one gets closed.

Just adding a reference to the Oracle docs, that explains why initOwner(mainStage) does not suit this case:

A stage can optionally have an owner Window. When a window is a stage's owner, it is said to be the parent of that stage. When a parent window is closed, all its descendant windows are closed. The same chained behavior applied for a parent window that is iconified. A stage will always be on top of its parent window. The owner must be initialized before the stage is made visible.

From: https://docs.oracle.com/javase/8/javafx/api/javafx/stage/Stage.html#initOwner-javafx.stage.Window-