Chcę obsługiwać zdarzenia na scenie (tj. Ukrywanie) z mojej klasy kontrolera. Więc wszystko, co muszę zrobić, to dodać słuchacza przez
((Stage)myPane.getScene().getWindow()).setOn*whatIwant*(...);
ale problem polega na tym, że inicjalizacja zaczyna się zaraz potem
Parent root = FXMLLoader.load(getClass().getResource("MyGui.fxml"));
a wcześniej
Scene scene = new Scene(root);
stage.setScene(scene);
zatem .getScene () zwraca null.
Jedynym obejściem, które sam znalazłem, jest dodanie detektora do myPane.sceneProperty (), a gdy nie jest on pusty, otrzymuję scenę, dodaję do niej .windowProperty () my! Cholera! obsługa słuchacza, którą w końcu odzyskuję stage. A wszystko kończy się ustawieniem pożądanych słuchaczy na sceniczne wydarzenia. Myślę, że jest zbyt wielu słuchaczy. Czy to jedyny sposób na rozwiązanie mojego problemu?
load()
metody. (Również javadoc nagetController
brzmi tak, jak powiniensetController
.)Wszystko, czego potrzebujesz, to podać
AnchorPane
identyfikator, a następnie możesz go uzyskaćStage
.@FXML private AnchorPane ap; Stage stage = (Stage) ap.getScene().getWindow();
Stąd możesz dodać to
Listener
, czego potrzebujesz.Edycja: jak stwierdzono poniżej w EarthMind, nie musi to być
AnchorPane
element; może to być dowolny zdefiniowany przez Ciebie element.źródło
element
może być dowolny element ze związkiemfx:id
w tym oknie:Stage stage = (Stage) element.getScene().getWindow();
. Na przykład, jeśli masz tylko plikButton
fx:id
w oknach z symbolem, użyj go, aby uzyskać scenę.getScene()
wciąż wracanull
.bgimage.sceneProperty().addListener((observableScene, oldScene, newScene) -> { if (oldScene == null && newScene != null) { bgimage.fitWidthProperty().bind(newScene.widthProperty()); ... } });
Wiem, że to nie jest odpowiedź, której chcesz, ale IMO proponowane rozwiązania nie są dobre (i twój własny sposób jest). Czemu? Ponieważ zależą od stanu aplikacji. W JavaFX kontrolka, scena i scena nie zależą od siebie. Oznacza to, że element sterujący może istnieć bez dodawania go do sceny, a scena może istnieć bez dołączenia do sceny. A następnie, w chwili t1, sterowanie może zostać dołączone do sceny, aw chwili t2, scena ta może zostać dodana do sceny (i to wyjaśnia, dlaczego są one wzajemnie obserwowalnymi właściwościami).
Zatem podejście, które sugeruje pobranie odwołania do kontrolera i wywołanie metody, przekazanie do niej etapu, dodaje stan do aplikacji. Oznacza to, że musisz wywołać tę metodę w odpowiednim momencie, zaraz po utworzeniu sceny. Innymi słowy, musisz teraz wykonać zamówienie: 1 - Utwórz etap 2 - Przekaż utworzony etap do sterownika metodą.
Nie możesz (lub nie powinieneś) zmieniać tej kolejności w tym podejściu. Więc straciłeś bezpaństwowość. W oprogramowaniu generalnie stan jest zły. W idealnym przypadku metody nie powinny wymagać żadnej kolejności wywołań.
Więc jakie jest właściwe rozwiązanie? Istnieją dwie możliwości:
1- Twoje podejście, we właściwościach odsłuchu kontrolera, aby dostać się na scenę. Myślę, że to właściwe podejście. Lubię to:
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- Robisz to, co musisz zrobić, gdzie tworzysz
Stage
(a nie tego chcesz):Stage stage = new Stage(); stage.maximizedProperty().addListener((a, b, c) -> { if (c) { System.out.println("I am maximized!"); } }); stage.setScene(someScene); ...
źródło
pane
do sceny, która jest już dołączona do sceny, to nie zadziała, prawda? Czy nie powinno być sprawdzania wsceneProperty
słuchaczu i dodawaniastageProperty
słuchacza tylko wtedy, gdy scena nadal jest pusta? W przeciwnym razie po prostu zrobić to, co muszę od razu?Najprostszym sposobem na pobranie obiektu stage w kontrolerze jest:
Dodaj dodatkową metodę we własnej stworzonej klasie kontrolera, np. (Będzie to metoda ustawiająca ustawienie sceny w klasie kontrolera),
private Stage myStage; public void setStage(Stage stage) { myStage = stage; }
Pobierz kontroler w metodzie startowej i ustaw etap
FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml")); OwnController controller = loader.getController(); controller.setStage(this.stage);
Teraz możesz uzyskać dostęp do sceny w kontrolerze
źródło
stage
to w ten sposób.Przypisz fx: id lub zadeklaruj zmienną do / dowolnego węzła: kotwica, przycisk itp. Następnie dodaj do niego moduł obsługi zdarzenia i w ramach tego modułu obsługi zdarzenia wstaw poniższy kod:
Mam nadzieję, że to działa dla Ciebie !!
źródło
Platform.runLater działa, aby zapobiec wykonaniu do momentu zakończenia inicjalizacji. W takim przypadku chcę odświeżyć widok listy za każdym razem, gdy zmieniam szerokość okna.
w Twoim przypadku
źródło
Możesz uzyskać
node.getScene
, jeśli nie zadzwonisz zPlatform.runLater
, wynikiem jest wartość null.przykładowa wartość null:
przykład brak wartości null:
Platform.runLater(() -> { node.getScene().addEventFilter(KeyEvent.KEY_PRESSED, event -> { //your event }); });
źródło