gpt4 book ai didi

java - 为什么 SceneBuilder 对自定义控件如此讲究?

转载 作者:太空宇宙 更新时间:2023-11-04 06:30:00 24 4
gpt4 key购买 nike

我希望有人能够向我解释为什么 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*/
}

然后这里就有了 Controller 类:

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 中时,它不起作用。它不存在于可导入控件列表中。

所以...我尝试了一些不同的东西。我尝试将 Controller 类嵌套在 Control 类中:

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*/
}
}

这也不起作用。我尝试了公共(public)、私有(private)、公共(public)静态、私有(private)静态,但都不起作用。

那么为什么会出现这种情况呢?为什么 SceneBuilder 无法识别自定义控件,除非 Control 类和 Controller 类是两个独立的实体?

编辑:

感谢下面的 James_D,我能够得到答案并使自定义控件按照我想要的方式工作。如果类的名称与 FXML 文件的名称相同,我还能够创建适用于所有自定义类的通用 Load 方法:

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();
}

只是想我会分享这一点。再次请注意,它仅在您的类名为 Hybrid 并且您的 FXML 文件名为 Hybrid.fxml 时才有效。

最佳答案

您的第二个(和第三个)版本根本无法工作(SceneBuilder 或没有 SceneBuilder),因为断言

this == loader.getController()

将会失败。当您调用 loader.load() 时,FXMLLoader 会看到 fx:controller="some.package.Hybrid"创建它的一个新实例。现在您有了 Hybrid 类的两个实例:一个在 FXMLLoader 上调用 load,另一个被设置为加载的 FXML 的 Controller 。

您需要从 FXML 文件中删除 fx:controller 属性,并直接在代码中设置 Controller ,如 documentation 中所示。 :

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 进行实验,它似乎会尝试通过调用无参数构造函数来创建自定义控件,并期望在不创建异常的情况下完成。在这种特定情况下,它似乎无法正确处理注入(inject) @FXML 带注释的值。我建议在 jira 提交错误为了这。

作为解决方法,您可能必须编写代码,以便即使未注入(inject) @FXML 注释字段,也能完成无参数构造函数的执行,而不会引发异常。 (是的,这很痛苦。)

关于java - 为什么 SceneBuilder 对自定义控件如此讲究?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26243900/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com