如何专门化 JavaFX 的组件并隐藏其 API 以仅显示我的
How to specialize a components of JavaFX and hide its API to only show mine
如标题中所述,我想专门介绍我将多次重复使用的 TableView 的用法,该规范包含:
- 已显示列
- 根据默认重复过滤器和一些附加过滤器(基于布尔值或回调)过滤添加的内容。
我使用原始 FXML 文件和控制器,没有 UI 拖放构建。
为了尽可能简单地使用我的组件,我想隐藏 JavaFX 的组件部分,只允许我的方法,该怎么做?
这是我发现的当前使用接口的方法,并在使用 @FXML
注入时使用该接口。
我的专业组件:
public class EquipmentTableView extends AnchorPane implements IEquipmentTableView{[...]}
其中AnchorPane
来自JavaFX
,界面来自我。
组件的 FXML :
<fx:root type="javafx.scene.layout.AnchorPane" xmlns:fx="http://javafx.com/fxml">
<TableView fx:id="tableView"
AnchorPane.topAnchor="0.0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
</TableView>
</fx:root>
要包含组件的 FXML :
<EquipmentTableView fx:id="tableView"/>
控制器中的注入
public class ReadController {
// use the interface here
@FXML private IEquipmentTableView tableView;
public static String FXML="read.fxml";
public static String TITLE_KEY="read.title";
@FXML
void initialize(){
tableView.addAll(Arrays.asList(
new Equipment("name1", "partNumber1", "MFC1", "00000000001", "3400000000000001"),
new Equipment("name2", "partNumber2", "MFC2", "00000000002", "3400000000000002"),
new Equipment("name3", "partNumber3", "MFC3", "00000000003", "3400000000000003")));
}
}
总结一下:
- 通过在组件内部使用
TableView
而不是继承它,我不允许操纵 TableView
。我改为继承 AnchorPane,因为我希望我的 table 视图自动调整大小,否则您可以从 Pane 继承。
- 因为我无法访问 TableView,所以我只能使用接口方法来操作它。
- 仅使用界面不允许我出于其他目的操纵 AnchorPane 或必须搜索我的方法。
创建一个 class 扩展 Control
。将您希望用户访问的方法添加到此 class.
为此创建一个皮肤 class 并实现您不希望用户在那里访问的行为。
好处:
- 对用户隐藏实施细节。
- 如果需要,允许用户替换 "private" 行为。
- 允许您直接从节点访问 "public" 行为。
例子
控制
public class MyControl extends Control {
@Override
protected Skin<?> createDefaultSkin() {
return new MyControlSkin(this);
}
private final StringProperty text = new SimpleStringProperty();
public final String getText() {
return this.text.get();
}
public final void setText(String value) {
this.text.set(value);
}
public final StringProperty textProperty() {
return this.text;
}
}
皮肤
public class MyControlSkin extends SkinBase<MyControl> {
public MyControlSkin(MyControl control) {
super(control);
Text text = new Text();
text.textProperty().bind(control.textProperty());
getChildren().setAll(text);
}
}
使用
@Override
public void start(Stage primaryStage) {
final MyControl control = new MyControl();
Button btn = new Button("Say 'Hello World'");
btn.setOnAction((ActionEvent event) -> {
control.setText("Hello World!");
});
Scene scene = new Scene(new VBox(10, btn, control));
primaryStage.setScene(scene);
primaryStage.show();
}
请注意,您如何创建 UI 并不重要。它可以直接从 java 创建或从 fxml 加载 - 这无关紧要。你可以例如使用皮肤作为 fxml 控制器和根:
<fx:root type="javafx.scene.control.SkinBase" xmlns:fx="http://javafx.com/fxml">
<children>
<Text fx:id="text"/>
</children>
</fx:root>
@FXML
private Text text;
public MyControlSkin(MyControl control) throws IOException {
super(control);
getChildren().clear();
FXMLLoader loader = new FXMLLoader(someUrl);
loader.setRoot(this);
loader.setController(this);
loader.load();
text.textProperty().bind(control.textProperty());
}
顺便说一句:恕我直言,重复过滤在单独的 class 中会更好,例如 TransformationList
。通过这种方式,您可以重用独立于 UI 的行为,这样可以更轻松地重用(例如,与 ListView
一起使用)。
如标题中所述,我想专门介绍我将多次重复使用的 TableView 的用法,该规范包含:
- 已显示列
- 根据默认重复过滤器和一些附加过滤器(基于布尔值或回调)过滤添加的内容。
我使用原始 FXML 文件和控制器,没有 UI 拖放构建。
为了尽可能简单地使用我的组件,我想隐藏 JavaFX 的组件部分,只允许我的方法,该怎么做?
这是我发现的当前使用接口的方法,并在使用 @FXML
注入时使用该接口。
我的专业组件:
public class EquipmentTableView extends AnchorPane implements IEquipmentTableView{[...]}
其中AnchorPane
来自JavaFX
,界面来自我。
组件的 FXML :
<fx:root type="javafx.scene.layout.AnchorPane" xmlns:fx="http://javafx.com/fxml">
<TableView fx:id="tableView"
AnchorPane.topAnchor="0.0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
</TableView>
</fx:root>
要包含组件的 FXML :
<EquipmentTableView fx:id="tableView"/>
控制器中的注入
public class ReadController {
// use the interface here
@FXML private IEquipmentTableView tableView;
public static String FXML="read.fxml";
public static String TITLE_KEY="read.title";
@FXML
void initialize(){
tableView.addAll(Arrays.asList(
new Equipment("name1", "partNumber1", "MFC1", "00000000001", "3400000000000001"),
new Equipment("name2", "partNumber2", "MFC2", "00000000002", "3400000000000002"),
new Equipment("name3", "partNumber3", "MFC3", "00000000003", "3400000000000003")));
}
}
总结一下:
- 通过在组件内部使用
TableView
而不是继承它,我不允许操纵TableView
。我改为继承 AnchorPane,因为我希望我的 table 视图自动调整大小,否则您可以从 Pane 继承。 - 因为我无法访问 TableView,所以我只能使用接口方法来操作它。
- 仅使用界面不允许我出于其他目的操纵 AnchorPane 或必须搜索我的方法。
创建一个 class 扩展 Control
。将您希望用户访问的方法添加到此 class.
为此创建一个皮肤 class 并实现您不希望用户在那里访问的行为。
好处:
- 对用户隐藏实施细节。
- 如果需要,允许用户替换 "private" 行为。
- 允许您直接从节点访问 "public" 行为。
例子
控制
public class MyControl extends Control {
@Override
protected Skin<?> createDefaultSkin() {
return new MyControlSkin(this);
}
private final StringProperty text = new SimpleStringProperty();
public final String getText() {
return this.text.get();
}
public final void setText(String value) {
this.text.set(value);
}
public final StringProperty textProperty() {
return this.text;
}
}
皮肤
public class MyControlSkin extends SkinBase<MyControl> {
public MyControlSkin(MyControl control) {
super(control);
Text text = new Text();
text.textProperty().bind(control.textProperty());
getChildren().setAll(text);
}
}
使用
@Override
public void start(Stage primaryStage) {
final MyControl control = new MyControl();
Button btn = new Button("Say 'Hello World'");
btn.setOnAction((ActionEvent event) -> {
control.setText("Hello World!");
});
Scene scene = new Scene(new VBox(10, btn, control));
primaryStage.setScene(scene);
primaryStage.show();
}
请注意,您如何创建 UI 并不重要。它可以直接从 java 创建或从 fxml 加载 - 这无关紧要。你可以例如使用皮肤作为 fxml 控制器和根:
<fx:root type="javafx.scene.control.SkinBase" xmlns:fx="http://javafx.com/fxml">
<children>
<Text fx:id="text"/>
</children>
</fx:root>
@FXML
private Text text;
public MyControlSkin(MyControl control) throws IOException {
super(control);
getChildren().clear();
FXMLLoader loader = new FXMLLoader(someUrl);
loader.setRoot(this);
loader.setController(this);
loader.load();
text.textProperty().bind(control.textProperty());
}
顺便说一句:恕我直言,重复过滤在单独的 class 中会更好,例如 TransformationList
。通过这种方式,您可以重用独立于 UI 的行为,这样可以更轻松地重用(例如,与 ListView
一起使用)。