我能否从FXML自动生成控制器类?

19

据我所了解,使用 FXML 描述 Java FX 场景时,控制器类需手动编写,其中的成员变量和方法可从 .fxml 文件中引用。当使用 FXMLLoader 加载场景时,成员变量被设置为相应的场景元素,方法会自动连接到相应的事件上。这种方式可以工作,但是很麻烦,因为需要在两个地方进行更改,任何错误都只会在运行时显示。

我看到其他 GUI 框架允许您从场景描述中生成控制器作为抽象类,需要实现该类才能访问场景元素并处理事件。以下是我的一个例子:

我将创建以下 .fxml 文件(例如使用 JavaFX Scene Builder):

<AnchorPane ... >
  <children>
     <Button fx:id="button" ... text="Button" onAction="#buttonPressed" />
  </children>
</AnchorPane>

在我的构建过程中,以下的.java文件将会被创建(例如使用Maven插件):

abstract class TestController {
    protected final Parent root;
    protected final Button button;

    {
        // Load test.fxml file
        // Assign scene elements to root and button
        // Attach event handler to the button that calls buttonClicked()
    }

    protected abstract void buttonClicked(ActionEvent event);
}

我随后可以创建该控制器的一个具体实现,可能会多次进行:

final class TestControllerImpl extends TestController {
    TestControllerImpl(String buttonLabel) {
        button.setText(buttonLabel);
    }

    @Override
    protected void buttonClicked(ActionEvent event) {
        button.setText("I've been clicked! What a great day!");
    }
}

有没有一个旨在实现这个目标的项目?或者在应用于 FXML 时是否存在问题?

我认为这种方法有以下好处:

  • 控制器的成员变量和方法声明会自动生成。
  • 所有成员变量都是 finalprotected,而不是 non-final 并且要么是public 要么带注解。
  • 方法也是如此,它们是 protected,而不是 public 或者带注解。
  • 未实现方法或拼写错误将导致编译错误。
  • 场景的编程设置可以在构造函数中完成,而不是在initialize()方法中完成,因为构造函数会在场景加载并将其元素分配给成员变量之后运行。

只是出于好奇,您是否使用过JavaFX Scene Builder的自动控制器示例? - ItachiUchiha
@ItachiUchiha 我已经使用过它,虽然它确实减少了创建控制器类的工作量,但它并没有解决我想避免的任何问题。此外,它只有在最初创建控制器时有所帮助,而不是在修改具有现有控制器的视图时。 - Feuermurmel
8个回答

13

现在在SceneBuilder、NetBeans和Eclipse中都支持此功能。请注意,在NetBeans和SceneBuilder中,此功能开箱即用,但是在Eclipse中,您需要首先安装 e(fx)clipse 插件。

SceneBuilder: 在编辑器中打开 FXML 文件后,进入菜单选择 "View" 和 "Show Sample Controller Skeleton"。

Eclipse: 打开 FXML 文件,让其内容显示在代码编辑窗格中(在 Eclipse 中,您应该看到 FXML 以纯文本 XML 的形式呈现,带有语法高亮,而不是在 SceneBuilder 中进行可视化渲染)。右键单击 Eclipse 中的代码,选择 "Code",然后选择 "Generate Controller"。

NetBeans: 在 NetBeans 中,甚至更加简单,只需右键单击项目资源管理器中的 FXML 文件,然后选择 "Make Controller"。


1
顺便说一句,更新一下。在Eclipse Oxygen中,右键单击代码->源->生成控制器。 - user3437460
1
@user3437460。很高兴你这么说,因为我在Eclipse Photon中找不到它。可惜它说,“不支持更新现有控制器!”也许有一天会支持,并且拼写得到纠正! - jradxl
在Eclipse 2020-09上,我是否需要在按下“生成控制器”之前创建一个单独的控制器类,或者如果您已经有一个控制器类,它会自动创建一个控制器类?我实际上尝试了上述解决方案,但是除非我已经创建了一个控制器类,否则它不会生成控制器类。在IntelliJ v2020及更高版本中,如果您还没有控制器类,它将要求用户创建一个。 - miKeL

9

2020年11月更新

本回答已经过时。

正如其他更近期的回答所指出的,现在有许多不同的工具可用于从FXML文档自动生成FXML控制器类。其中许多是针对现有开发工具(如SceneBuilder、Idea、Eclipse或NetBeans)的扩展、特性或插件。

