当前位置: 首页 > 知识库问答 >
问题:

如何重用JavaFXGUI?我可以动态更改控制器吗?

杨选
2023-03-14

我使用JavaFXSceneBuilder/FXML设计了一个场景,我想创建该场景的多个实例,但每个场景都有不同的行为。有没有办法动态更改场景/FXML的控制器?

我想要的是设计一个场景并重用它,但是每个实例有不同的行为。

目前我正在加载FXML及其控制器,如下所示:

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(fxmlFile));
Parent root = (Parent) fxmlLoader.load();
Scene scene = new Scene(root);
Controller controller = fxmlLoader.getController();

共有1个答案

赏梓
2023-03-14

在FXML加载器中可以使用自定义的Controlller工厂。setControlllerFactory方法需要一个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();

请注意,通过这种方式,不同的参数也可以提供给控制器,因此继承可能是一种过度杀戮。例如,可以向控制器提供初级阶段,例如用于消除对控制器中不同设置器的需要。

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实例仍然不容易。计算实例化类的数量是一种可行的方法,但与任何基于标识符的方法相比,它没有提供太多的控制。

 类似资料:
  • 问题内容: 如何使用JS更改视频的来源? 问题答案: 当然,您可以在元素上设置属性: 或使用jQuery代替标准DOM方法:

  • 据我所知,当使用FXML描述Java FX场景时,controller类是手动编写的,然后可以从文件引用它的成员变量和方法。当使用加载场景时,成员变量被设置为相应的场景元素,方法被自动连接到相应的事件。这可以工作,但是非常麻烦,因为需要在两个地方进行更改,并且任何错误只会在运行时出现。 我看到过其他GUI框架,这些框架允许您从场景描述生成控制器作为抽象类,需要实现该抽象类来访问场景元素和处理事件。

  • 我使用的是spring boot V1.3.2 我尝试创建自定义注释,它通过添加RequestMapping来扩展RestController。这里有一个例子,但它不起作用。

  • 现在,我从Visual Studio 2015提供的默认ASP.NET核心Web应用程序项目模板开始,包括对单个用户帐户的身份验证。 大多数(如果不是所有)生成的控制器都返回视图,通常遵循以下模式: 此方法返回一个您可以看到的视图,当web客户机请求时,一切都很好。但是如果游戏正在向相同的方法发送请求呢?在这种情况下,需要一个JSON响应(不是view/html文档),我的问题是在ASP.NET核

  • 本文向大家介绍如何更改控制台的WindowLeft,包括了如何更改控制台的WindowLeft的使用技巧和注意事项,需要的朋友参考一下 使用Console.WindowLeft属性更改C#中控制台的WindowLeft。 示例 现在让我们看一个例子- 输出结果 这将产生以下输出-

  • 问题内容: 谈话很便宜,请先显示我的代码: HTML: 指示: }); 控制器: 现在工作了,当我单击加号图标时,浏览器控制台输出“添加”。 但我想将控制器动态设置为指令,如下所示: HTML: 控制器: 指令喜欢: 如何实现我的目标?感谢您的回答! 问题答案: 现在可以使用AngularJS。在指令中你只需要添加两个新的属性叫 ,财产,也正好在这里需要。 指令中要注意的重要事项 设置指令动态控制