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(), и когда он станет не null, я получаю сцену, добавляю к ней .windowProperty() my! черт! обработчик слушателя, который я, наконец, извлекаю. И все это заканчивается настройкой желаемых слушателей на сценические события.
Я думаю, что слишком много слушателей.
Это единственный способ решить мою проблему?
Ответы
Ответ 1
Вы можете получить экземпляр контроллера из 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
Ответ 2
Все, что вам нужно, это дать идентификатору AnchorPane
, а затем вы можете получить Stage
от этого.
@FXML private AnchorPane ap;
Stage stage = (Stage) ap.getScene().getWindow();
Здесь вы можете добавить Listener
, который вам нужен.
Изменить: Как указано EarthMind ниже, он не должен быть элементом AnchorPane
; это может быть любой элемент, который вы определили.
Ответ 3
Я знаю, что это не тот ответ, который вы хотите, но ИМО предлагаемые решения не очень хороши (и ваш собственный путь).
Зачем?
Потому что они зависят от состояния приложения. В 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);
...
Ответ 4
Самый простой способ получить объект stage в контроллере:
-
Добавьте дополнительный метод в собственный созданный класс контроллера вроде (это будет метод 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);
-
Теперь вы можете получить доступ к сцене в контроллере
Ответ 5
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