您好,如果我在 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 毫无例外地打开。
我真的需要将每个外部库添加到此设置吗?
我知道这个问题是 2 年前问的,但是...
如果您想首先在 SceneBuilder 中打开使用自定义组件的 FXML 文件,您必须使用选项
JAR/FXML Manager > Add Library/FXML from file system
加载自定义组件的 JAR 文件。然后浏览您的文件系统以找到 jar.
有关更多信息,请参阅这些参考资料: