场景生成器中的自定义控件 ClassNotFoundException

Posted

技术标签:

【中文标题】场景生成器中的自定义控件 ClassNotFoundException【英文标题】:Custom Control ClassNotFoundException in Scene Builder 【发布时间】:2016-03-31 12:05:58 【问题描述】:

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

例如,这是我创建的一个扩展 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);
    

将此控件添加到我的 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>

...加载 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

为什么 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();
    

Controller.java

public class Controller implements Initializable 
    public RegexLimitingTextField textField;

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) 
        textField.setRegexLimiter("\\w*");
    

【问题讨论】:

可能是***.com/questions/30063792/…的副本 @James_D 成功了,谢谢。不过我有点生气。他们为什么要删除scenebuilder-classpath-element 标签?这似乎意味着每次我对我的课程进行更改时,我都必须重新构建 jar 并重新导入它。没有更简单的方法吗? 【参考方案1】:

如果有人仍然遇到 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);

归功于the miracle worker, thatjavaguy。

【讨论】:

我很遗憾听到这个消息,@SerhiiDikobrazko。至少还有 5 个人似乎不同意。【参考方案2】:

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

此解决方案仅适用于那些已经尝试过一切并且一切都正确的人,例如:

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

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

【讨论】:

【参考方案3】:

我还从扩展 TextField 的自定义组件中获得了很多乐趣,并导致 Scene Builder 在打开时冻结。

我添加到 Scene Builder 的 jar 文件只包含这一类。但是我的自定义组件引用了控制器——这就是重点。当我将两个类都导出到jar 时,一切都很好。

因此,如果您处于类似情况并正在寻找答案,请仔细查看依赖关系。没有 Scene Builder 的世界就不一样了。

【讨论】:

以上是关于场景生成器中的自定义控件 ClassNotFoundException的主要内容,如果未能解决你的问题,请参考以下文章

无法清除 OnPaint 方法中的自定义控件

我生成了一个换行的自定义Label控件,如何取得该行数啊??

Sharepoint webparts - 在 .designer.cs 文件中作为基本 UserControl 生成的自定义用户控件

Android中的自定义控件

ASP.NET C# 中的自定义控件

Android中的自定义视图控件