我有两个FXML
个文档,每个文档代表一个视图,我们称之为View1
和View2
,我已将每个文档放在一个单独的Tab
中},(Tab1
和Tab2
)在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
}
}
答案 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个月内走进你的办公室并说“顾客不喜欢标签窗格,用一次只显示一个屏幕的东西替换它”时,这很容易一切都正确地解耦,做出类似的改变。 (您只需要更改主视图及其控制器,其他任何视图或控制器都不会发生任何变化。)如果将选项卡窗格暴露给所有其他控制器,则必须找到您访问过的所有位置它可以做出类似的改变。