Java 控制器类中FXML控制器的getter而不是lookup?

Java 控制器类中FXML控制器的getter而不是lookup?,java,javafx,java-8,javafx-8,Java,Javafx,Java 8,Javafx 8,我正在start()中加载FXML,我想把它们放在主窗口中,比如说有一个边框窗格 FXMLLoader loader = new FXMLLoader(); loader.setLocation(Main.class.getResource("Resources/Game.fxml")); Parent root = loader.load(); GameController gameManagerController = load

我正在
start()
中加载FXML,我想把它们放在主窗口中,比如说有一个边框窗格

        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("Resources/Game.fxml"));
        Parent root = loader.load();
        GameController gameManagerController = loader.getController();

        loader = new FXMLLoader();
        loader.setLocation(getClass().getResource("Resources/TopMenuBar.fxml"));
        Parent topMenuBar = loader.load();
        TopMenuBarController topMenuBarController = loader.getController();
现在,在
根目录中查找borderPane将返回null,即使我给了它一个id(不是fx:id)。所以我的问题是,是否可以在
gameManagerController
中为borderPane编写一个getter,然后执行类似的操作

gameManagerController.getBorderPane().setTop(topMenuBar);

在控制器之外公开UI元素通常不是一个好主意。这样做会使以后更改UI的组织方式变得更加困难,因为可能会有控制器FXML对之外的代码,这取决于特定的布局或存在的特定UI元素类

一个简单但更健壮的解决方案是定义一种方法,用于在
GameController
中显示菜单:

public class GameController {

    @FXML
    private BorderPane rootPane ;

    // ...

    public void showMenu(Node menu) {
        rootPane.setTop(menu);
    }

    // ...
}
现在你可以做了

gameManagerController.showMenu(topMenuBar);

一种更复杂的方法是使用“视图模型”来表示应用程序的视图状态,这种方法对于这种情况可能有些过分,但仍然值得一看

public class ApplicationViewState {

    private final ObjectProperty<Node> menu = new SimpleObjectProperty<>();
    private final ObjectProperty<Node> content = new SimpleObjectProperty<>();

    public ObjectProperty<Node> menuProperty() {
        return menu ;
    }

    public final Node getMenu() {
        return menuProperty().get();
    }

    public final void setMenu(Node menu) {
        menuProperty().set(menu);
    }


    public ObjectProperty<Node> contentProperty() {
        return content ;
    }

    public final Node getContent() {
        return contentProperty().get();
    }

    public final void setContent(Node content) {
        contentProperty().set(content);
    }

    // ...
}
然后

FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("Resources/Game.fxml"));
Parent root = loader.load();
GameController gameManagerController = loader.getController();

loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Resources/TopMenuBar.fxml"));
Parent topMenuBar = loader.load();
TopMenuBarController topMenuBarController = loader.getController();


ApplicationViewState viewState = new ApplicationViewState();
gameManagerController.setViewState(viewState);
viewState.setMenu(topMenuBar);

这种方法的优点是,它为任何控制器提供了一种机制来更新应用程序其他部分中的UI,而无需“了解”其他控制器。这有助于分离UI的各个部分。缺点是增加了应用程序的复杂性—调试可能很困难,因为UI中发生的事情不太清楚。

从控制器中公开UI元素通常不是一个好主意(尽管可能比使用非常脆弱的查找更好)。至少,在
GameController
中定义一个方法来显示菜单,这样您就可以调用
gameManagerController.showMenu(topMenuBar)
(根据需要命名方法)。你也可以考虑使用一个“视图模型”,但是在这种情况下它可能是多余的。<代码>显示菜单()/<代码>会做什么?它会这样做:
BorderPane.setTop(topMenuBar)@James_DI会在控制器中用一个更合适的字段名替换
BorderPane
,但这是个好主意。关键是,如果您决定更改布局的管理方式,则所有更改仅限于控制器和FXML,您不需要更改超出此范围的代码。使用您建议的解决方案,如果以后需要,维护或更改您的UI会变得更加困难。当然,我对所有内容都使用有意义的名称。我明白了,再次谢谢你@James_DIs'ApplicationViewState'外观模式?否;不是真的。它实际上只是MVC中的一个模型。
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("Resources/Game.fxml"));
Parent root = loader.load();
GameController gameManagerController = loader.getController();

loader = new FXMLLoader();
loader.setLocation(getClass().getResource("Resources/TopMenuBar.fxml"));
Parent topMenuBar = loader.load();
TopMenuBarController topMenuBarController = loader.getController();


ApplicationViewState viewState = new ApplicationViewState();
gameManagerController.setViewState(viewState);
viewState.setMenu(topMenuBar);