Scene Builder嵌套自定义节点 [英] Scene Builder Nested Custom Nodes

查看:159
本文介绍了Scene Builder嵌套自定义节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎在Scene Builder 8.4.1中遇到了一个非常严重的错误,其他人之前遇到过不同版本的错误(参见 this link)。问题在于,当我尝试导入自定义节点时,该节点又包含jar文件中的其他自定义节点,只能找到嵌套节点。也就是说,找不到外部节点。

I seem to have come across a pretty severe bug in Scene Builder 8.4.1 that other people have come across before for different versions (see this link). The bug is that when I try to import a custom node that in turn contains other custom nodes from a jar file only the nested nodes are found. That is, the outer node is not found.

所以我在想。有没有人知道一个稳定版本的Scene Builder没有这个bug(最好没有其他严重的版本)用于更新版本的java(如果它还没出现,那么8,9或10)?我还希望有一个安装向导,它将为我提供一个exe应用程序,而不是一个可运行的jar,以便更好地与我的IDE集成。如果这不存在,那么您对Scene Builder的更多经验是什么让我推荐的呢?我应该在没有嵌套节点的情况下制作所有fxml文档,并在以后手动添加它们吗?

So I was wondering. Does anyone know of a stable release of Scene Builder that does not have this bug (and preferably no other severe ones) for a more recent version of java (8, 9 or maybe 10 if it is out yet)? I would also like there to be an install wizard which will give me an exe application instead of a runnable jar for better integration with my IDE. If this does not exist what do you more Scene Builder experienced people recommend that I do? Should I make all my fxml documents without the nested nodes and add them in later manually?

感谢您的帮助!

编辑:可以找到所有源文件这里。请注意,外部容器是SliderVariable,内部是InfoIcon。

All source files can be found here. Note that the outer container is the SliderVariable and the inner is the InfoIcon.

推荐答案

您可以在其中嵌套两个或更多自定义控件同样的jar,从你的IDE或命令行运行就好了。

You can nest two or more custom controls in the same jar, and that will run just fine from your IDE or from command line.

但是如果你从Scene Builder导入那个jar,一些自定义控件可能会失败如果他们依赖其他人就会被导入。

But if you import that jar from Scene Builder, some of the custom control might fail to be imported if they have a dependency on the others.

这是有原因的,最好的部分是,还有一个简单的解决方案。

There is a reason for this, and the best part, there is an easy solution as well.

如何导入自定义控件?

如果你看一下Scene Builder的源代码,要导入jar的可能自定义控件,有一个 JarExplorer class,有探索 方法

If you have a look at Scene Builder's source code, to import the possible custom controls of a jar, there is a JarExplorer class, that has an explore method.

这个方法基本上会遍历jar中的每个类,找出该类是否是应该添加到用户库中的可能自定义组件。

This method basically will go through every class in the jar, finding out if that class is a possible custom component that should be added to the user's library.

最后,它是如何工作的,是尝试基于该类创建FXML对象: / p>

At the end, how this works, is by trying to create an FXML object based on that class:

 entryClass = classLoader.loadClass(className);
 instantiateWithFXMLLoader(entryClass, classLoader);

如果成功,则将该类添加到组件集合中。

If that succeeds, the class is added to the components collection.

为什么嵌套的自定义控件无法导入?

那么为什么是嵌套的自定义控件,这是一个控件有另一个自定义控件作为依赖项,无法导入?可以找到调试Scene Builder的原因,并打印出你得到的异常:

So why a nested custom control, which is a control that has another custom control as a dependency, fails to be imported? The reason for this can be found debugging Scene Builder, and printing out the exception you get:

try {
    instantiateWithFXMLLoader(entryClass, classLoader);
} catch (RuntimeException | IOException x) {
    status = JarReportEntry.Status.CANNOT_INSTANTIATE;
    x.printStackTrace(); // <-- print exception
} catch (Error | ClassNotFoundException x) {
    status = JarReportEntry.Status.CANNOT_LOAD;
    x.printStackTrace(); // <-- print exception
}

记录这个对你来说真有帮助创建任何类型的自定义控件。

Logging this is really helpful when you are creating any type of custom control.

在嵌套自定义控件的情况下,如果依赖项已在类路径中可用,并且通过类路径我的意思是所有由Scene Builder预先加载的依赖项,不会有问题。但如果它不可用,FXMLLoader将无法创建此控件的有效实例。

In the case of a nested custom control, if the dependency is already available in the class path, and by class path I mean all the dependencies loaded by Scene Builder in advance, there won't be a problem. But if it is not available, the FXMLLoader will fail to create a valid instance of this control.

让我们试试你的 SliderVariable 控制。如果你打印出异常,你会看到如下内容:

Let's try your SliderVariable control. If you print out the exception, you'll see something like this:

javafx.fxml.LoadException: 
    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2425)
    at com.oracle.javafx.scenebuilder.kit.library.util.JarExplorer.instantiateWithFXMLLoader(JarExplorer.java:110)
... 9 more

Caused by: java.lang.RuntimeException: javafx.fxml.LoadException: 
    file:.../SliderVariable-1.0-SNAPSHOT-shaded!/com/coolcompany/slidervariable/SliderVariable.fxml
...
Caused by: java.lang.ClassNotFoundException: com.coolcompany.infoicon.InfoIcon
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at javafx.fxml.FXMLLoader.loadTypeForPackage(FXMLLoader.java:2916)
    at javafx.fxml.FXMLLoader.loadType(FXMLLoader.java:2905)
    at javafx.fxml.FXMLLoader.importClass(FXMLLoader.java:2846)
... 26 more

所以基本上这解释了为什么没有导入嵌套控件:内部控件事先在类路径中不可用。

So basically this explains why the nested control is not imported: the inner control wasn't available in the class path in advance.

可能的解决方案

显然你可以单独捆绑两个控件,首先导入 InfoIcon 控件,然后只导入 SliderVariable 控制。但如果您想在单个依赖项中分发这些控件,则可能会出现问题。

Obviously you could bundle separately both controls, import first the InfoIcon control, and then just import the SliderVariable control. But this could be problematic if you want to distribute these controls in a single dependency.

最佳解决方案

那么如果两者都在同一个jar中,我们如何在运行时将内部控件提供给外部控件呢?

So how do we make available the inner control to the outer one in runtime if both are in the same jar?

这是通过将此外部控件类的类加载器传递给 FXMLLoader 来完成的。这可以在外部控件中调用 FXMLLoader :: setClassLoader 方法完成。

This is done by passing the classloader of this outer control class to the FXMLLoader. And this can be done calling the FXMLLoader::setClassLoader method in the outer control.

在你的情况下:

FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("SliderVariable.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);

// set FXMLLoader's classloader!
fxmlLoader.setClassLoader(getClass().getClassLoader());

try {
    fxmlLoader.load();
} catch (IOException exception) { }

如果你再试一次,你会得到两个控件可用作自定义组件。

If you try again, you will get both controls available as custom components.

< img src =https://i.stack.imgur.com/eztJp.pngalt =导入嵌套控件>

这篇关于Scene Builder嵌套自定义节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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