it-swarm.com.ru

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

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

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

но проблема в том, что инициализация начинается сразу после

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

и раньше 

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

таким образом .getScene () возвращает ноль.

Единственный обходной путь, который я нашел сам, - это добавить слушателя к myPane.sceneProperty (), и когда он становится ненулевым, я получаю сцену, добавьте к нему .windowProperty () мой! Черт возьми! обработка слушателя, которую я, наконец, извлекаю на сцене. И все это заканчивается настройкой желаемых слушателей на сценические события .. Я думаю, что слишком много слушателей .. Это единственный способ решить мою проблему?

78
Chechulin

Вы можете получить экземпляр контроллера из 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
99
Sebastian

Все, что вам нужно, это дать AnchorPane идентификатор, а затем вы можете получить Stage из этого.

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

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

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

86
Robert Martin

Я знаю, что это не тот ответ, который вам нужен, но 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);
...
24
Utku Özdemir

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

  1. Добавьте дополнительный метод в свой собственный созданный класс контроллера, например (это будет метод 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. Теперь вы можете получить доступ к сцене в контроллере

9
Sandeep Kumar

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

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

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

0
Ankit RajDeo