Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

javafx - Open FXML with SceneBuilder that uses a custom component with external library results in java.lang.ClassNotFoundException

Hi if I use a custom component in SceneBuilder that uses an external library in the constructor or the initialize method, I get an java.lang.ClassNotFoundException exception when try to open the FXML with JavaFX SceneBuilder 8.5.0.

I followed the instructions from here: https://docs.oracle.com/javafx/2/fxml_get_started/custom_control.htm. The custom component is part of my Eclipse project. I don't want to export it as an external jar file.

When I run this application in Eclipse everything works fine. The external library "FontAwesomeIcon" is part of my build path in Eclipse.

When I try to open the FXML of the custom component with SceneBuilder (with the Terminal to get debug logs), I get the following output and no file is loaded:

/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

Can someone explain the whole thing to me? I don't understand why SceneBuilder has to call the constructor or the initialize method. If I didn't understand the use of custom components in JavaFX and SceneBuilder correctly, what is the right way to do this?

Thanks for your help and greetings from Germany.

Following the content of my files...

Main class (Initializes the JavaFX application and opens the main window):

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();
    }
}

Test window class (Loads the test window FXML). This window uses the custom component:

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 of test window:

<?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>

Custom component class (Uses an external library "FontAwesomeIcon" that crashes SceneBuilder - corresponding line is bold):

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 of custom component:

<?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>

Update:

When I add the .jar file for the class "de/jensd/fx/glyphs/fontawesome/FontAwesomeIcon" to the "app.classpath" option in the SceneBuilder configuration file, the fxml opens without any exception.

Do I really need to add every external library to this setting?

question from:https://stackoverflow.com/questions/65646149/open-fxml-with-scenebuilder-that-uses-a-custom-component-with-external-library-r

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...