我的应用程序中有两个不同的阶段,它们是使用相同 FXML 文件的帮助屏幕。我不想创建 2 个 FXML 文件,而是只使用一个并拥有两个调用相同 fxml 的控制器。
唯一的问题是控制器是在 FXML 文件中分配的。那么,有没有办法用 Controller 类本身的代码更改分配的控制器?
我真的很想避免复制 FXML 文件只是为了更改每个中的控制器。提前致谢。
我的应用程序中有两个不同的阶段,它们是使用相同 FXML 文件的帮助屏幕。我不想创建 2 个 FXML 文件,而是只使用一个并拥有两个调用相同 fxml 的控制器。
唯一的问题是控制器是在 FXML 文件中分配的。那么,有没有办法用 Controller 类本身的代码更改分配的控制器?
我真的很想避免复制 FXML 文件只是为了更改每个中的控制器。提前致谢。
您可以fx:controller=""
从文件中删除分配,并在加载期间FXML
通过 分配控制器。FXMLLoader
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Your.fxml"));
fxmlLoader.setController(this);
try
{
fxmlLoader.load();
}
catch (IOException exception)
{
throw new RuntimeException(exception);
}
在 FXML 文件中,标签可以引用多个其他 fxml 文件<fx:include>
。fx:controller
每个 fxml 文件都可以使用该属性定义自己的控制器。在fx:controller
标签内部,类型没有给出实例,因此在使用 FXML 加载器解析它时可能会使用自定义Controllerfactory 。
该setControllerFactor
函数需要一个Callback
类型,它是一个只有一个可调用函数的接口:call
工厂使用的函数。该函数(由 FXMLLoader 类调用)期望获取一个Class
对象作为输入参数,并根据类型提供一个实例化对象。以上Java8 lambdas可用于提供工厂:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(fxmlFile));
loader.setControllerFactory((Class<?> controllerType) ->{
if(controllerType == Controller.class){
return new Controller();
}
});
Parent root = (Parent) fxmlLoader.load();
上面代码中的参数controllerType
是 fxmlfx:controller
属性提供的类型,由Java 类加载器决定。当调用 Controllerfactory 时,还没有实例化任何内容,这就是为什么在 fxml 中甚至可以给出抽象类的原因。为了实现不同的行为,可以使用继承。
一个例子是:
class Controller{...}
class FirstController extends Controller{...}
class SecondController extends Controller{...}
工厂可以这样使用:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(fxmlFile));
final int[] instantiatedClasses = {0};
loader.setControllerFactory((Class<?> controllerType) ->{
if(controllerType == Controller.class){
if(0 == instantiatedClasses[0]){
++instantiatedClasses[0];
return new FirstController();
} else return new SecondController();
}
});
Parent root = (Parent) fxmlLoader.load();
请注意,这种方式也可以向控制器提供不同的参数,因此继承可能是一种矫枉过正。例如,可以将primaryStage 提供给控制器,例如用于消除对控制器中不同设置器的需要。
class Controller{
public Controller(int behaviorParam){...}
}
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(fxmlFile));
final int[] instantiatedClasses = {-1}; /* so it would start at 0 */
loader.setControllerFactory((Class<?> controllerType) ->{
if(controllerType == Controller.class){
++instantiatedClasses[0];
return new Controller(instantiatedClasses[0]);
}
});
Parent root = (Parent) fxmlLoader.load();
然而,这种方法的挑战在于,区分同一控制器类型的不同 fxml 实例仍然不是很简单。计算实例化类的数量是一种可行的方法,但与任何基于标识符的方法相比,它并不能提供太多控制。