0

I'm trying to make a tricky(stupid mb?) algorithm to pass parameters between opened app windows. What I'm doing:

  1. I have a Pane - expanding class with necessary fields. It will be the "gate".
  2. Invoking controller loads node tree from FXML, attaches it as a child to the "gate" object
  3. then creates and shows a new scene with "gate" as a root node.
  4. new window controller has a reference to FXML root node (direct child of the "gate") and all he need to do is use .getParent() on it to get the "gate".

But what the heck! It returns null! What am I doing wrong? Should i set a different controller via FXMLLoader?

And what will be the right way to organize message stream from one controller to another?

here are the code chunks: main app class:

private void handleMenuVisibility(ActionEvent event) throws IOException
{
    Parent root = FXMLLoader.load(getClass().getResource("/ContextMenus/Visibility.fxml"));
    final AttributedWrapper aw = new AttributedWrapper();
    aw.getChildren().add(root);
    Scene scene = new Scene(aw);
    Stage stage = new Stage();
    stage.setScene(scene);
    stage.show();
}

and the invoked window controller:

public void initialize(URL url, ResourceBundle rb) {
AttributedWrapper aw = (AttributedWrapper) anchorPane.getParent();
}

upd: AttributedWrapper is a class that extends javafx.scene.layout.Pane

major upd: found some info here: How to pass object created in FXML Controller1 to Controller2 of inner FXML control i use my attributedWrapper as a root node on FXML file, and in general it works. But the problem remains in the invoked controller initialization. Parameters i've sent from main app controller to the invoked one are not availible. The function

    public void initialize(URL url, ResourceBundle rb)

starts exactly when the FXMLLoader.load() is performed and before I put data into wrapper.

Here are essentials: main app

final AttributedWrapper aw = FXMLLoader.load(getClass().getResource("/ContextMenus/Visibility.fxml"));
Scene scene = new Scene(aw);
Stage stage = new Stage();
stage.setScene(scene);
    aw.writeParam("key1", "value1");
    stage.show()

invoked controller

@FXML private AttributedWrapper aw;
public void initialize(URL url, ResourceBundle rb) {
System.out.println(aw.readParam("key1"));
anchorPane.writeParam("key2", "value2");
}

after closing invoked window, I read "key2" param and it is ok, but reading "key1" from invoked window returns null.

What will be the right way to pass params here? Or all i can do is making static fields?

Community
  • 1
  • 1
Chechulin
  • 2,426
  • 7
  • 28
  • 35

1 Answers1

1

The problem is that method public void initialize(URL url, ResourceBundle rb) is being called during FXMLLoader call:

Parent root = FXMLLoader.load(getClass().getResource("/ContextMenus/Visibility.fxml"));

thus your Parent is not yet set.

There are several approached to solve that:

  1. Move initialize logic into separate method and call it manually:

    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/ContextMenus/Visibility.fxml"));
    Parent root = fxmlLoader.load();
    controller = (MyController) fxmlLoader.getController();
    final AttributedWrapper aw = new AttributedWrapper();
    aw.getChildren().add(root);
    controller.doMyInit();
    
  2. Use your "major upd" approach, but again -- call custom init after setting parameters.

  3. Add listener to anchorPane.parentProperty() and perform initialization then Parent became not null.

    root.parentProperty().addListener(new ChangeListener<Parent>() {
    
        @Override
        public void changed(ObservableValue<? extends Parent> ov, Parent oldP, Parent newP) {
            if (newP != null && oldP == null) {
                System.out.println("my parent is " + newP);
            }
        }
    });
    
Sergey Grinev
  • 34,078
  • 10
  • 128
  • 141