2016-09-05 66 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中的一個模型。 –

相關問題