JavaFX 8 兼容性问题 - FXML 静态字段或方法

21

我设计了一个JavaFX应用程序,在jdk 7中运行良好。但是当我尝试在Java 8中运行它时,出现以下异常:

javafx.fxml.LoadException: 
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2617)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2595)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3230)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3191)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3164)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3140)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3132)


Exception in thread "JavaFX Application Thread" java.lang.NullPointerException: Root cannot be null
    at javafx.scene.Scene.<init>(Scene.java:364)
    at javafx.scene.Scene.<init>(Scene.java:232)
        at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:204)
    at javafx.concurrent.EventHelper.fireEvent(EventHelper.java:219)
    at javafx.concurrent.Task.fireEvent(Task.java:1357)
    at javafx.concurrent.Task.setState(Task.java:720)
    at javafx.concurrent.Task$TaskCallable$2.run(Task.java:1438)
    at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
    at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
    at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
    at java.lang.Thread.run(Thread.java:744)

我发现问题的原因在于控制器类的初始化方法中,我无法在任何静态组件中使用内置方法。(例如:在Java 8中,staticMyTextField.setText()会导致问题,但在Java 7中不会)。我在JavaFX指南中没有找到任何关于此的文档记录。请问有人能提供一些关于为什么这会在Java 8中引起问题的想法吗?如果有相关文档,请分享。


你能提供一份代码示例吗? - Sergey Grinev
请参考此链接。这在JDK 7中可以工作,但在JDK 8中却不行。https://dev59.com/G2oy5IYBdhLWcg3wnPWJ....你能帮忙吗? - Christopher_Daniel
1个回答

40

听起来你正在尝试将一个TextField注入到静态字段中。就像这样:

@FXML
private static TextField myTextField ;

这在JavaFX 2.2中似乎有效,但在JavaFX 8中不起作用。由于没有官方文档支持此使用方法,因此它并不真正违反向后兼容性,尽管公平地说,关于FXMLLoader的具体功能的文档相当糟糕。

@FXML注入字段设置为静态实际上并没有多大意义。当您加载FXML文件时,它会为FXML文件中的每个元素创建新对象。每次调用FXMLLoader.load(...)时,都会关联一个新的控制器实例,并向该控制器实例注入与所创建的FXML元素相对应的对象。因此,被注入的字段必须特定于控制器实例。如果您在控制器中有一个静态注入字段,并且您两次加载相同的FXML文件并在UI中显示两次,则无法引用两组控件。


@FXML 标记的静态方法在 FXML 中也无法使用。

例如:

@FXML
private static void changeUser(ActionEvent e) {
    // System.out.println("test");
}

并且:

<Button text="Change User" onAction="#changeUser"/>

这将失败,并显示以下错误信息:
javafx.fxml.LoadException: Error resolving onAction='#changeUser', either the event handler is not in the Namespace or there is an error in the script.

为了解决这个问题,只需从方法规范中移除 static 修饰符即可。

更新: 回答评论中的问题

特别地,不要仅仅为了让它们可以从类外部访问而使用静态字段。静态字段具有属于类的单个值,而不是每个类实例的值,只有在这样做有意义时才应该决定将字段设置为静态。换句话说,static 定义了 作用域,而不是 可访问性。要允许访问实例数据,您只需要拥有对实例的引用。 FXMLLoader 有一个 getController() 方法,允许您检索对控制器的引用。

一个相关的观点:从控制器中暴露UI控件也不是一个好主意。相反,你应该暴露数据。例如,不要在控制器中定义一个getTextField()方法,而是定义一个textProperty()方法,返回一个表示TextField内容的StringProperty。原因是当你的老板来到办公室告诉你他想用TextAreaComboBox<String>或其他控件替换TextField时,如果控制器外部的类正在使用你的TextField,那么这将会更加困难。由控制器表示的数据结构比如何向用户呈现数据的实现更不可能改变。
以下是一些例子。

谢谢James。有没有办法从其他控制器类访问组件的内容?例如,我在一个控制器类中的listView中显示了一些内容(复选框和标签)。如果我想在另一个控制器类中访问它而不改变或修改其内容,我该怎么做? - Christopher_Daniel
+1 一个好的解释。我一直认为静态在这些情况下很有意义。你仍然可以像8b109那样晚期使用静态。这是我迄今看到的第五个关于这个问题的提问,但从未解释过“为什么不使用静态”。 - brian

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