我希望有人能向我解释一下为什么SceneBuilder在导入自定义控件时如此温和。
以一个相对简单的自定义控件为例(仅作为示例):
public class HybridControl extends VBox{
final private Controller ctrlr;
public CustomComboBox(){
this.ctrlr = this.Load();
}
private Controller Load(){
final FXMLLoader loader = new FXMLLoader();
loader.setRoot(this);
loader.setClassLoader(this.getClass().getClassLoader());
loader.setLocation(this.getClass().getResource("Hybrid.fxml"));
try{
final Object root = loader.load();
assert root == this;
} catch (IOException ex){
throw new IllegalStateException(ex);
}
final Controller ctrlr = loader.getController();
assert ctrlr != null;
return ctrlr;
}
/*Custom Stuff Here*/
}
然后你有控制器类在这里:
public class Controller implements Initializable{
/*FXML Variables Here*/
@Override public void initialize(URL location, ResourceBundle resources){
/*Initialization Stuff Here*/
}
}
这工作得很好。.jar编译得很好,SceneBuilder读取的.jar很好,它导入的控件也很好,这很好。
让我恼火的是,它需要两个独立的类来完成,这没什么大不了的,除了我觉得只用一个类就可以做到这一点。
我现在有了上面的方法,但是我尝试了另外两种方法都失败了(SceneBuilder不会找到并让我导入控件),我希望有人能告诉我为什么,这样我才能继续我的生活。
在第二种情况下,我尝试了一个扩展VBox并实现初始化的类:
public class Hybrid extends VBox implements Initializable{ /*In this case the FXML file Controller would be set to this class.*/
/*FXML Variables Here*/
public Hybrid(){
this.Load();
}
private void Load(){
final FXMLLoader loader = new FXMLLoader();
loader.setRoot(this);
loader.setClassLoader(this.getClass().getClassLoader());
loader.setLocation(this.getClass().getResource("Hybrid.fxml"));
try{
final Object root = loader.load();
assert root == this;
} catch (IOException ex){
throw new IllegalStateException(ex);
}
assert this == loader.getController();
}
@Override public void initialize(URL location, ResourceBundle resources){
/*Initialization Stuff Here*/
}
}
这对我来说非常有意义。它应该工作,至少在我的脑海中是这样,但它没有。jar可以很好地编译,我甚至敢打赌它在程序中可以很好地工作,但是当我尝试将. jar导入Scene Builder时,它不起作用。它不存在于可导入控件的列表中。
所以…我尝试了不同的方法。我尝试在Control类中嵌套Controller类:
public class Hybrid extends VBox{ /*In this case the FXML Controller I had set to Package.Hybrid.Controller*/
final private Controller ctrlr
public Hybrid(){
this.ctrlr = this.Load();
}
private Controller Load(){
/*Load Code*/
}
public class Controller implements Initializable{
/*Controller Code*/
}
}
这个也不行,我试了一下公的,私的,公静态,私静态,都不行
那么为什么会这样呢?为什么SceneBuilder无法识别自定义控件,除非Control类和Controller类是两个独立的实体?
感谢下面的James_D,我能够得到一个答案,并使自定义控件以我想要的方式工作。我还能够创建一个通用的Load方法,如果类的名称与FXML文件的名称相同,该方法适用于所有自定义类:
private void Load(){
final FXMLLoader loader = new FXMLLoader();
String[] classes = this.getClass().getTypeName().split("\\.");
String loc = classes[classes.length - 1] + ".fxml";
loader.setRoot(this);
loader.setController(this);
loader.setClassLoader(this.getClass().getClassLoader());
loader.setLocation(this.getClass().getResource(loc));
try{
final Object root = loader.load();
assert root == this;
} catch (IOException ex){
throw new IllegalStateException(ex);
}
assert this == loader.getController();
}
我只是想分享一下。请再次注意,它只在以下情况下有效,例如,您的类名为混合,而您的FXML文件名为Hybrid.fxml.
您的第二个(和第三个)版本根本无法工作(SceneBuilder或没有SceneBuildr),因为断言
this == loader.getController()
将失败。当您调用加载器.load()
时,FXMLLoader
会看到 fx:控制器=“一些.包.混合”
,并创建它的新实例。因此,现在您有两个混合
类的实例:一个在 FXMLLoader
上调用 load
,另一个被设置为已加载 FXML 的控制器。
您需要从 FXML 文件中删除 fx:控制器
属性,并直接在代码中设置控制器,如文档所示:
private void Load(){
final FXMLLoader loader = new FXMLLoader();
loader.setRoot(this);
loader.setClassLoader(this.getClass().getClassLoader());
loader.setLocation(this.getClass().getResource("Hybrid.fxml"));
// add this line, and remove the fx:controller attribute from the fxml file:
loader.setController(this);
try{
final Object root = loader.load();
assert root == this;
} catch (IOException ex){
throw new IllegalStateException(ex);
}
assert this == loader.getController();
}
尝试使用 SceneBuilder,它似乎将尝试通过调用其无参数构造函数来创建自定义控件,并期望在不创建异常的情况下完成此操作。在此特定方案中,它似乎无法正确处理注入@FXML
带注释的值。我建议为此在jira上提交一个错误。
作为一种解决方法,您可能必须编写代码,以便即使未注入@FXML
注释字段,也可以完成执行无参数构造函数而不会引发异常。(是的,这是一种痛苦。
> 我是使用fx:root,还是不使用它?我选择用它。所以在控件的controller+root类中,我将自己设置为root和controller,就像需要的那样。但它仍然说“root尚未设置。在加载之前使用setRoot()方法。” 在包含自定义控件的父FXML中,我应该导入什么? 正确的类路径是什么,以便我可以在SceneBuilder2.0中显示我的自定义控件?我根本不太明白“/.../..
我有一个自定义JavaFx控件,它在我的应用程序中呈现。但是,我无法让SceneBuilder理解它。 我有customTextField.java/customTextField.CustomTextField继承自UserControl,如这里所定义的,但我创建的任何自定义控件都会出现场景生成器问题。 首先,我必须将import语句更改为通配符。从 sample.fxml:
我跟随这个博客向Scene Builder 2.0添加了一个自定义JavaFX组件,并构建了自己的自定义组件。 FXML文件: 控制器类: 样式表: 现在我的问题是我不能改变场景生成器中标签的值。我们是否可以创建一个自定义字段,该字段将出现在场景生成器上,并有助于更改标签文本?
每隔一段时间,我就会犯这样的错误 2020-02-26 14:17:31.605963:I tensorflow/stream_执行器/平台/默认/dso_加载器。cc:42]已成功打开动态库libcublas。所以10.0 2020-02-26 14:17:31.829898:I tensorflow/流执行器/平台/默认/dso装载器。cc:42]已成功打开动态库libcudnn。所以7 20
我需要在窗格上有一个选择监听器和选择方法,以便在单击节点时能够监视并显示突出显示。 我做了以下操作: 这工作得很好 - 但是我无法再使用场景构建器,因为我的FXML引用了此而不是。我不确定如何将我的自定义窗格放入场景构建器。我已经看过其他问题,它们都是FXML和控制器的组合 - 这只是一个。 有没有人知道这样做的方法,或者在初始化时将< code>Pane换成< code > PaneWithSe
自定义控件用JavaScript和原生平台支持的语言编写。它们使用原生Tabris.js客户端的接口,并被封装在Cordova插件中。本文将介绍JavaScript的实现部分。 用JavaScript定义自定义控件 自定义控件必须继承自Widget。它能够与自定义控件的原生部分进行通信。 自定义控件类必须覆写_nativeType属性的getter以返回与原生实现匹配的类型: class MyCu