JavaFX: Как получить этап от controllerа во время инициализации?

Я хочу обрабатывать события этапа (т. Е. Скрывать) из моего classа controllerа. Так что все, что мне нужно сделать, это добавить слушателя через

((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 () my! Damdamn! обработчик слушателя, который я, наконец, извлекаю. И все это заканчивается настройкой желаемых слушателей на сценические события. Я думаю, что слишком много слушателей. Это единственный способ решить мою проблему?

Вы можете получить экземпляр controllerа из FXMLLoader после инициализации с помощью getController() , но тогда вам нужно создать механизм FXMLLoader вместо использования статических методов.

Я передал бы сцену после вызова load() непосредственно на controller потом:

 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 идентификатор, а затем вы можете получить Stage из этого.

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

Отсюда вы можете добавить в Listener что вам нужно.

Изменить: Как указано EarthMind ниже, он не должен быть элементом AnchorPane ; это может быть любой элемент, который вы определили.

Я знаю, что это не тот ответ, который вам нужен, но ИМО предлагаемые решения не очень хороши (и ваш собственный путь). Зачем? Потому что они зависят от состояния приложения. В JavaFX элемент управления, сцена и сцена не зависят друг от друга. Это означает, что управление может жить без добавления в сцену, и сцена может существовать без привязки к сцене. И затем, в момент времени t1, управление может привязываться к сцене и в момент t2 эта сцена может быть добавлена ​​на сцену (и это объясняет, почему они являются наблюдаемыми свойствами друг друга).

Таким образом, подход, который предлагает получить ссылку на controller и вызвать метод, передавая ему этап, добавляет состояние в ваше приложение. Это означает, что вам нужно вызвать этот метод в нужный момент, сразу после создания сцены. Другими словами, вам необходимо выполнить заказ сейчас: 1- Создать сцену 2. Пропустить этот созданный этап на controller с помощью метода.

Вы не можете (или не должны) изменять этот порядок в этом подходе. Таким образом, вы потеряли безгражданство. И в программном обеспечении, как правило, состояние – это зло. В идеале, методы не должны требовать какого-либо вызова.

Итак, какое правильное решение? Существуют две альтернативы:

1- Ваш подход, в функции прослушивания controllerа, чтобы получить сцену. Я думаю, что это правильный подход. Как это:

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

Самый простой способ получить объект сцены в controllerе:

  1. Добавьте дополнительный метод в собственный созданный class controllerа (это будет метод setter, чтобы установить этап в classе controllerа),

     private Stage myStage; public void setStage(Stage stage) { myStage = stage; } 
  2. Получить controller в методе запуска и установить этап

     FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml")); OwnController controller = loader.getController(); controller.setStage(this.stage); 
  3. Теперь вы можете получить доступ к сцене в controllerе

Назначьте fx: id или объявите переменную в / любого узла: anchorpane, button и т. Д. Затем добавьте обработчик событий к нему и внутри этого обработчика события вставьте данный код ниже:

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

Надеюсь, что это работает для вас!!

Вы можете получить с node.getScene , если вы не вызываете из Platform.runLater , результатом является нулевое значение.

примерное значение null:

 node.getScene(); 

пример нет значения:

 Platform.runLater(() -> { node.getScene().addEventFilter(KeyEvent.KEY_PRESSED, event -> { //your event }); }); 
  • Ошибка компилятора: «Инициализатор не является константой времени компиляции»
  • Как инициализировать значения HashSet по построению?
  • Ошибка "элемент инициализации не является константой" при попытке инициализировать переменную с константой
  • Когда инициализируются статические и глобальные переменные?
  • Есть ли разница между инициализацией копирования и прямой инициализацией?
  • C ++ инициализирует статические переменные в classе?
  • Должен ли я ссылаться на self.property в методе init с ARC?
  • Значение по умолчанию BOOL
  • Почему я вижу странные значения при печати неинициализированных переменных?
  • Как инициализировать память новым оператором в C ++?
  • Статическая членная переменная C ++ и ее инициализация
  • Давайте будем гением компьютера.