首页 文章

JavaFX - 中心子阶段到父阶段

提问于
浏览
4

我是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

    如果要显示 Stage ,则必须将从FXML文件加载的内容放入 Scene ,并且 Scene 将设置为 Scene .

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

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

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

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

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

    例如:

    //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();
    
  • 3

    您可以在显示 Stage 之前布置 Scene 并根据 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();
    }
    

相关问题