JavaFX PropertyGrid / Editor

时间:2016-11-28 11:22:08

标签: javafx javafx-8 propertygrid treetableview

我正在尝试编写一个通常称为“属性编辑器”或“属性网格”的JavaFx组件。属性是名称 - 值对。

我想property sheet是为此做的,但我想使用TreeTableView。主要是因为我有嵌套属性,最后有几列。

右边的组件正是我试图实现的。 treetableview

我在TreeTableView中遇到的问题是,CellFactory中必须进行单元格自定义,这会导致项目类型的切换。这个解决方案使事情变得非常不灵活。

例如,如果必须通过TextField为给定属性更新字符串值,并通过ComboBox更新另一个属性,会发生什么?

任何建议都非常受欢迎!

相关问题:javafx-8-custom-listview-cells-its-evil

UPDATE1

我试图实施@ fabian的第一个建议。

我有我的豆子:

public class PropertyItem {

private StringProperty name = new SimpleStringProperty("");

private EditableItem value;
...
}

EditableItem的默认实现,用于在TextField中编辑字符串:

public class DefaultEditableItem implements EditableItem {

String value = "init value";
private TextField textField = new TextField();

public DefaultEditableItem(String value) {
    this.setValue(value);
}

// implementations of assignItem, removeItem, startEdit, cancelEdit,... as suggested for the cell behavior
}

我对TableView的实现:

PropertyItem rootProp = new PropertyItem("ROOT", new    DefaultEditableItem("test roots"));
TreeItem<PropertyItem> root = new TreeItem(rootProp);

// the name column is straightforward ...

// value column
TreeTableColumn<PropertyItem, EditableItem> valueColumn = new TreeTableColumn<>("VALUE");
valueColumn.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<PropertyItem, EditableItem>, ObservableValue<EditableItem>>() {
    @Override
    public ObservableValue<EditableItem> call(TreeTableColumn.CellDataFeatures<PropertyItem, EditableItem> cellData) {
            TreeItem<PropertyItem> treeItem = cellData.getValue();
            PropertyItem propertyItem = treeItem.getValue();
            // this will not compile...
            return propertyItem.value();                
    }
});

valueColumn.setCellFactory(new Callback<TreeTableColumn<PropertyItem, EditableItem>, TreeTableCell<PropertyItem, EditableItem>>() {
    @Override
    public TreeTableCell<PropertyItem, EditableItem> call(TreeTableColumn<PropertyItem, EditableItem> param) {
            return new EditingTreeTableCell();
    }
});
valueColumn.setOnEditCommit(...)

treeTableView.getColumns().addAll(nameColumn, valueColumn);
treeTableView.setEditable(true);

我的问题是在cellValueFactory上需要返回一个ObservableValue。鉴于我希望此专栏可编辑,我该怎么办?

我猜EditableItem必须扩展Property?但是,我的DefaultEditableItem可以扩展SimpleStringProperty吗?

1 个答案:

答案 0 :(得分:1)

您可以存储有关如何在项目本身中编辑项目的信息(直接或允许您使用项目中存储的合适密钥从地图或类似数据结构中检索项目)。

示例:

public interface EditableItem {

    /**
     * Modify cell ui the way updateItem would do it, when the item is
     * added to the cell
     */
    void assignItem(EditingTreeTableCell<?, ?> cell);

    /**
     * Modify cell ui to remove the item the way it would be done in the updateItem method
     */
    void removeItem(EditingTreeTableCell<?, ?> cell);
}
public class EditingTreeTableCell<U, V> extends TreeTableCell<U, V> {

    @Override
    public void updateItem(V item, boolean empty) {
        boolean cleared = false;
        V oldItem = getItem();
        if (oldItem instanceof EditableItem) {
            ((EditableItem) oldItem).removeItem(this);
            cleared = true;
        }

        super.updateItem(item, empty);

        if (empty) {
            if (!cleared) {
                 setText("");
                 setGraphic(null);
            }
        } else {
             if (item instanceof EditableItem) {
                 ((EditableItem) item).assignItem(this);
             } else {
                 setText(Objects.toString(item, ""));
                 // or other default initialistation
             }
        }

    }

}

但是,这会增加项目的大小,您还可以根据属性所在的bean的类型以及属性的名称来存储信息,即bean和{为属性分配了{1}}属性:

name
public interface CellEditor<U, V> {

    /**
     * Modify cell ui the way updateItem would do it, when the item is
     * added to the cell
     */
    void assignItem(EditorTreeTableCell<U, V> cell, V item);

    /**
     * Modify cell ui to remove the item the way it would be done in the updateItem method
     */
    void removeItem(EditorTreeTableCell<U, V> cell);
}

这将允许您根据对象所属的bean的对象名称和类型选择编辑器...