【问题标题】:JavaFX 2.2 Controller initialize() not called when being loaded within JAR file在 JAR 文件中加载时未调用 JavaFX 2.2 控制器初始化()
【发布时间】:2013-01-31 17:50:48
【问题描述】:

背景:我创建了一个 JavaFX 应用程序,使用 JFXPanel 嵌入到 Swing 框架中。我一直在使用 Eclipse 作为 IDE。 “主应用程序”是另一个类,它仅用于创建一个类的实例,该类扩展 JFXPanel 以在实例化时加载我的 .fxml 文件。从 Eclipse 执行主类时,一切都很好,我的 .fxml 文件中指定的 fx:controller 调用了它的 initialize() 方法(我可以从它在加载时对 UI 所做的更改中看出)并且没有问题。

但是,当我将所有内容打包到 JAR 中并尝试将我的 JFXPanel 扩展类添加到 Swing JFrame 实例时,它会设法加载 .fxml 文件,只是读取图像、样式表等以及其余部分的代码按预期运行,但永远不会调用 fx:controllerinitialize() 方法。我从 jar 内部或外部的其他类访问该类没有问题,我什至尝试设置一个 ControllerFactory,它将返回一个 Controller 的实例,并尝试设置 FXMLLoader 的类加载器的各种组合并使用调用load() 的静态和非静态方法。结果总是一样的:从 IDE 启动时它会起作用,但从我打包的 jar 启动时不起作用。我知道 jar 没有丢失任何文件,因为就像我说的那样,从 Java 代码中找到类没有问题,并且捆绑的 fxml/css 文件似乎加载正常,减去控制器问​​题。

有人曾经遇到过这种情况,或者知道FXMLLoader 未能设置控制器会发生什么吗?这可能是某种错误吗?

【问题讨论】:

  • 你的jar是如何部署的?对于 JavaFX 2.2,由于 FXML 使用反射,FXML 目前不能在未签名的 webstart 或小程序中工作。我还相信,由于 OSGI 类加载的管理方式(尽管我从未尝试过),可能需要进行一些调整才能使 JavaFX 2.2 FXML 应用程序在 OSGI 环境中工作。您的 Jar 应使用 JavaFX 部署工具打包,否则可能找不到正确的运行时。也许其中一件事是你的问题。

标签: java javafx-2 javafx


【解决方案1】:

在将我的 JavaFX 软件打包成 .jar 文件时,我遇到了类似的问题。原来这是关于相对路径的问题。您的 IDE 对此没有任何问题,但是在 jar 中编译时会出现问题。

使用以下代码调用我的 .fxml 文件解决了这个问题。

getClass().getClassloader().getResource("/my/view/selector.fxml")

要说这是你的错误的“原因”,我不确定,但这确实让我难过一段时间,似乎是我遇到的问题。

原问题:Executable Jar limited to one window with JavaFX

【讨论】:

  • 问题不在于找到 fxml 文件或 jar 中的任何内容,问题在于加载 fxml 后未调用控制器类的初始化方法。 fxml 文件本身(和 css)被找到并加载得很好。由于我只需要它来获取对 fxml 中组件的引用以进行进一步编码,因此我选择创建一个“按 id 查找小部件”递归搜索方法以在场景的根目录上运行以根据它们的 fxml 查找各种组件id。
  • 我没有 100% 关注,但我认为如果你用你所做的(显示一些代码)回答这个问题会很好。这可能对查找此内容的其他人有所帮助。
【解决方案2】:

我无法解决这个问题。虽然 fxml/css 文件加载正常并引用了正确的控制器类,但我仍然无法看到控制器类的 initialize() 方法在所有内容打包到 jar 后被调用。

由于我需要控制器的唯一目的是获取 fxml 文件中定义的各种 UI 对象,以便我可以对它们进行真正的编程,因此我选择创建一个递归搜索来查找这些单独的小部件他们的 fxml ID [似乎先查找 'id' 然后查找 'fx:id' 如果没有找到 'id'] 在场景树中..

//grabs fxml file relative to root of the jar
FXMLLoader loader = new FXMLLoader(ClassLoader.getSystemClassLoader().getResource("app.fxml"));
Parent javaFXRoot = (Parent) loader.load();

public Node findWidgetByID(String id, Parent javaFXRoot)
{
    return findObject(root, id);
}

private Node findObject(Parent root, String id)
{
    for (Node node : root.getChildrenUnmodifiable())
    {
        if (node.getId() != null && node.getId().equals(id))
        {
            return node; // found the node, return it
        }
        Node retValue = null;
        if (node instanceof Parent)
        {
            retValue = findObject(((Parent) node), id); // recursive search
        }
        if (retValue != null) //if our node was found by the recursive search, return that
        {
            return retValue;
        }
    }
    return null;
}

【讨论】:

    【解决方案3】:

    我遇到了同样的问题,即从 IDE 调用 initialize() 方法,但不是从(阴影)jar 调用。

    问题是我们使用了配置为保留protectedpublic 方法的ProGuard。但是,initialize() 方法被声明为private。因此它混淆了方法名称,JavaFX 找不到任何适当命名的方法,并且从未调用过 initialize()

    要阻止 ProGuard 混淆您的 JavaFX 注释方法和字段,请将此规则包含在您的 proguard.conf 中:

    -keepattributes javafx.fxml.FXML
    
    -keepclassmembers class * {
        @javafx.fxml.FXML *;
    }
    

    第一行将保留@FXML 注释,另一条规则保留@FXML 注释的类成员名称。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-18
      • 2019-12-03
      • 1970-01-01
      • 1970-01-01
      • 2016-11-02
      • 1970-01-01
      相关资源
      最近更新 更多