JavaFX:检索节点

时间:2016-12-22 14:49:52

标签: javafx fxml

我有两个FXML个文档,每个文档代表一个视图,我们称之为View1View2,我已将每个文档放在一个单独的Tab中},(Tab1Tab2)在TabPane内。

现在位于Controller1的{​​{1}}我有一个事件会将View1的{​​{1}}从selectedItem切换为TabPane。我的问题是如何从Tab1

访问我的Tab2

总的来说。我们如何在TabPane中检索某个Controller1

修改 视图1

Node

控制器1

Javafx

的MainView

<VBox fx:controller="controllers.Controller1">
    <Button onAction="#openView2"/>
</VBox>

MainController

public class Controller1{
    public void openView2(){
        //What should I do here
    }
}

1 个答案:

答案 0 :(得分:2)

您应该创建一个“视图模型”,它封装视图的当前状态,并与每个控制器共享。然后从主控制器观察并做出相应的响应。

例如:

public class ApplicationState {

    private final StringProperty currentViewName = new SimpleStringProperty();

    public StringProperty currentViewNameProperty() {
        return currentViewName ;
    }

    public final String getCurrentViewName() {
        return currentViewNameProperty().get();
    }

    public final void setCurrentViewName(String viewName) {
        currentViewNameProperty().set(viewName);
    }
}

现在你可以这样做(注意我在这里也删除了冗余的重复代码):

public class MainController implements Initializable {

    @FXML
    public TabPane tabPane;

    private final ApplicationState appState = new ApplicationState();
    private final Map<String, Tab> views = new HashMap<>();

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        try {
            tabPane.getTabs().add(createViewTab("View1", new Controller1(appState)));
            tabPane.getTabs().add(createViewTab("View2", new Controller2(appState)));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        appState.currentViewNameProperty().addListener((obs, oldView, newView) ->
            tabPane.getSelectionModel().select(views.get(newView)));
        appState.setCurrentViewName("View1");
    }

    protected Tab createViewTab(String viewName, Object controller) throws IOException {
        Tab tab = new Tab();
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/"+viewName+".fxml"));
        loader.setController(controller);
        tab.setContent(loader.load());
        views.put(viewName, tab);
        return tab;
    }


}

现在你的控制器必须这样做:

public class Controller1{

    private final ApplicationState appState ;

    public Controller1(ApplicationState appState) {
        this.appState = appState ;
    }

    public void openView2(){
        appState.setCurrentViewName("View2");
    }
}

请注意,由于控制器没有no-arg构造函数,因此我使用loader.setController(...)在代码中设置它们。这意味着您必须从view1和view2的fxml文件中删除fx:controller属性,例如你的View1.fxml变为:

<VBox xmlns="..."> <!-- no fx:controller here -->
     <Button onAction="#openView2"/>
</VBox>

这种设计的优点是,当你的老板在8个月内走进你的办公室并说“顾客不喜欢标签窗格,用一次只显示一个屏幕的东西替换它”时,这很容易一切都正确地解耦,做出类似的改变。 (您只需要更改主视图及其控制器,其他任何视图或控制器都不会发生任何变化。)如果将选项卡窗格暴露给所有其他控制器,则必须找到您访问过的所有位置它可以做出类似的改变。