JavaFX:如何从初始化阶段从控制器阶段?

我想从我的控制器类处理舞台事件(即隐藏)。 所以我所要做的就是添加一个监听器

((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()我!该死的! 监听器处理,我终于检索阶段。 而这一切都以设置所需的听众到舞台事件结束。 我觉得听众太多了。 这是解决我的问题的唯一方法吗?

你可以在初始化后通过getController()从FXMLLoader获得控制器实例,但是你需要实例化一个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 

所有你需要的是给AnchorPane一个ID,然后你可以从那里得到Stage

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

从这里,你可以添加你需要的Listener

编辑:正如下面的EarthMind所述,它不一定是AnchorPane元素; 它可以是你定义的任何元素。

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

所以build议让控制器参考并调用方法的方法,将舞台传递给它,可以为您的应用程序添加一个状态。 这意味着您需要在创build舞台后的恰当时刻调用该方法。 换句话说,您现在需要遵循一个订单:1-创build阶段2-通过一个方法将创build的阶段传递给控制器​​。

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

那么什么是正确的解决scheme? 有两种select:

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

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

  1. 在自己创build的控制器类中添加一个额外的方法(它将是一个setter方法来设置控制器类中的阶段),

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

     FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml")); OwnController controller = loader.getController(); controller.setStage(this.stage); 
  3. 现在你可以访问控制器的阶段

 Puedes llamarlo de de la siguiente tomando un nodo del fxml. you can get with node. getScene, if you dont call from Platform.runLater, the result is a null value. example null value: node.getScene(); example no null value: Platform.runLater(() -> { node.getScene().addEventFilter(KeyEvent.KEY_PRESSED, event -> { //your event }); }); Enjoy