2016-09-05 46 views
1

我加载fxmls在start(),我想将它们放置在其中有说borderPane主窗口。获取控制器类中的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(); 

现在查找在root的borderPane被返回null,即使我没有给它一个id(不FX:ID)。所以我的问题是,可以接受为gameManagerController中的borderPane写一个getter,然后做这样的事情吗?

gameManagerController.getBorderPane().setTop(topMenuBar); 
+1

从控制器中公开UI元素通常不是一个好主意(尽管它可能比使用查找非常脆弱)。至少,在'GameController'中定义一个显示菜单的方法,这样你就可以调用'gameManagerController.showMenu(topMenuBar)'(为任何适当的方法命名)。你也可以考虑使用“视图模型”,但在这种情况下它可能是矫枉过正的。 –

+0

'showMenu()'会做什么?它会这样做:'BorderPane.setTop(topMenuBar);'? @James_D – shinzou

+2

我会在控制器中用一个更合适的字段名替换'BorderPane',但是,是的,这是想法。重点是,如果您决定更改布局的管理方式,所有更改仅限于控制器和FXML,您不需要更改代码。如果您以后需要使用您的建议解决方案,维护或更改您的用户界面将变得更加困难。 –

回答

2

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

一个简单的,但更强大的解决方案,只是在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); 
    } 

    // ... 
} 

现在你可以共享控制器之间的视图模型,可以观察和更新状态,因为它们需要的单一实例:

public class GameController { 

    @FXML 
    private BorderPane rootPane ; 

    private ApplicationViewState viewState ; 

    public void setViewState(ApplicationViewState viewState) { 
     this.viewState = viewState ; 
     rootPane.topProperty().bind(viewState.menuProperty()); 
    } 

    // ... 
} 

然后

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中发生的不同事情。

+0

'ApplicationViewState'是一个门面模式吗? – shinzou

+0

否;不是真的。这只是MVC中的一个模型。 –

相关问题