【发布时间】:2014-12-02 08:18:18
【问题描述】:
我希望有人能够准确地向我解释为什么 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 并实现 Initializable 的类:
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*/
}
}
这也不起作用。我试过公共的、私有的、公共的静态的、私有的静态的,它们都不起作用。
那么为什么会这样呢?为什么除非 Control 类和 Controller 类是两个独立的实体,否则 SceneBuilder 无法识别自定义控件?
编辑:
感谢下面的 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。
【问题讨论】:
标签: java class javafx scenebuilder