我想从我的控制器类处理阶段事件(即隐藏)。所以我要做的就是通过
添加一个监听器((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()添加一个监听器,当它变为非null时,我得到场景,添加到它的.windowProperty()我的!该死!我最终检索阶段的监听器处理。这一切都以设置所需的听众来举办舞台活动而告终。 我认为听众太多了。 这是解决我问题的唯一方法吗?
答案 0 :(得分:104)
您可以通过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
答案 1 :(得分:87)
您只需要为AnchorPane
提供一个ID,然后就可以从中获取Stage
。
@FXML private AnchorPane ap;
Stage stage = (Stage) ap.getScene().getWindow();
从这里,您可以添加所需的Listener
。
编辑:如下面的EarthMind所述,它不一定是AnchorPane
元素;它可以是您定义的任何元素。
答案 2 :(得分:25)
我知道这不是你想要的答案,但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);
...
答案 3 :(得分:10)
在控制器中获取舞台对象的最简单方法是:
在自己创建的控制器类中添加一个额外的方法(它将是一个在控制器类中设置阶段的setter方法),
private Stage myStage;
public void setStage(Stage stage) {
myStage = stage;
}
在启动方法中获取控制器并设置阶段
FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml"));
OwnController controller = loader.getController();
controller.setStage(this.stage);
现在您可以访问控制器中的舞台
答案 4 :(得分:1)
Platform.runLater用于阻止执行直到初始化完成。在这种情况下,我想在每次调整窗口宽度大小时刷新列表视图。
Platform.runLater(() -> {
((Stage) listView.getScene().getWindow()).widthProperty().addListener((obs, oldVal, newVal) -> {
listView.refresh();
});
});
以您的情况
Platform.runLater(()->{
((Stage)myPane.getScene().getWindow()).setOn*whatIwant*(...);
});
答案 5 :(得分:0)
分配 fx:id 或向以下任意节点声明变量:锚定窗格,按钮等。然后向其中添加事件处理程序,并在该事件处理程序中插入下面的给定代码:
Stage stage = (Stage)((Node)((EventObject) eventVariable).getSource()).getScene().getWindow();
希望,这对您有用!