Open FXML with SceneBuilder 使用带有外部库的自定义组件导致 java.lang.ClassNotFoundException

问题描述 投票:0回答:1

您好,如果我在 SceneBuilder 中使用自定义组件,该组件在构造函数或初始化方法中使用外部库,当我尝试使用 JavaFX SceneBuilder 8.5.0 打开 FXML 时,会出现 java.lang.ClassNotFoundException 异常。

我按照这里的说明进行操作:https://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm。 自定义组件是我的 Eclipse 项目的一部分。我不想将其导出为外部 jar 文件。

当我在 Eclipse 中运行这个应用程序时,一切正常。外部库“FontAwesomeIcon”是我在 Eclipse 中构建路径的一部分。

当我尝试使用 SceneBuilder(使用终端获取调试日志)打开自定义组件的 FXML 时,我得到以下输出并且没有加载任何文件:

/Applications/SceneBuilder.app/Contents/MacOS/SceneBuilder /Users/phillip/MEGA/Eclipse/JTunes/src/test/TestWindow.fxml

Jan 09, 2021 6:31:44 PM com.oracle.javafx.scenebuilder.app.SceneBuilderApp logTimestamp
INFORMATION: JavaFX Scene Builder started
TestComponent()
TestComponent: Init
Jan 09, 2021 6:31:45 PM com.oracle.javafx.scenebuilder.app.SceneBuilderApp$SceneBuilderUncaughtExceptionHandler uncaughtException
SCHWERWIEGEND: An exception was thrown:
java.lang.NoClassDefFoundError: de/jensd/fx/glyphs/fontawesome/FontAwesomeIcon
    at test.TestComponent.initialize(TestComponent.java:28)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
    at test.TestComponent.<init>(TestComponent.java:22)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at sun.reflect.misc.ReflectUtil.newInstance(ReflectUtil.java:51)
    at javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1009)
    at javafx.fxml.FXMLLoader$ValueElement.processStartElement(FXMLLoader.java:746)
    at javafx.fxml.FXMLLoader.processStartElement(FXMLLoader.java:2707)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2527)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425)
    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMLoader.load(FXOMLoader.java:93)
    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.<init>(FXOMDocument.java:89)
    at com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument.<init>(FXOMDocument.java:106)
    at com.oracle.javafx.scenebuilder.kit.editor.EditorController.updateFxomDocument(EditorController.java:2540)
    at com.oracle.javafx.scenebuilder.kit.editor.EditorController.setFxmlTextAndLocation(EditorController.java:761)
    at com.oracle.javafx.scenebuilder.app.DocumentWindowController.loadFromFile(DocumentWindowController.java:385)
    at com.oracle.javafx.scenebuilder.app.SceneBuilderApp.performOpenFiles(SceneBuilderApp.java:672)
    at com.oracle.javafx.scenebuilder.app.SceneBuilderApp.access$100(SceneBuilderApp.java:98)
    at com.oracle.javafx.scenebuilder.app.SceneBuilderApp$1.invalidated(SceneBuilderApp.java:524)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyBooleanPropertyBase.fireValueChangedEvent(ReadOnlyBooleanPropertyBase.java:72)
    at javafx.beans.property.ReadOnlyBooleanWrapper.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:103)
    at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
    at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
    at com.oracle.javafx.scenebuilder.kit.library.user.UserLibrary.lambda$updateFirstExplorationCompleted$6(UserLibrary.java:352)
    at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
Caused by: java.lang.ClassNotFoundException: de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 36 more

Jan 09, 2021 6:31:46 PM com.oracle.javafx.scenebuilder.app.SceneBuilderApp logTimestamp
INFORMATION: JavaFX Scene Builder stopped

有人能给我解释一下吗?我不明白为什么 SceneBuilder 必须调用构造函数或初始化方法。 如果我没有正确理解 JavaFX 和 SceneBuilder 中自定义组件的使用,那么正确的做法是什么?

感谢德国的帮助和问候

按照我的文件内容...

主类(初始化JavaFX应用程序并打开主窗口):

package test;

import javafx.application.Application;
import javafx.stage.Stage;

public class Main extends Application {
    
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage = new TestWindow();
        primaryStage.show();
    }
}

测试窗口类(加载测试窗口 FXML)。此窗口使用自定义组件:

package test;

import java.io.IOException;

import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class TestWindow extends Stage {
    
    public TestWindow() throws IOException {
        System.out.println("TestWindow()");
        
        FXMLLoader loader = new FXMLLoader();
        loader.setController(this);
        loader.setLocation(this.getClass().getResource("TestWindow.fxml"));
        Parent root = loader.load();
        
        Scene scene = new Scene(root);
        this.setScene(scene);
    }
}

测试窗口的FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.VBox?>
<?import test.TestComponent?>

<VBox alignment="CENTER" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <TestComponent />
   </children>
</VBox>

自定义组件类(使用使 SceneBuilder 崩溃的外部库“FontAwesomeIcon”——对应的行为粗体):

package test;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.layout.VBox;

public class TestComponent extends VBox implements Initializable {
    
    public TestComponent() throws IOException {
        System.out.println("TestComponent()");
        
        FXMLLoader loader = new FXMLLoader();
        loader.setController(this);
        loader.setRoot(this);
        loader.setLocation(this.getClass().getResource("TestComponent.fxml"));
        loader.load();
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        System.out.println("TestComponent: Init");
        System.out.println("TestComponent: "+FontAwesomeIcon.ADJUST);
    }
    
    @FXML
    private void click() {
        System.out.println("Click");
    }
}

自定义组件的FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<fx:root alignment="CENTER" type="VBox" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Label text="TestComponent" />
      <Button onMouseClicked="#click" text="Button" />
   </children>
</fx:root>

更新:

当我将“de/jensd/fx/glyphs/fontawesome/FontAwesomeIcon”类的 .jar 文件添加到 SceneBuilder 配置文件中的“app.classpath”选项时,fxml 毫无例外地打开。

我真的需要将每个外部库添加到此设置吗?

javafx noclassdeffounderror classnotfoundexception scenebuilder custom-component
1个回答
0
投票

我知道这个问题是 2 年前问的,但是...

如果您想首先在 SceneBuilder 中打开使用自定义组件的 FXML 文件,您必须使用选项

JAR/FXML Manager > Add Library/FXML from file system
加载自定义组件的 JAR 文件。然后浏览您的文件系统以找到 jar.

有关更多信息,请参阅这些参考资料:

© www.soinside.com 2019 - 2024. All rights reserved.