具有多个不同控制器的JavaFX 1 FXML文件?

时间:2013-04-12 06:46:02

标签: controller javafx fxml

我的应用程序中有两个不同的阶段,即使用相同FXML文件的帮助屏幕。而不是创建2个FXML文件,我想只使用一个,并有两个控制器调用相同的fxml。

唯一的问题是Controller是在FXML文件中分配的。那么,有没有办法在Controller类本身中用代码更改分配的控制器?

我真的想避免重复FXML文件只是为了更改每个文件中的Controller。提前谢谢。


2 个答案:

答案 0 :(得分:7)

您可以从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);
}

查看Introduction to FXML section on custom components

答案 1 :(得分:0)

在 FXML 文件中,<fx:include> 标记可以引用多个其他 fxml 文件。每个 fxml 文件都可以使用 fx:controller 属性定义自己的控制器。 在 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是fxml fx:controller属性提供的类型,由Java Class loader决定。当调用 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 实例仍然不是很简单。计算实例化类的数量是一种有效的方法,但与任何基于标识符的方法相比,它并没有提供太多控制。