在JavaFX8中,有一个UI Controls Architecture用于制作自定义控件。基本上是基于:
此外,还有basic structure of an FXML project用于制作GUI。基本上:
我想将FXML与UI Controls Architecture一起使用,所以我的问题是:
谁是FXML文件的控制器?皮肤?
我必须做以下代码吗?:
public class MySkin extends SkinBase<MyControl> {
public GaugeSkin(MyControl control) {
super(control);
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("MyView.fxml"));
fxmlLoader.setRoot(control);
fxmlLoader.setController(control);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
答案 0 :(得分:4)
我认为你是在正确的轨道上,Skin
类是加载的FXML文件的控制器,因为Skin
负责定义构成'look'的节点一个特定的控制。
Control
类本身应该只定义保存控件状态的属性,而不应该关心Skin
实际创建视图层次结构的方式(也就是说,它应该只关心它的状态,而不是它的样子。)
我要做的一个区别是将fxmlloader.setController(control);
更改为fxmlloader.setController(this);
,以便Skin
类成为控制器而不是控件本身。
您可以做的另一件事是将FXMLLoader
逻辑移动到基类中,这样您每次要创建Skin
时都不必复制它,如下所示:< / p>
public abstract class FXMLSkin<C extends Control> extends SkinBase<C>{
public FXMLSkin(C control) {
super(control);
this.load();
}
private void load() {
FXMLLoader loader = new FXMLLoader(getFXML());
loader.setController(this);
try {
Node root = loader.load();
this.getChildren().add(root);
} catch (IOException ex) {
Logger.getLogger(FXMLSkin.class.getName()).log(Level.SEVERE, null, ex);
}
}
protected abstract URL getFXML();
}
我有一个JavaFX UserControl
on my Github页面,它与上面的FXMLSkinBase
类非常相似。它使用约定来加载与派生类同名的FXML文件,以便每次都不需要指定FXML文件名。 I.E.如果派生的皮肤被称为FooControlSkin
,控件将自动加载名为FooControlSkin.fxml
的FXML文件。
该类非常简单,代码可以很容易地重构为一个满足您要求的功能齐全的FXMLSkinBase
类。
答案 1 :(得分:0)
我更好的方法:
<fx:root>
作为.fxml文件的根元素。fxmlLoader.setRoot(control);
。fxmlLoader.setController(control);
。fx:controller="{controller class name}"
自动成为控制器。适当的Control类。
public static class ControlName extends Control {
@Override
protected Skin<?> createDefaultSkin() {
ControlNameSkin.Factory factory = new ControlNameSkin.Factory(this);
FXMLLoader fxmlLoader = new FXMLLoader(getClass()
.getResource("ControlName.fxml"));
fxmlLoader.setControllerFactory(factory);
try {
Node root = fxmlLoader.load();
ControlNameSkin skin = fxmlLoader.getController();
skin.construct(root);
return skin;
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
Skin和Controller的组合类。
public static class ControlNameSkin extends SkinBase<ControlName> {
public ControlNameSkin(Factory factory) {
super(factory.control);
// any setup NOT using FXML references
}
public void construct(Node root) {
ControlName control = getSkinnable();
// any setup using FXML references
getChildren().add(root);
}
public static class Factory implements Callback<Class<?>, Object> {
public final ControlName control;
public Factory(ControlName control) {
this.control = control;
}
@Override
public Object call(Class<?> cls) {
try {
return cls.getConstructor(Factory.class).newInstance(this);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
}