如何在初始化期间从控制器获取阶段?

问题描述 投票:0回答:7

我想从我的控制器类中处理阶段事件(即隐藏)。所以我所要做的就是像这样添加一个监听器:

((Stage) myPane.getScene().getWindow()).setOn*whatIwant*(...);

但问题是初始化在这段代码之后开始:

Parent root = FXMLLoader.load(getClass().getResource("MyGui.fxml"));

在此代码之前:

Scene scene = new Scene(root);
stage.setScene(scene);

因此

getScene
返回 null.

我自己找到的唯一解决方法是向

myPane.sceneProperty
添加一个监听器,当它不为空时,我得到场景,添加它是
windowProperty
我的监听器处理,我最终检索到舞台。这一切都以将所需的听众设置为舞台事件而告终。

我觉得听众太多了

这是解决我问题的唯一方法吗?

javafx initialization javafx-2 javafx-8 stage
7个回答
127
投票

你可以通过

FXMLLoader
初始化后从
getController()
获取控制器的实例,但是你需要实例化一个
FXMLLoader
而不是使用静态方法。

我会在之后直接打电话给控制器

load()
后通过舞台:

FXMLLoader loader = new FXMLLoader(getClass().getResource("MyGui.fxml"));
Parent root = (Parent)loader.load();
MyController controller = (MyController)loader.getController();
controller.setStageAndSetupListeners(stage); // or what you want to do

124
投票

你只需要给

AnchorPane
一个ID,然后你就可以从中得到
Stage

@FXML private AnchorPane ap;
Stage stage = (Stage) ap.getScene().getWindow();

在这里,您可以添加您需要的

Listener

编辑:正如下面EarthMind所述,它不一定是

AnchorPane
元素;它可以是您定义的任何元素。


33
投票

我知道这不是你想要的答案,但 IMO 提出的解决方案并不好(你自己的方式是)。 为什么? 因为它们取决于应用程序状态。在 JavaFX 中,控件、场景和舞台彼此不依赖。这意味着控件可以在不添加到场景的情况下存在,场景可以在不附加到舞台的情况下存在。然后,在时刻 t1,控制可以附加到场景,在时刻 t2,该场景可以添加到舞台(这解释了为什么它们是彼此可观察的属性)。

因此建议获取控制器引用并调用方法,将阶段传递给它的方法会为您的应用程序添加一个状态。这意味着您需要在适当的时候调用该方法,就在创建阶段之后。换句话说,你现在需要遵循一个命令: 1- 创建舞台 2-通过方法将这个创建的阶段传递给控制器。

你不能(或不应该)用这种方法改变这个顺序。所以你失去了无国籍状态。在软件中,一般来说,状态是邪恶的。理想情况下,方法不需要任何调用顺序。

那么正确的解决方案是什么? 有两种选择:

1- 你的方法,在控制器监听属性中获取阶段。我认为这是正确的做法。像这样:

pane.sceneProperty().addListener((observableScene, oldScene, newScene) -> {
    if (oldScene == null && newScene != null) {
        // scene is set for the first time. Now its the time to listen stage changes.
        newScene.windowProperty().addListener((observableWindow, oldWindow, newWindow) -> {
            if (oldWindow == null && newWindow != null) {
                // stage is set. now is the right time to do whatever we need to the stage in the controller.
                ((Stage) newWindow).maximizedProperty().addListener((a, b, c) -> {
                    if (c) {
                        System.out.println("I am maximized!");
                    }
                });
            }
        });
    }
});

2-您在创建

Stage
的地方做您需要做的事情(这不是您想要的):

Stage stage = new Stage();
stage.maximizedProperty().addListener((a, b, c) -> {
            if (c) {
                System.out.println("I am maximized!");
            }
        });
stage.setScene(someScene);
...

18
投票

在控制器中获取舞台对象的最简单方法是:

  1. 在自己创建的控制器类中添加一个额外的方法(这将是一个设置方法来设置控制器类中的舞台),

    private Stage myStage;
    public void setStage(Stage stage) {
         myStage = stage;
    }
    
  2. 在启动方法中获取控制器并设置阶段

    FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml"));
    Parent parent = loader.load(); // Note the loader must be loaded before you can access the controller.
    OwnController controller = loader.getController();
    controller.setStage(this.stage);
    
  3. 现在您可以在控制器中访问舞台


2
投票

Platform.runLater 用于阻止执行直到初始化完成。在这种情况下,我想在每次调整窗口宽度时刷新列表视图。

Platform.runLater(() -> {
    ((Stage) listView.getScene().getWindow()).widthProperty().addListener((obs, oldVal, newVal) -> {
        listView.refresh();
    });
});

你的情况

Platform.runLater(()->{
    ((Stage)myPane.getScene().getWindow()).setOn*whatIwant*(...);
});

0
投票

分配 fx:id 或声明任何节点的变量:anchorpane、button 等。然后向其添加事件处理程序,并在该事件处理程序中插入下面给定的代码:

Stage stage = (Stage)((Node)((EventObject) eventVariable).getSource()).getScene().getWindow();

希望,这对你有用!!


-2
投票

可以用

node.getScene
获取,如果不从
Platform.runLater
调用,结果是空值。

空值示例:

node.getScene();

没有空值的例子:

Platform.runLater(() -> {
    node.getScene().addEventFilter(KeyEvent.KEY_PRESSED, event -> {
               //your event
     });
});
© www.soinside.com 2019 - 2024. All rights reserved.