web-dev-qa-db-fra.com

JavaFX: Comment obtenir l'étape du contrôleur lors de l'initialisation?

Je veux gérer les événements de la scène (c'est-à-dire se cacher) de ma classe de contrôleur. Donc, tout ce que je dois faire est d'ajouter un auditeur via

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

mais le problème est que l'initialisation commence juste après

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

et avant 

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

ainsi .getScene () renvoie null.

La seule solution que j'ai trouvée par moi-même est d'ajouter un auditeur à myPane.sceneProperty (), et lorsque la valeur devient non nulle, la scène s'ajoute. Ajoutez à cela .windowProperty () my! Putain! la gestion de l'auditeur que je récupère enfin l'étape. Et tout se termine par le réglage des auditeurs désirés pour qu'ils mettent en scène des événements… Je pense qu'il y a trop d'auditeurs… est-ce le seul moyen de résoudre mon problème?

78
Chechulin

Vous pouvez obtenir l'instance du contrôleur depuis FXMLLoader après l'initialisation via getController(), mais vous devez instancier une FXMLLoader au lieu d'utiliser les méthodes statiques alors. 

Je passerais l'étape après avoir appelé load() directement au contrôleur ensuite:

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

Tout ce dont vous avez besoin est de donner un identifiant à la AnchorPane et vous pourrez ensuite obtenir la Stage à partir de cela.

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

À partir de là, vous pouvez ajouter la Listener dont vous avez besoin.

Edit: Comme indiqué par EarthMind ci-dessous, il n'est pas nécessaire que ce soit l'élément AnchorPane; ce peut être n'importe quel élément que vous avez défini.

86
Robert Martin

Je sais que ce n’est pas la réponse que vous souhaitez, mais les solutions proposées par l’OMI ne sont pas bonnes (et votre propre manière de le faire)… .. Pourquoi? Parce qu'elles dépendent de l'état de l'application. En JavaFX, un contrôle, une scène et une étape ne dépendent pas l'un de l'autre. Cela signifie qu'un contrôle peut vivre sans être ajouté à une scène et qu'une scène peut exister sans être attachée à une scène. Et puis, à un instant t1, le contrôle peut être attaché à une scène et à l'instant t2, cette scène peut être ajoutée à une scène (et cela explique pourquoi elles sont des propriétés observables les unes des autres).

Ainsi, l’approche qui suggère d’obtenir la référence du contrôleur et d’appeler une méthode et de lui transmettre l’étape ajoute un état à votre application. Cela signifie que vous devez invoquer cette méthode au bon moment, juste après la création de la scène. En d'autres termes, vous devez suivre un ordre maintenant: 1- Créez l'étape 2- Passez cette étape créée au contrôleur via une méthode.

Vous ne pouvez pas (ou ne devriez pas) changer cet ordre dans cette approche. Donc, vous avez perdu l'apatridie. Et dans les logiciels, généralement, l'état est mauvais. Idéalement, les méthodes ne devraient pas nécessiter d'ordre d'appel.

Alors, quelle est la bonne solution? Il y a deux alternatives:

1- Votre approche, dans les propriétés d’écoute du contrôleur pour obtenir le stade. Je pense que c'est la bonne approche. Comme ça:

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- Vous faites ce que vous devez faire là où vous créez la Stage (et ce n'est pas ce que vous voulez):

Stage stage = new Stage();
stage.maximizedProperty().addListener((a, b, c) -> {
            if (c) {
                System.out.println("I am maximized!");
            }
        });
stage.setScene(someScene);
...
24
Utku Özdemir

Le moyen le plus simple d'obtenir un objet de scène dans le contrôleur est le suivant:

  1. Ajouter une méthode supplémentaire dans sa propre classe de contrôleur créée, telle que

    private Stage myStage;
    public void setStage(Stage stage) {
         myStage = stage;
    }
    
  2. Obtenir le contrôleur dans la méthode de démarrage et définir l'étape

    FXMLLoader loader = new FXMLLoader(getClass().getResource("MyFXML.fxml"));
    OwnController controller = loader.getController();
    controller.setStage(this.stage);
    
  3. Maintenant, vous pouvez accéder à la scène dans le contrôleur

9
Sandeep Kumar

Assign fx: id ou déclarer une variable à/d'un nœud: anchorpane, bouton, etc. Ensuite, ajoutez-y un gestionnaire d'événements et insérez dans ce gestionnaire les codes donnés ci-dessous:

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

J'espère que cela fonctionne pour toi!!

0
Ankit RajDeo