JavaFX: jak uzyskać stage z kontrolera podczas inicjalizacji?

Chcę obsługiwać zdarzenia sceniczne (tj. ukrywanie) z mojej klasy kontrolerów. Więc wszystko, co muszę zrobić, to dodać słuchacza przez

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

Ale problem polega na tym, że inicjalizacja rozpoczyna się zaraz po

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

I przed

Scene scene = new Scene(root);
stage.setScene(scene);
Tak więc .getScene () zwraca null.

Jedynym obejściem, jakie znalazłem, jest dodanie słuchacza do myPane.sceneProperty (), a gdy staje się nie null dostaję scene, dodaję do niego .windowProperty () my !cholera! obsługa słuchacza który w końcu odzyskałem. A wszystko to kończy się na ustawieniu pożądanych słuchaczy do wydarzeń scenicznych. Myślę, że jest zbyt wielu słuchaczy. Czy to jedyny sposób na rozwiązanie mojego problemu?

Author: Robert Martin, 2012-11-06

7 answers

Możesz pobrać instancję kontrolera z FXMLLoader po inicjalizacji przez getController(), ale musisz utworzyć instancję FXMLLoader zamiast używać metod statycznych.

Przeszedłbym etap po wywołaniu load() bezpośrednio do kontrolera później:

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
 121
Author: zhujik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-11 16:09:31

Wystarczy, że podasz AnchorPane Identyfikator, a potem dostaniesz Stage z tego.

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

Stąd możesz dodać Listener, które potrzebujesz.

Edit: zgodnie z poniższym opisem EarthMind, nie musi to być element AnchorPane; może to być dowolny element, który zdefiniowałeś.

 114
Author: Robert Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-18 21:01:39

Wiem, że to nie jest odpowiedź, ale IMO proponowane rozwiązania nie są dobre(a twój własny sposób jest). Dlaczego? Ponieważ zależą one od stanu aplikacji. W JavaFX sterowanie, scena i scena nie zależą od siebie nawzajem. Oznacza to, że kontrola może żyć bez dodawania do sceny, a scena może istnieć bez dołączania do sceny. Następnie, w momencie instant T1, kontrola może zostać dołączona do sceny, a w momencie instant t2, scena może zostać dodana do sceny (i to wyjaśnia, dlaczego są obserwowalnymi własnościami siebie nawzajem).

Więc podejście, które sugeruje uzyskanie referencji kontrolera i wywołanie metody, przejście do niej etapu dodaje stan do aplikacji. Oznacza to, że musisz wywołać tę metodę w odpowiednim momencie, tuż po utworzeniu etapu. Innymi słowy, musisz wykonać zamówienie teraz: 1-Utwórz scenę 2-przekazać ten utworzony etap do kontrolera za pomocą metody.

Nie możesz (lub nie powinieneś) zmienić tej kolejności w tym podejdźcie. Więc straciłeś bezpaństwowość. A w oprogramowaniu, ogólnie, państwo jest złem. Idealnie, metody nie powinny wymagać żadnego zamówienia wywołania.

Więc jakie jest właściwe rozwiązanie? Istnieją dwie alternatywy:

1 - twoje podejście, we właściwościach nasłuchu kontrolera, aby uzyskać scenę. Myślę, że to właściwe podejście. Tak:

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);
...
 32
Author: Utku Özdemir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-01 17:58:35

Najprostszym sposobem uzyskania obiektu stage w kontrolerze jest:

  1. Dodaj dodatkową metodę w stworzonej przez siebie klasie kontrolera like (będzie to metoda setter do ustawiania stage w klasie kontrolera),

    private Stage myStage;
    public void setStage(Stage stage) {
         myStage = stage;
    }
    
  2. Get controller in start method and set stage

    FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml"));
    OwnController controller = loader.getController();
    controller.setStage(this.stage);
    
  3. Teraz możesz uzyskać dostęp do sceny w controller

 14
Author: Sandeep Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-15 04:17:31

Przypisz FX:id lub zadeklaruj zmienną do/dowolnego węzła: anchorpane, button, itd. Następnie dodaj do niego funkcję obsługi zdarzeń i wprowadź podany poniżej kod:

Stage stage = (Stage)((Node)((EventObject) eventVariable).getSource()).getScene().getWindow();
Hope, to działa dla Ciebie!!
 1
Author: Ankit RajDeo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-11 10:13:57

Platforma.runLater działa, aby zapobiec wykonaniu do momentu zakończenia inicjalizacji. W tym przypadku chcę odświeżyć widok listy za każdym razem, gdy zmieniam rozmiar okna.

Platform.runLater(() -> {
    ((Stage) listView.getScene().getWindow()).widthProperty().addListener((obs, oldVal, newVal) -> {
        listView.refresh();
    });
});

W Twoim przypadku

Platform.runLater(()->{
    ((Stage)myPane.getScene().getWindow()).setOn*whatIwant*(...);
});
 1
Author: AdamOutler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-01-23 14:31:58

Można uzyskać za pomocą node.getScene, jeśli nie wywoła się z Platform.runLater, wynikiem jest wartość null.

Przykładowa wartość null:

node.getScene();

Przykład brak wartości null:

Platform.runLater(() -> {
    node.getScene().addEventFilter(KeyEvent.KEY_PRESSED, event -> {
               //your event
     });
});
 -2
Author: fjqa86,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-02 06:13:52