我建议感兴趣的读者们先阅读这个回答和其他相关问题的回答,然后查看他们的个人用例和工具链,并从可用选择中选择最适合他们的解决方案。


我不知道有什么东西可以完全按照您在问题中提出的要求进行操作。

很可能随着时间的推移,这个回答会变得相当过时。

替代技术

JRuby使用略微不同的方法实现了您概述的大部分优点——它使用jRuby的动态编程魔法,在运行时动态地从FXML自动创建Ruby类成员。

Tom Schindl编写了一个从FXML生成Java代码的工具。在本回答列出的各种方法中,Tom的工具似乎最接近您的问题。

SceneBuilder骨架

在SceneBuilder的View | Show Sample Controller Skeleton功能中提供了一个类似的从FXML生成Java代码的工具,这在这篇博客文章中有所描述。当我使用SceneBuilder时,我经常使用这个功能,并尽量保持我的控制器非常轻量级,以便它们几乎都是从SceneBuilder骨架功能自动生成的代码。

但是,这有点让人烦恼,因为它没有实现生成代码和手写代码之间的干净分离,所以当您更新FXML并想要生成新的骨架并将其复制粘贴到现有控制器的某些部分时,需要小心(此外,这是一项稍微容易出错的手动操作,需要一些开发人员的时间)。

如果您想查看它的工作原理,可以查看SceneBuilder的源代码

潜在的构建工具插件

这样的代码生成功能可能是JavaFX生态系统中一些现有构建工具(如JavaFX Maven插件JavaFX Gradle插件)的有价值的补充,也可以作为一个独立插件。

未来的发展

我相信Oracle也在为将来的JavaFX版本(Java 8之后)开发一个FXML的功能扩展,它可以直接将FXML编译为Java字节码(类文件),跳过Java源代码步骤。这种功能可能会实现您列出的大部分好处。


8

在NetBeans 8 版本中是可以实现的。

打开FXML,进入Source(源代码)并点击generate controller(生成控制器)。

编辑:现在任何IDE都可以完成这个操作,但Eclipse需要一个插件。


我正在寻找一些由构建系统自动化的东西,例如使用Maven插件。 - Feuermurmel

3
对于使用Intellij Idea IDE的用户,FXMLManager插件可以帮助解决问题。请查看插件主页
当您在.fxml文件上点击鼠标右键时,会出现新的菜单项“从FXML更新控制器”。 单击此项将修改FXML Java控制器:
- 删除所有在FXML中缺失的@FXML字段及其getter/setter - 添加所有在控制器中缺失的@FXML字段 - @Deprecate 所有在FXML中缺失的ActionEvent方法 - 创建所有在控制器中缺失的ActionEvent方法

2

据我所知,NetBeans中存在两种解决方案。

首先是NetBeans内部功能“Make Controller”,您可以在fxml文档上右键单击以查看。它将生成一个控制器类,该类将与FXMLLoader一起使用。控制器的Java文件名应在fxml文档中指定。(左侧面板 -> 控制器 -> 控制器类)

Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

其次,NetBeans的插件“FXML 2 JAVA Converter”,您可以从菜单(工具-&gt;插件-&gt;可用插件-&gt;FXML 2 JAVA Converter)中安装。右键单击fxml文档,您将看到“生成抽象类”菜单项。它将从fxml文档生成源代码,并且您可以将其用作抽象类,而不使用FXMLoader,就像普通的JavaFX项目而不是JavaFXML项目一样。

嗨,我已经安装了插件,可以在插件窗口的“已安装”选项卡中看到它,但是当右键单击我的FXML文件时,我没有看到“生成抽象类”菜单项。 - mdnfiras

2

1
谢谢Hammad!!!它起作用了!但是你必须指定在打开fxml之前,直接在代码上右键单击(而不是在包资源管理器中),然后选择Source -> generate controller。 - rugby82
没错!!就是那样 - TheOriginX
这个解决方案是否会自动创建一个控制器类,还是我们需要在点击“生成控制器”之前单独创建控制器类并绑定FXML? - miKeL

2

如果您正在使用IntelliJ IDE,您可能需要尝试FXML Helper插件。
首先,在文件 | 设置... | 插件中安装插件。安装完成后重新启动IDE,现在右键单击.fxml文档,然后选择FXML Helper菜单。就这样。


1

@Feuermurmel
没有自动生成特定.fxml文件控制器类的方法。
您应该使用注释@fxml动态声明变量和方法,并在场景构建器中进行设置(绑定)。


你的意思是什么?能否提供一些示例照片? - miKeL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接