从另一个控制器设置 borderpane 的中心 class
Setting center of borderpane form another controller class
我将 Borderpane 作为 homePane(它的 fxml 文件是 home.fxml)。首先,在 homePane 的中心我有一个 HBox,其中包含一个名为 delivery 的按钮。当用户单击此按钮时,homePane 的中心切换为显示客户列表。
有效!
homeController代码:
public class HomeController {
@FXML
private BorderPane homePane;
@FXML
public void deliveryBtnClicked (){
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fragments/customers.fxml"));
homePane.getChildren().remove(homePane.getCenter());
try {
Pane pane = loader.load();
homePane.setCenter(pane);
}catch (IOException e){
System.out.println(e.getMessage());
}
}
public BorderPane getHomePane() {
return homePane;
}
}
新窗格包含 table 个客户和一个名为订单的按钮。它有自己的控制器:
public class CustomerController {
@FXML
public void loadOrderView() throws IOException {
Customer customer = customerTable.getSelectionModel().getSelectedItem();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/home.fxml"));
loader.load();
HomeController homeController = loader.getController();
BorderPane homePane = homeController.getHomePane();
homePane.getChildren().remove(homePane.getCenter());
System.out.println(homePane.getCenter());
FXMLLoader loader1 = new FXMLLoader(getClass().getResource("/fragments/order.fxml"));
Pane orderView = loader1.load();
homePane.setCenter(orderView);
System.out.println(homePane.getCenter());
}
}
当用户点击订单按钮时,订单视图必须加载到 homePane 的中央。
打印命令显示删除后的 homePane 中心为空,然后加载后获得新视图。
null
AnchorPane@755b1503
但在 运行 程序中它不显示顺序视图。我已将按钮顺序的 onAction 设置为 loadOrderView。这绝对不是问题。
正如 James 所指出的,您不应该再次加载 home fxml。
改为:
在控制器和 fxml 中定义 orderButton(通过 fx:id
和 @FXML
注入)。
使用场景图找到主窗格,以便您可以替换它的中心。
public class CustomerController {
@FXML Button orderButton
@FXML
public void loadOrderView() throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fragments/order.fxml"));
Pane orderView = loader.load();
BorderPane homePane = (BorderPane) orderButton.getScene().getRoot();
homePane.setCenter(orderView);
}
}
小框架中的替代方法定义在以下问题的答案中:
- Loading new fxml in the same scene
您可以导航场景图,如 所示,这对于小型应用程序来说是一个非常好的解决方案。
对于较大的应用程序,您可能需要在更改能力方面具有更大的灵活性,例如如何管理布局,请考虑使用 MVC/MVVM 类型的方法。从维持当前视图状态的模型 class 开始:
public class ViewModel {
public enum View {
CUSTOMER(ViewModel.class.getResource("/fragments/customer.fxml")),
ORDER(ViewModel.class.getResource("/fragments/order.fxml"));
private final URL resource ;
private View(URL resource) {
this.resource = resource ;
}
public URL getResource() {
return resource ;
}
}
private final ObjectProperty<View> currentView = new SimpleObjectProperty<>();
public ObjectProperty<View> currentViewProperty() {
return currentView ;
}
public final View getCurrentView() {
return currentViewProperty().get();
}
public final void setCurrentView(View currentView) {
currentViewProperty().set(currentView);
}
}
让你的控制器实现一个接口,允许它们引用 ViewModel
:
public interface ViewModelObserver {
public void setViewModel(ViewModel model);
}
你的 HomeController
,假设它被加载一次并且主页始终显示,可以创建 ViewModel
的单个实例,观察它,更新边框窗格,并传递实例加载到其他控制器时:
public class HomeController {
private final ViewModel viewModel = new ViewModel();
@FXML
private BorderPane homePane;
@FMXL
public void initialize() {
viewModel.currentViewProperty().addListener((obs, oldView, newView) -> {
try {
FXMLLoader loader = new FXMLLoader(newView.getResource());
Parent root = loader.load();
Object controller = loader.getController();
if (controller instanceof ViewModelObserver) {
((ViewModelObserver)controller).setViewModel(viewModel);
}
homePane.setCenter(root);
} catch (Exception exc) {
exc.printStackTrace();
}
});
}
@FXML
public void deliveryBtnClicked (){
viewModel.setCurrentView(ViewModel.View.CUSTOMER);
}
}
然后为 FXML“片段”实现控制器 ViewModelObserver
。他们可以简单地更新当前视图,家庭控制器将加载并显示它:
public class CustomerController implements ViewModelObserver {
private ViewModel viewModel ;
@Override
public void setViewModel(ViewModel viewModel) {
this.viewModel = viewModel ;
}
@FXML
public void loadOrderView() throws IOException {
viewModel.setCurrentView(ViewModel.View.ORDER);
}
}
您可能需要在视图模型中包含其他属性,例如授予对 Customer
实例等的访问权
我将 Borderpane 作为 homePane(它的 fxml 文件是 home.fxml)。首先,在 homePane 的中心我有一个 HBox,其中包含一个名为 delivery 的按钮。当用户单击此按钮时,homePane 的中心切换为显示客户列表。 有效!
homeController代码:
public class HomeController {
@FXML
private BorderPane homePane;
@FXML
public void deliveryBtnClicked (){
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fragments/customers.fxml"));
homePane.getChildren().remove(homePane.getCenter());
try {
Pane pane = loader.load();
homePane.setCenter(pane);
}catch (IOException e){
System.out.println(e.getMessage());
}
}
public BorderPane getHomePane() {
return homePane;
}
}
新窗格包含 table 个客户和一个名为订单的按钮。它有自己的控制器:
public class CustomerController {
@FXML
public void loadOrderView() throws IOException {
Customer customer = customerTable.getSelectionModel().getSelectedItem();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/home.fxml"));
loader.load();
HomeController homeController = loader.getController();
BorderPane homePane = homeController.getHomePane();
homePane.getChildren().remove(homePane.getCenter());
System.out.println(homePane.getCenter());
FXMLLoader loader1 = new FXMLLoader(getClass().getResource("/fragments/order.fxml"));
Pane orderView = loader1.load();
homePane.setCenter(orderView);
System.out.println(homePane.getCenter());
}
}
当用户点击订单按钮时,订单视图必须加载到 homePane 的中央。 打印命令显示删除后的 homePane 中心为空,然后加载后获得新视图。
null
AnchorPane@755b1503
但在 运行 程序中它不显示顺序视图。我已将按钮顺序的 onAction 设置为 loadOrderView。这绝对不是问题。
正如 James 所指出的,您不应该再次加载 home fxml。
改为:
在控制器和 fxml 中定义 orderButton(通过
fx:id
和@FXML
注入)。使用场景图找到主窗格,以便您可以替换它的中心。
public class CustomerController {
@FXML Button orderButton
@FXML
public void loadOrderView() throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fragments/order.fxml"));
Pane orderView = loader.load();
BorderPane homePane = (BorderPane) orderButton.getScene().getRoot();
homePane.setCenter(orderView);
}
}
小框架中的替代方法定义在以下问题的答案中:
- Loading new fxml in the same scene
您可以导航场景图,如
对于较大的应用程序,您可能需要在更改能力方面具有更大的灵活性,例如如何管理布局,请考虑使用 MVC/MVVM 类型的方法。从维持当前视图状态的模型 class 开始:
public class ViewModel {
public enum View {
CUSTOMER(ViewModel.class.getResource("/fragments/customer.fxml")),
ORDER(ViewModel.class.getResource("/fragments/order.fxml"));
private final URL resource ;
private View(URL resource) {
this.resource = resource ;
}
public URL getResource() {
return resource ;
}
}
private final ObjectProperty<View> currentView = new SimpleObjectProperty<>();
public ObjectProperty<View> currentViewProperty() {
return currentView ;
}
public final View getCurrentView() {
return currentViewProperty().get();
}
public final void setCurrentView(View currentView) {
currentViewProperty().set(currentView);
}
}
让你的控制器实现一个接口,允许它们引用 ViewModel
:
public interface ViewModelObserver {
public void setViewModel(ViewModel model);
}
你的 HomeController
,假设它被加载一次并且主页始终显示,可以创建 ViewModel
的单个实例,观察它,更新边框窗格,并传递实例加载到其他控制器时:
public class HomeController {
private final ViewModel viewModel = new ViewModel();
@FXML
private BorderPane homePane;
@FMXL
public void initialize() {
viewModel.currentViewProperty().addListener((obs, oldView, newView) -> {
try {
FXMLLoader loader = new FXMLLoader(newView.getResource());
Parent root = loader.load();
Object controller = loader.getController();
if (controller instanceof ViewModelObserver) {
((ViewModelObserver)controller).setViewModel(viewModel);
}
homePane.setCenter(root);
} catch (Exception exc) {
exc.printStackTrace();
}
});
}
@FXML
public void deliveryBtnClicked (){
viewModel.setCurrentView(ViewModel.View.CUSTOMER);
}
}
然后为 FXML“片段”实现控制器 ViewModelObserver
。他们可以简单地更新当前视图,家庭控制器将加载并显示它:
public class CustomerController implements ViewModelObserver {
private ViewModel viewModel ;
@Override
public void setViewModel(ViewModel viewModel) {
this.viewModel = viewModel ;
}
@FXML
public void loadOrderView() throws IOException {
viewModel.setCurrentView(ViewModel.View.ORDER);
}
}
您可能需要在视图模型中包含其他属性,例如授予对 Customer
实例等的访问权