我从几周开始就使用JavaFX,在花了很长时间处理tableView和TreeTableView之后,我来找你对Cell Factory有了更好的了解。
我的第一个问题涉及 JavaFX 中 CellFactory 的全局方法。
通常,工厂被设计为生产具有不同行为的不同对象。但是,在JavaFX中,CellFactory似乎为整个列创建了相同类型的Cell...
这种方法尊重工厂设计模式的什么?
如果我想根据单元格的内容(值(更改单元格的行为,我不能(正如我到目前为止所看到的(。
所以我的第一个问题是(鼓声...
如何根据单元格的内容为表列中的每个单元格创建自定义单元格工厂?
这种方法尊重工厂设计模式的哪些方面?
是的,确实如此。工厂模式的全部意义在于允许使用它的类(TableView
(创建遵守某个契约(TableCell
(的类的实例,但隐藏了具体的实现。
此页面上的图表中显示的工作流:http://www.oodesign.com/factory-pattern.html
只需将Client
替换为TableView
,Product
替换为TableCell
...
这允许为cellFactory
和cellValueFactory
设计可重用的类,而无需更改任何扩展TableView
/TableColumn
。 (只需查看javafx.scene.control.cell
包;其中的大多数(甚至所有(单元格都有一个静态方法来为其类型创建工厂;这些工作独立于TableView
项目,可以一起使用,例如与PropertyValueFactory
(。
如何根据单元格的内容为表列中的每个单元格创建自定义单元格工厂?
你没有。您编写一个表格单元格,该单元格根据通过修改text
和graphic
属性等传递的内容来决定其布局。当项更改时(item
属性侦听器或updateItem
方法(。
通过显示使用默认构造函数创建的实例来显示类的单元格示例:
column1.setCellFactory(v -> new TableCell<Class<? extends Node>, Class<? extends Node>>() {
@Override
protected void updateItem(Class<? extends Node> item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
try {
setGraphic(item.getConstructor().newInstance());
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | InvocationTargetException ex) {
setGraphic(null);
}
}
}
});
这假设您可以决定给定项目值的布局。
如果你不能用这种方法设计干净的代码,请考虑将其与策略模式结合起来,即让你的项目决定TableCell
的布局:
@FunctionalInterface
public interface TableCellLayouter {
void layoutCell(TableCell<?, ?> cell);
}
// the content could be more complex of course
TableView<TableCellLayouter> tv = new TableView<>(FXCollections.observableArrayList(
cell -> {
cell.setText(null);
cell.setGraphic(new Rectangle(100, 100));
},
cell -> {
cell.setGraphic(null);
cell.setText("Hello world!");
},
cell -> {
cell.setGraphic(new Circle(20));
cell.setText("circle");
}));
TableColumn<TableCellLayouter, TableCellLayouter> column1 = new TableColumn<>("a");
column1.setCellValueFactory(c -> Bindings.createObjectBinding(() -> c.getValue()));
column1.setCellFactory(v -> new TableCell<TableCellLayouter, TableCellLayouter>() {
@Override
protected void updateItem(TableCellLayouter item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
setText(null);
} else {
item.layoutCell(this);
}
}
});