【问题标题】:JavaFX PropertyGrid/EditorJavaFX PropertyGrid/编辑器
【发布时间】:2016-11-28 11:22:08
【问题描述】:

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

我猜property sheet 是为此而设计的,但我想使用 TreeTableView。主要是因为我有嵌套的属性,最终有几列。

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

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

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

欢迎提出任何建议!

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


更新1

我尝试实施@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);

我的问题出在需要返回 ObservableValue 的 cellValueFactory 上。鉴于我希望此列可编辑,我应该怎么做?

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

【问题讨论】:

    标签: javafx javafx-8 propertygrid treetableview


    【解决方案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 的类型和属性的名称来存储信息,即如果 beanname为该属性分配了属性:

    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);
    }
    
    public class EditorTreeTableCell<U, V> extends TreeTableCell<U, V> {
    
        public EditorTreeTableCell(Map<Class, Map<String, CellEditor<U, ?>>> editors) {
            this.editors = editors;
        }
    
        private CellEditor<U, V> editor;
        private final Map<Class, Map<String, CellEditor<U, ?>>> editors;
    
        @Override
        public void updateIndex(int i) {
            if (editor != null) {
                editor.removeItem(this);
                editor = null;
            }
            ObservableValue<V> observable = getTableColumn().getCellObservableValue(i);
            if (observable instanceof ReadOnlyProperty) {
                ReadOnlyProperty prop = (ReadOnlyProperty) observable;
                String name = prop.getName();
                Object bean = prop.getBean();
                if (name != null && bean != null) {
                     Class cl = bean.getClass();
                     while (editor == null  && cl != null) {
                         Map<String, CellEditor<U, ?>> map = editors.get(cl);
                         if (map != null) {
                              editor = (CellEditor) map.get(name);
                         }
                         cl = cl.getSuperclass();
                     }
                }
            }
    
            super.updateIndex(i);
        }
    
        public void updateItem(V item, boolean empty) {
            super.updateItem();
            if (editor == null) {
                 setGraphic(null);
                 setText(Objects.toString(item, ""));
            } else {
                 editor.assignItem(this, item);
            }
        }
    
    }
    

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

    【讨论】:

    • 感谢@fabian 快速详细的建议!我尝试了我们的第一个建议,但遇到了一些困难。我仍然缺少一些砖块!我用 sn-ps 更新了我的问题。
    • @Rascarcapac 在您的问题中,您需要ObjectProperty&lt;EditableItem&gt;一种或另一种方式:要么返回new SimpleObjectProperty(propertyItem.value()),要么修改value() 方法以返回ObjectProperty&lt;EditableItem&gt;。或者,您可以使用第二种方法并将name 初始化为name = new SimpleStringProperty(this, "name"); 并使用map.get(PropertyItem.class).get("name") 返回合适的CellEditor 的映射
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多