Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX - Center Child Stage to Parent Stage

I'm new in JavaFX and I have problem with setting position of my new window, related to parent window position. I want to open new window at the center of parent window.

I tried these two ways:

1) Init owner - i thought that init owner will open my window at the center of parent but it doesn't

FXMLLoader fxmlLoader = new     FXMLLoader(AddUserController.class.getResource("/view/addUserStage.fxml"));
Parent root = fxmlLoader.load();
Stage stage = new Stage();
stage.initOwner(parentStage);
stage.showAndWait();

2) Reposition when windows is shown - it works but after window is shown I can see its first position and then I see it is moved to new calculated position. I can't accept that.

FXMLLoader fxmlLoader = new     FXMLLoader(AddUserController.class.getResource("/view/addUserStage.fxml"));
Parent root = fxmlLoader.load();
Stage stage = new Stage();
stage.initOwner(parentStage);
stage.setOnShown(event -> controller.onWindowShown());
stage.showAndWait();

In onWindowShown function I'm setting new X and Y position of my window, because only after shown width and height of my window are known and i can easly calculate new position.

How can I can set child window position at the center of parent window before showAndWait function?

like image 315
scoozi17 Avatar asked Oct 18 '16 09:10

scoozi17


2 Answers

As the other answer correctly states, JavaFX calculates the stage width and height as the window is being shown. The onShowing() property is called before the calculation takes place, and before the window is set visible, so placing a stage.hide() command there effectively does nothing. And as the question states, seeing a blip on the screen just before the window is relocated is a less-than-desirable outcome.

The only way I have found to solve this problem (though I would love to know if a better way exists) is to add Listeners to the width and height properties of the stage, and let them fire the event to change the window's position. Then once the window is visible, remove the Listeners.

for example:

//Let's say we want to center the new window in the parent window

ChangeListener<Number> widthListener = (observable, oldValue, newValue) -> {
        double stageWidth = newValue.doubleValue();
        stage.setX(parentStage.getX() + parentStage.getWidth() / 2 - stageWidth / 2);
};
ChangeListener<Number> heightListener = (observable, oldValue, newValue) -> {
        double stageHeight = newValue.doubleValue();
        stage.setY(parentStage.getY() + parentStage.getHeight() / 2 - stageHeight / 2);   
};

stage.widthProperty().addListener(widthListener);
stage.heightProperty().addListener(heightListener);

//Once the window is visible, remove the listeners
stage.setOnShown(e -> {
    stage.widthProperty().removeListener(widthListener);
    stage.heightProperty().removeListener(heightListener);
});

stage.show();
like image 149
Daryl Avatar answered Oct 19 '22 23:10

Daryl


If you want to show a Stage you have to put the content loaded from the FXML file to a Scene and this Scene will be set on the Stage.

Unfortunately the size of the Stage is unknown until it is rendered (as you mentioned), but to relocate it to the center of the parent Stage, you have to know the size.

One trick that could work is to hide the Stage before it is shown, relocate it, and then make it visible again on the new position.

Example

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {
        try {
            BorderPane root = new BorderPane();
            Scene scene = new Scene(root, 400, 400);

            Button button = new Button("Open another Stage");
            button.setOnAction(e -> {

                Stage popUpStage = new Stage();

                // Here add the FXML content to the Scene
                Scene popUpScene = new Scene(new Button());
                popUpStage.setScene(popUpScene);

                // Calculate the center position of the parent Stage
                double centerXPosition = primaryStage.getX() + primaryStage.getWidth()/2d;
                double centerYPosition = primaryStage.getY() + primaryStage.getHeight()/2d;

                // Hide the pop-up stage before it is shown and becomes relocated
                popUpStage.setOnShowing(ev -> popUpStage.hide());

                // Relocate the pop-up Stage
                popUpStage.setOnShown(ev -> {
                    popUpStage.setX(centerXPosition - popUpStage.getWidth()/2d);
                    popUpStage.setY(centerYPosition - popUpStage.getHeight()/2d);
                    popUpStage.show();
                });

                popUpStage.showAndWait();
            });

            root.setCenter(button);


            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
like image 37
DVarga Avatar answered Oct 19 '22 22:10

DVarga