简体   繁体   English

JavaFX从FXML子访问父控制器类

[英]JavaFX access parent Controller class from FXML child

using JavaFX for an application and I have a Main.fxml file with some fxml child files inside it. 使用JavaFX作为应用程序,我有一个Main.fxml文件,里面有一些fxml子文件。

I would like to access to MainController class of Main.fxml from the child Controllers. 我想从子控制器访问Main.fxml的MainController类。

I'll try to explain better with an example: 我将尝试用一个例子更好地解释:

MainFxml: MainFxml:

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

MainController: MainController:

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

ChildFxml: ChildFxml:

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

ChildController: 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. 我尝试在StackOverflow上找到这个解决方案,但我需要获取已经加载的Main.fxml的Controller引用。 Is there any method to get the Controller starting from a specific Pane? 是否有任何方法可以从特定的窗格启动Controller? Something like: 就像是:

    // child.getParent().getController();

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 . 如果将fx:id分配给<fx:include>标记, FXMLLoader尝试将包含的fxml的控制器注入名为<fx:id>Controller的字段。 You can pass the MainController reference to the child controllers in the initialize method: 您可以在initialize方法中将MainController引用传递给子控制器:

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

MainController MainController

@FXML
private ChildController childController;

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

ChildController 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. 但是,更好的做法是让ChildController独立于父ChildController This could be done by providing a StringProperty in the ChildController that gets set to the value the parent should display. 这可以通过在ChildController中提供一个StringProperty来完成,该StringProperty设置为父应该显示的值。

ChildController ChildController

private final StringProperty value = new SimpleStringProperty();

public StringProperty valueProperty() {
    return value;
}

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

ParentController ParentController

@Override
public void initialize(URL url, ResourceBundle rb) {
    childController.valueProperty().addListener((observable, oldValue, newValue) -> setString(newValue));
}

I solved this issue in my own projects with the use of the Singleton model. 我使用Singleton模型在自己的项目中解决了这个问题。 You can use a separate class to keep references to parent controllers. 您可以使用单独的类来保持对父控制器的引用。

For example: 例如:

Global.java: 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); 在父控制器中,您只需要通过调用Global.setParentController(this);自身的引用传递给GlobalGlobal.setParentController(this); . You can then access it from the child by using the Getter: Global.getParentController(); 然后,您可以使用Getter: Global.getParentController();从子Global.getParentController();访问它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. 我自己对Java很新,这可能不是用于这种情况的最复杂的方法,但到目前为止它对我来说非常有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM