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?
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();
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With