使用fx时自定义控制器工厂:include



我使用的是JavaFX 15.0.1版本。我想通过注入几个FXML文件来制作更复杂的场景,像这样:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane fx:controller="MainFxmlController">
<children>
<VBox>
<children>
<fx:include fx:id="topMenu" source="top_menu.fxml" />
<fx:include fx:id="navigation" source="navigation.fxml" />
<fx:include fx:id="statusBar" source="status_bar.fxml" />
</children>
</VBox>
</children>
</AnchorPane>

在这里,我发现包含FXML的控制器是自动加载的,并注入到主控制器(在本例中为MainFxmlController)中名为fx:id> controller的<value的@FXML注释字段中。>

我的问题是:在这种情况下,我如何使用我自己的控制器工厂实例化相应的控制器类?我需要在构造函数中给控制器一些依赖项。

所包含的FXML将与所包含的FXML使用相同的控制器工厂;因此,控制器工厂可以测试传递给回调方法的控制器类,创建适当的对象,并将依赖项传递给它。

像这样:

// application model class:
DataModel model = new DataModel();
FXMLLoader loader = new FXMLLoader(getClass().getResource("main.fxml"));
loader.setControllerFactory(controllerType -> {
if (controllerType == MainController.class) {
return new MainController(model);
}
if (controllerType == TopMenuController.class) {
return new TopMenuController(model);
}
if (controllerType == NavigationController.class) {
return new NavigationController(model);
}
if (controllerType == StatusBarController.class) {
return new StatusBarController(model);
}
return null ; // or throw an unchecked exception
});
Parent mainRoot = loader.load();

如果你喜欢(或需要更多的通用性),你可以使用反射:

loader.setControllerFactory(controllerType -> {
try {
for (Constructor<?> c : controllerType.getConstructors()) {
if (c.getParameterCount() == 1 
&& c.getParameterTypes()[0] == DataModel.class) {
return c.newInstance(model);
}
}
// If we got here, there's no constructor taking a model,
// so try to use the default constructor:
return controllerType.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
});

最新更新