Scene Builder中的自定义控件ClassNotFoundException

Mit*_*dge 6 java javafx classnotfoundexception scenebuilder

我通过扩展现有控件创建了一个新控件,我想在我的JavaFX场景中使用这个新控件.我希望能够使用Scene Builder编辑我的场景,但在将新控件添加到FXML文件后,我ClassNotFoundException在打开Scene Builder 时遇到了问题.

例如,这是我制作的一个类,它扩展了TextField:

RegexLimitingTextField.java

public class RegexLimitingTextField extends TextField {

    private String regexLimiter = ".*";

    public void setRegexLimiter(String regex) {
        this.regexLimiter = regex;
    }

    @Override
    public void replaceText(int start, int end, String text) {
        if (text.matches(regexLimiter))
            super.replaceText(start, end, text);
    }

    @Override
    public void replaceSelection(String replacement) {
        if (replacement.matches(regexLimiter))
            super.replaceSelection(replacement);
    }
}
Run Code Online (Sandbox Code Playgroud)

将此控件添加到我的FXML文件后...

sample.fxml

<?import javafx.scene.layout.GridPane?>
<?import sample.RegexLimitingTextField?>
<GridPane fx:controller="sample.Controller"
          xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
    <RegexLimitingTextField fx:id="textField" text="Test" />
</GridPane>
Run Code Online (Sandbox Code Playgroud)

...加载Scene Builder 2.0时出现此错误:

Caused by: java.lang.ClassNotFoundException: sample.RegexLimitingTextField
    at java.lang.ClassLoader.findClass(ClassLoader.java:530)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2920)
    at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2909)
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2850)
    ... 23 more
Run Code Online (Sandbox Code Playgroud)

为什么Scene Builder找不到我的新控件?我需要做什么才能找到并能够使用我的新控件?

如果需要,以下是其他文件:

Main.java

public class Main extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setScene(new Scene(root, 200, 200));
        primaryStage.show();
    }
}
Run Code Online (Sandbox Code Playgroud)

Controller.java

public class Controller implements Initializable {
    public RegexLimitingTextField textField;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        textField.setRegexLimiter("\\w*");
    }
}
Run Code Online (Sandbox Code Playgroud)

Bra*_*rek 6

如果仍然有人对SceneBuilder无法加载其自定义组件感到烦恼,只需传递ClassLoader即可为我解决问题。

try {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("CustomComponent.fxml"));
    loader.setRoot(this);
    loader.setController(this);
    loader.setClassLoader(getClass().getClassLoader());
    loader.load();
} catch (IOException e ){
    throw new RuntimeException(e);
}
Run Code Online (Sandbox Code Playgroud)

功劳归奇迹的工作者thatjavaguy


Flo*_*tej 6

所以......经过很多努力,我想我找到了解决办法。这个问题太愚蠢了,你不会相信。

此解决方案仅适用于已经尝试过所有方法并正确完成所有操作的人,例如:

  • 正如 Brad Turek 所说,在为自定义组件创建控制器时传递 ClassLoader。
  • 为您的 .fxml 使用 fx:root 构造

因此,如果自定义组件(.fxml 及其 java 控制器)位于以大写字母开头的包中,您似乎也会在 Scene Builder 中获得 ClassNotFoundException。似乎所有包名称到您的自定义组件都必须以小写字母开头。可以肯定的是......只需使用小写字母来命名所有包。我注意到的另一件事是控制器的类名也必须以大写字母开头。