我试图用JvafaFX创建一个表格视图,它将显示一个摄像机参数列表。其中一些参数是可编辑的,有些则不可编辑,有些参数受限于其他值为自由文本输入的值列表。我已设置表以在键,值类型显示中显示参数,其中一列用于参数名称,另一列用于值。
使用从背景数据模型生成的可观察列表设置表的值:
propertyNamesColumn.setCellValueFactory(cellData -> cellData.getValue().getName());
propertyValuesColumn.setCellValueFactory(cellData -> cellData.getValue().getValue());
该模型还包含属性是否应该是可编辑的以及它可能包含的可能值,这些值当前存储在两个不同的字段中(我不确定这是否是最佳方式)因此有4个字段总。
设置表格的行时,我想制作那些应该可编辑的行(根据模型中的值),可以通过包含可能值列表中的值或文本字段的选项框进行编辑。
但是我不确定我需要实现什么才能实现这一点,我尝试扩展ChoiceBoxTableCell类以添加此逻辑,但表格单元格甚至永远不会变得可编辑。
我非常确定选择框单元类型的扩展或单元工厂应该能够做到这一点,但我不知道如何。
感谢您的帮助。
答案 0 :(得分:4)
我认为要这样做,您需要创建一个通用模型Parameter
类,并将其用作表的类型。你可以将它抽象化并定义一个抽象的getEditor()
方法(或者将编辑器工厂委托给另一个类,但我会尽量保持这个简单)。然后定义根据需要创建不同编辑器的子类。
这看起来像这样:
public abstract class Parameter<T> {
private final BooleanProperty editable = new SimpleBooleanProperty();
private final ObjectProperty<T> value = new SimpleObjectProperty<>();
private final String name ;
public Parameter(String name, T value, boolean editable) {
this.name = name ;
setValue(value);
setEditable(editable);
}
public Parameter(String name, T value) {
this(name, value, true);
}
public String getName() {
return name ;
}
public ObjectProperty<T> valueProperty() {
return value ;
}
public T getValue() {
return valueProperty().get();
}
public void setValue(T value) {
valueProperty().set(value);
}
public BooleanProperty editableProperty() {
return editable ;
}
public boolean isEditable() {
return editableProperty().get() ;
}
public void setEditable(boolean editable) {
editableProperty().set(editable);
}
public abstract Node getEditor() ;
}
那么对于“免费”字符串,你可能会有这样一个简单的实现:
public class StringParameter extends Parameter<String> {
private final TextField editor ;
public StringParameter(String name, String value) {
super(name, value);
editor = new TextField();
editor.textProperty().bindBidirectional(valueProperty());
}
@Override
public Node getEditor() {
return editor ;
}
}
对于一个微调器来说可能是这样的:
public class BoundIntegerParameter extends Parameter<Integer> {
private final Spinner<Integer> editor ;
public BoundIntegerParameter(int min, int max, String name, int value) {
super(name, value);
editor = new Spinner<>(min, max, value);
editor.setEditable(true);
editor.getValueFactory().valueProperty().bindBidirectional(valueProperty());
}
@Override
public Node getEditor() {
return editor ;
}
}
对于“修复列表”,您可以类似地实现FixedStringParameter
,其中包含字符串列表,其getEditor
方法返回ComboBox
。另一种固定选择的方法可能是使用Enum
类型:这可能看起来像
public class EnumParameter<E extends Enum<E>> extends Parameter<E> {
private final ComboBox<E> editor ;
public EnumParameter(String name, E value) {
super(name, value);
editor = new ComboBox<>();
@SuppressWarnings("unchecked")
Class<E> type = (Class<E>) value.getClass();
E[] values = type.getEnumConstants() ;
editor.getItems().setAll(values);
editor.valueProperty().bindBidirectional(valueProperty());
}
@Override
public Node getEditor() {
return editor ;
}
}
现在,对于值列的单元格实现,您需要一些技巧。这似乎有效:
public class ParameterValueEditingCell extends TableCell<Parameter<?>, Object> {
@Override
public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
setText(null);
Parameter<?> param = getTableView().getItems().get(getIndex());
setGraphic(param.getEditor());
} else {
setText(item.toString());
setGraphic(null);
}
}
}
@Override
public void startEdit() {
// check if current parameter is editable and bail if not:
int index = getIndex();
if (index < 0 || index >= getTableView().getItems().size()) {
return ;
}
if (! getTableView().getItems().get(index).isEditable()) {
return ;
}
super.startEdit();
setText(null);
setGraphic(getTableView().getItems().get(getIndex()).getEditor());
}
@Override
public void cancelEdit() {
super.cancelEdit();
Object item = getItem();
setText(item == null ? null : item.toString());
setGraphic(null);
}
}
最后,你可以设置为
TableView<Parameter<?>> table = new TableView<>();
table.setEditable(true);
TableColumn<Parameter<?>, Object> valueColumn = new TableColumn<>("Value");
// I can't see any way to set this up without the ugly (unchecked) cast
// Any ideas?
valueColumn.setCellValueFactory(cellData -> (ObservableValue<Object>)cellData.getValue().valueProperty());
valueColumn.setCellFactory(tc -> new ParameterValueEditingCell());
我做了一个完整的例子here