JavaFX access parent Controller class from FXML child
Asked Answered
I

2

13

using JavaFX for an application and I have a Main.fxml file with some fxml child files inside it.

I would like to access to MainController class of Main.fxml from the child Controllers.

I'll try to explain better with an example:

MainFxml:

    <HBox fx:controller="MainController.java">
        <fx:include source="child.fxml"/>
    </HBox>

MainController:

    public class MainController implements Initializable {
            private String string;
            public void setString (String string) {
                    this.string = string;
            }

ChildFxml:

    <HBox fx:id="child" fx:controller="ChildController.java">
        <Button text="hello" onAction="#selectButton"></Button>
    </HBox>

ChildController:

    public class ChildController implements Initializable {
            @FXML HBox child;
            @FXML Button button;
            @FXML
            public void selectButton (ActionEvent event) {
                // here call MainController.setString("hello");
            }

I tried this solution found on StackOverflow but I need to get the Controller reference of the Main.fxml that has been already loaded. Is there any method to get the Controller starting from a specific Pane? Something like:

    // child.getParent().getController();
Irresolution answered 28/6, 2017 at 16:5 Comment(1)
Maybe you can share a StringProperty object between ChildController and MainController so MainController can update itself when the string changes. See #31266998 for some more info.Alsace
D
19

If you assign a fx:id to the <fx:include> tag, FXMLLoader tries to inject the the controller of the included fxml to a field named <fx:id>Controller. You can pass the MainController reference to the child controllers in the initialize method:

<HBox fx:controller="MainController.java">
    <fx:include fx:id="child" source="child.fxml"/>
</HBox>

MainController

@FXML
private ChildController childController;

@Override
public void initialize(URL url, ResourceBundle rb) {
    childController.setParentController(this);
}

ChildController

private MainController parentController;

public void setParentController(MainController parentController) {
    this.parentController = parentController;
}

@FXML
private void selectButton (ActionEvent event) {
    this.parentController.setString("hello");
}

It would however be better practice to keep the ChildController independent from the parent. This could be done by providing a StringProperty in the ChildController that gets set to the value the parent should display.

ChildController

private final StringProperty value = new SimpleStringProperty();

public StringProperty valueProperty() {
    return value;
}

@FXML
private void selectButton (ActionEvent event) {
    value.set("hello");
}

ParentController

@Override
public void initialize(URL url, ResourceBundle rb) {
    childController.valueProperty().addListener((observable, oldValue, newValue) -> setString(newValue));
}
Disoblige answered 28/6, 2017 at 16:36 Comment(0)
M
0

I solved this issue in my own projects with the use of the Singleton model. You can use a separate class to keep references to parent controllers.

For example:

Global.java:

public class Global {

    public static ParentControllerClass parentController;

    private Global() {
    }

    public static ParentControllerClass getParentController() {
        return mainApp;
    }

    public static void setParentController(ParentControllerClass parentController) {
        Global.parentController = parentController;
    }
}

Within your parent controller, you would just need to pass a reference to itself to the Global class by calling Global.setParentController(this);. You can then access it from the child by using the Getter: Global.getParentController();

This is preferable to having the parent and child share the same controller as it helps to keep your code cleaner and easier to read.

I am fairly new to Java myself and this may not be the most sophisticated method to use for this scenario, but it has worked perfectly for me thus far.

Menswear answered 29/6, 2017 at 2:30 Comment(1)
This approach will be a trouble when you have multiple stage in your applicationAerobiology

© 2022 - 2024 — McMap. All rights reserved.