JavaFX - 中心子阶段到父阶段

时间:2016-10-18 09:37:47

标签: java javafx javafx-8

我是JavaFX的新手,我在设置新窗口位置方面遇到问题,与父窗口位置有关。我想在父窗口的中心打开新窗口。

我试过这两种方式:

1)初始所有者 - 我认为init所有者将在父母的中心打开我的窗口,但它没有

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

2)当窗口显示时重新定位 - 它可以工作但是在显示窗口后我可以看到它的第一个位置,然后我看到它被移动到新的计算位置。我不能接受。

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

在onWindowShown函数中,我正在设置窗口的新X和Y位置,因为只有在显示窗口的宽度和高度后才能知道,我可以轻松计算新位置。

如何在showAndWait函数之前将子窗口位置设置在父窗口的中心?

3 个答案:

答案 0 :(得分:4)

正如另一个答案正确指出的那样,JavaFX会在显示窗口时计算舞台宽度和高度。 onShowing()属性在计算发生之前被调用,并且在窗口设置为可见之前,因此将stage.hide()命令放在那里实际上什么都不做。正如问题所述,在窗口重新定位之前看到屏幕上的光点是一个不太理想的结果。

我找到解决这个问题的唯一方法(虽然我很想知道是否存在更好的方法)是将监听器添加到舞台的宽度和高度属性中,然后让它们触发事件以更改窗口的位置。然后,一旦窗口可见,请删除监听器。

例如:

to_id

答案 1 :(得分:1)

如果您想要显示Stage,则必须将从FXML文件加载的内容添加到Scene,并在Scene上设置此Stage

不幸的是Stage的大小在呈现之前是未知的(正如您所提到的),但要将其重新定位到父Stage的中心,您必须知道大小。

可行的一个技巧是hide Stage显示之前,重新定位它,然后make it visible再次显示新位置。

示例

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

答案 2 :(得分:0)

您可以在显示Scene之前布置Stage,并根据Scene尺寸确定排名。然而,这不会考虑窗户装饰,所以位置可能稍微偏离,除非你有一个带有相同装饰的窗户,以考虑这些装饰的大小:

@Override
public void start(Stage primaryStage) {
    Button btnMain = new Button("show");
    btnMain.setOnAction(evt -> {
        Stage stage = new Stage();
        Button btn = new Button("Close");
        btn.setOnAction((ActionEvent event) -> {
            stage.close();
        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);

        Bounds mainBounds = primaryStage.getScene().getRoot().getLayoutBounds();
        Scene scene = new Scene(root, 400, 400);

        stage.setScene(scene);

        // layout new scene
        scene.getRoot().applyCss();
        scene.getRoot().layout();

        Bounds rootBounds = scene.getRoot().getLayoutBounds();
        stage.setX(primaryStage.getX() + (mainBounds.getWidth() - rootBounds.getWidth()) / 2);
        stage.setY(primaryStage.getY() + (mainBounds.getHeight() - rootBounds.getHeight()) / 2);
        stage.showAndWait();
        System.out.println("done");
    });
    Scene mainScene = new Scene(new StackPane(btnMain), 600, 600);
    primaryStage.setScene(mainScene);
    primaryStage.show();
}