SceneBuilder不会加载我的自定义控件,该自定义控件通过FXML引用了另一个自定义控件 [英] SceneBuilder won't load my custom control which references another custom control via FXML

查看:53
本文介绍了SceneBuilder不会加载我的自定义控件,该自定义控件通过FXML引用了另一个自定义控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个基于FXML的自定义控件,该控件又引用了另一个基于FXML的自定义控件.当我将它们加载到eclipse中时,它们都可以正常工作,但是当我尝试将它们导入SceneBuilder时,外部控件(一个包含另一个)将无法正确导入.

I have created an FXML-based custom control, which in turn references another FXML-based custom control. They all work just fine when I load them in eclipse, but when I try to import them into SceneBuilder, the outer control (the one containing the other one) does not get imported properly.

这是一个大大简化的示例:

Here is a dramatically simplified example:

Widget.java:

Widget.java:

package example;

import java.util.logging.Level;
import java.util.logging.Logger;

import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;

public class Widget extends Pane{

    public Widget() {
        
        Logger logger = Logger.getLogger(Widget.class.getName());

        try {
            FXMLLoader loader= new FXMLLoader(Widget.class.getResource("Widget.fxml"));
            Pane pane = loader.load();
            this.getChildren().add(pane);
        }
        catch(Exception e) {
            logger.log(Level.SEVERE, "Failed to load Widget", e);
        }
    }
}

Widget.fxml:

Widget.fxml:

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

<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.control.Label?>
<?import example.SubWidget?>

<FlowPane  xmlns:fx="http://javafx.com/fxml/1" >
   <children>
       <Label text="Widget"/>
      <SubWidget></SubWidget>
   </children>
</FlowPane>

SubWidget.java:

SubWidget.java:

package example;

import java.util.logging.Level;
import java.util.logging.Logger;

import javafx.fxml.FXMLLoader;
import javafx.scene.layout.Pane;

public class SubWidget extends Pane{

    public SubWidget() {
        
        Logger logger = Logger.getLogger(SubWidget.class.getName());

        try {
            FXMLLoader loader= new FXMLLoader(SubWidget.class.getResource("SubWidget.fxml"));
            Pane pane = loader.load();
       
            this.getChildren().add(pane);
        }
        catch(Exception e) {
            logger.log(Level.SEVERE, "Failed to load SubWidget", e);
        }
    }
}

SubWidget.fxml:

SubWidget.fxml:

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

<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.control.Label?>

<FlowPane  xmlns:fx="http://javafx.com/fxml/1" >
   <children>
       <Label text="Subwidget"/>
   </children>
</FlowPane>

我将它们导出到jar中,并尝试通过SceneBuilder的jar导入功能将其导入.当我这样做时, SubWidget 被导入并且看起来还不错. Widget 也将显示为控件,但将完全为空.

I export these to a jar and attempt to import them via SceneBuilder's jar import functionality. When I do so, SubWidget gets imported and looks just fine. Widget will also show up as a control, but it will be completely empty.

当我检查日志文件时,我发现这是由于FXML加载程序无法找到SubWidget类文件所致:

When I check the log files I see that it is due to the FXML loader not being able to find the SubWidget class file:

Oct 29, 2020 4:28:30 PM example.Widget <init>
SEVERE: Failed to load Widget
javafx.fxml.LoadException: 
file:/C:/Users/nate/AppData/Roaming/Scene%20Builder/Library/TestFxControl.jar!/example/Widget.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2848)
    at javafx.fxml.FXMLLoader.processImport(FXMLLoader.java:2692)
    at javafx.fxml.FXMLLoader.processProcessingInstruction(FXMLLoader.java:2661)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2517)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2409)
    at example.Widget.<init>(Widget.java:27)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at java.lang.Class.newInstance(Unknown Source)
    at sun.reflect.misc.ReflectUtil.newInstance(Unknown Source)
    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.library.util.JarExplorer.instantiateWithFXMLLoader(JarExplorer.java:110)
    at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.exploreEntry(JarExplorer.java:160)
    at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.explore(JarExplorer.java:70)
    at com.oracle.javafx.scenebuilder.kit.library.user.LibraryFolderWatcher.exploreAndUpdateLibrary(LibraryFolderWatcher.java:325)
    at com.oracle.javafx.scenebuilder.kit.library.user.LibraryFolderWatcher.runDiscovery(LibraryFolderWatcher.java:138)
    at com.oracle.javafx.scenebuilder.kit.library.user.LibraryFolderWatcher.run(LibraryFolderWatcher.java:92)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: example.SubWidget
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2916)
    at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2905)
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2846)
    ... 24 more

在我看来,FXML加载器正在使用不包含其他自定义组件的类加载器,这很奇怪,因为如果我绕过了 Widget 类中的FXML并做到了:

It appears to me that the FXML loader is using a classloader which doesn't include other custom components, which is odd because if I bypassed the FXML in the Widget class and made it:

public class Widget extends FlowPane{

    public Widget() {
        
        this.getChildren().addAll(new Label("Widget"), new SubWidget());
    }
}

然后将其加载到SceneBuilder中就可以了.因此看来,实际上加载 Widget ClassLoader FXMLLoader 使用的是不相同的.

Then it loads just fine in SceneBuilder. So it appears that the ClassLoader that actually loads Widget and the one that the FXMLLoader uses are not the same.

这可能与这个未回答的问题有关.他们不是一回事.

This could possibly be related to this unanswered question, though they aren't exactly the same thing.

推荐答案

我遇到了同样的问题,并创建了一个虽然不漂亮但可行的解决方案.

I had the same issue and created a work around that is not pretty but works.

为无法加载到Scene Builder的控件创建一个包含空白类的jar,例如:

Create a jar that contains blank classes for the controls you can not load into Scene Builder, e.g:

package com.junglefinance.gui.controls;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class CategoryTextField extends TextField {
    @FXML private TextField textField;
    public CategoryTextField() {
    }
 }

确保程序包与目标控件的程序包匹配.

Make sure the package matches the package of your target control.

将此jar加载到Scene Builder中.这将使Scene Builder可以生成可以加载到程序中的FXML.加载后,它将选择您的目标控件,而不是导入时的虚拟控件(在这种情况下)

Load this jar into Scene Builder. This will allow Scene Builder to generate your FXML ready to load into your program. When it is loaded it will pick up your target control rather than the dummy as the import is (in this case)

<?import com.junglefinance.gui.controls.CategoryTextField?>

注意包装.

这篇关于SceneBuilder不会加载我的自定义控件,该自定义控件通过FXML引用了另一个自定义控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