每个单元格的自定义单元格工具JavaFX

时间:2016-02-04 08:20:32

标签: java design-patterns javafx cell factory

我使用JavaFX几周后,花了很长时间来处理tableView& TreeTableView,我来找你更好地了解Cell Factory。

我的第一个问题涉及JavaFX中CellFactory的全局方法。

通常,工厂设计用于生成具有不同行为的不同对象。 但是,在JavaFX中,CellFactory似乎为整个列创建了相同类型的Cell ......

这种方法对工厂设计模式有何影响?

如果我想根据Cell的内容(值)改变Cell的行为,我就不能(就像我目前所见)。

所以我的第一个问题是(鼓声......):

如何根据单元格的内容为表格列中的每个单元格创建自定义单元格工厂?

1 个答案:

答案 0 :(得分:1)

  

这种方法对工厂设计模式有何影响?

是的。工厂模式的重点是允许使用它的类(TableView)创建遵循特定契约(TableCell)的类的实例,但隐藏其中的具体实现。

此页面图表中显示的工作流程:http://www.oodesign.com/factory-pattern.html

只需将Client替换为TableView,将Product替换为TableCell ...

这允许为cellFactorycellValueFactory设计可重用的类,而不必更改TableView / TableColumn的任何内容。 (只需看一下javafx.scene.control.cell package;那里的大多数(甚至所有)单元格都有一个静态方法来为它创建一个工厂类型;这些工作独立于TableView个项目,可以可以与PropertyValueFactory)一起使用。

  

如何根据单元格的内容为TableColumn中的每个Cell创建自定义Cell Factory?

你不是。您编写了一个表单元格,根据通过修改textgraphic属性等所传递的内容来决定它的布局。当项目更改时(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);
        }
    }

});