JavaFX 控制器与动态内容的通信

JavaFX controller communication with dynamic content

这是我正在创建的 JavaFX android 移动应用程序的一般结构。 使用(AppBar 或 AppBarSearch 这些动态交换)作为主应用程序 FXML 中的嵌套控制器。

父控制器 - 应用栏控制器 - AppBarSearchController

primary.fxml - appBar.fxml / appBarSearch.fxml

    <AnchorPane fx:id="appBarPane" prefHeight="56.0" prefWidth="350.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
        <children>
            <fx:include source="appbar.fxml" fx:id="appBar" /> 
    <!-- initially shows AppBar but appBarSearch can also be here after clicking search button -->
        </children>
    </AnchorPane>

每个子 fxml 中的一个按钮负责在 appBar/AppBarSearch.

的 fxml 内容之间切换

当我将 appBar 的内容动态更改为 appBarSearch 并返回时,就会出现问题。我希望 appBar 菜单按钮与 NavigationMenu 进行通信以滑入和滑出。

我一直在研究是否应该以某种方式在 AppBarController 中拥有一个 parentController 的实例。

我确实使用了以下内容:

@FXML
private AppBarController appBarController; // injected via <fx:include fx:id="child" ... />

<fx:include source="appbar.fxml" fx:id="appBar" /> <- dynamically changes

//to dynamically change content in Panes
public static void setView(View view, Pane pane) {
    try {
        pane.getChildren().clear();
        pane.getChildren().setAll((Node) FXMLLoader.load(Main.class.getResource(view.getTemplate()), resources));
    } catch (IOException e) {
        logger.error(e.getMessage());
    }
}

    @FXML
public void initialize() {
    appBarController.setParentController(this);
}

    @FXML
private void menuButtonClick (ActionEvent event) {
    this.parentController.triggerMenu();
}

最初上面的工作,但在 appBarSearch 和 appBar 之间切换后,它给了我一个指向 parentController 实例的 nullPointer。

可能是动态切换控制器后无法识别子控制器。

我希望 AppBar 中的 menuBtn 打开一个导航菜单,因此它需要从 PrimaryController 中调用 triggerMenu() 以在单击 AppBar 中的按钮后启动它滑入和滑出的动画。

非常感谢评论,我能够解决问题并提高我对如何使用控制器和包含的 fxml 的理解。 下面是我用来连接子控制器和我的主控制器并动态改变视图的通用代码。

@FXML
private AppBarController appBarController; // injected via <fx:include fx:id="child" ... />

@FXML
private NavMenuController navMenuController; // injected via <fx:include fx:id="child" ... />

@FXML
private MainContentController mainContentController; // injected via <fx:include fx:id="child" ... />

@FXML
public void initialize() {
    appBarController.setScreenParent(this);
    navMenuController.setScreenParent(this);
    mainContentController.setScreenParent(this);
}

/**
 * Set View on a Pane Javafx component
 */
public <T extends Pane> boolean setView(View view, T pane) {
    try {
        FXMLLoader myLoader = new FXMLLoader(getClass().getResource(view.getTemplate()), resources);
        pane.getChildren().clear();
        pane.getChildren().setAll((Node) myLoader.load());
        ControlledScreen childController = myLoader.getController();
        childController.setScreenParent(this);
        return true;
    } catch (IOException e) {
        logger.error(e.getMessage());
        return false;
    }
}

public void setMainContentView(View view) {
    setView(view, mainContentPane);
}

public void setAppBarView(View view) {
    setView(view, appBarPane);
}

public void setNavMenuView(View view) {
    setView(view, navMenuPane);
}

public void triggerNavMenu() {
    if (navMenuPane.getTranslateX() != 0) {
        openNav.play();
        appBarController.setMenuClosedImage();
    } else {
        closeNav.setToX(-(navMenuPane.getWidth()));
        closeNav.play();
        appBarController.setMenuClosedImage();
    }
}