JavaFXPropertyGrid/Editor
我正在尝试编写一个JavaFx组件,它通常被称为“属性编辑器”或“属性网格”。作为名称-值对的属性 我想这是为这个设计的,但是我想使用TreeTableView。主要是因为我有嵌套的属性,最后还有几个列 右边的组件正是我想要实现的。 我在TreeTableView中遇到的问题是,单元格自定义必须在CellFactory中进行,这会导致打开项目类型。这个解决方案使事情变得非常不灵活 例如,如果字符串值必须通过给定属性的TextField和另一个属性的ComboBox进行更新,会发生什么情况 欢迎提出任何建议 有关问题:JavaFXPropertyGrid/Editor,javafx,javafx-8,propertygrid,treetableview,Javafx,Javafx 8,Propertygrid,Treetableview,我正在尝试编写一个JavaFx组件,它通常被称为“属性编辑器”或“属性网格”。作为名称-值对的属性 我想这是为这个设计的,但是我想使用TreeTableView。主要是因为我有嵌套的属性,最后还有几个列 右边的组件正是我想要实现的。 我在TreeTableView中遇到的问题是,单元格自定义必须在CellFactory中进行,这会导致打开项目类型。这个解决方案使事情变得非常不灵活 例如,如果字符串值必须通过给定属性的TextField和另一个属性的ComboBox进行更新,会发生什么情况 欢迎
更新1 我试图实施@fabian的第一个建议 我有我的豆子:
public class PropertyItem {
private StringProperty name = new SimpleStringProperty("");
private EditableItem value;
...
}
EditableItem的默认实现,用于编辑文本字段中的字符串:
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);
PropertyItem rootProp=newpropertyItem(“根”,newdefaulteditableItem(“测试根”);
TreeItem root=新的TreeItem(rootProp);
//名称列很简单。。。
//值列
TreeTableColumn valueColumn=新的TreeTableColumn(“值”);
valueColumn.setCellValueFactory(新回调(){
@凌驾
公共ObservableValue调用(TreeTableColumn.CellDataFeatures cellData){
TreeItem TreeItem=cellData.getValue();
PropertyItem PropertyItem=treeiItem.getValue();
//这不会编译。。。
返回propertyItem.value();
}
});
valueColumn.setCellFactory(新回调(){
@凌驾
公共TreeTableCell调用(TreeTableColumn参数){
返回新的EditingTreeTableCell();
}
});
valueColumn.setOnEditCommit(…)
treeTableView.getColumns().addAll(nameColumn,valueColumn);
treeTableView.setEditable(true);
我的问题是cellValueFactory,它需要返回一个可观察的值。如果我希望此列可编辑,我该怎么办
我猜EditableItem必须扩展属性?但是,我的DefaultEditableItem是否可以扩展SimpleStringProperty?您可以在项目本身中存储有关如何编辑项目的信息(直接或通过允许您使用项目中存储的合适键从映射或类似数据结构中检索项目) 例如:
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类EditorTreeTableCell扩展了TreeTableCell{
公共编辑器TreetableCell(地图编辑器){
this.editors=编辑器;
}
私人编辑;
私人最终地图编辑;
@凌驾
公共无效更新索引(int i){
如果(编辑器!=null){
编辑:removeItem(本);
编辑器=null;
}
ObservableValue observable=getTableColumn().getCellObservableValue(i);
if(只读属性的可观察实例){
ReadOnlyProperty属性=(ReadOnlyProperty)可观察;
字符串名称=prop.getName();
objectbean=prop.getBean();
if(name!=null&&bean!=null){
Class cl=bean.getClass();
while(编辑器==null&&cl!=null){
Map=editors.get(cl);
if(map!=null){
editor=(CellEditor)map.get(name);
}
cl=cl.getSuperclass();
}
}
}
超级更新索引(i);
}
public void updateItem(V项,布尔值为空){
super.updateItem();
如果(编辑器==null){
设置图形(空);
setText(Objects.toString(项“”);
}否则{
编者:分配项目(本,项目);
}
}
}
这将允许您根据对象名称和对象所属bean的类型选择编辑器…感谢@fabian提供的快速而详细的建议!我尝试了我们的第一个建议,但遇到了一些困难。我还是少了一些砖头!我用代码片段更新了我的问题。@Rascarcapac在你的问题中,你需要一个
ObjectProperty
:要么返回new SimpleObjectProperty(propertyItem.value())
,要么修改value()
方法以返回ObjectProperty
。或者,您可以使用第二种方法,将name
初始化为name=newsimplestringproperty(这个“名称”)
并使用映射,其中map.get(PropertyItem.class).get(“name”)
返回合适的CellEditor
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
}
}
}
}
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);
}
}
}