我認爲要做到這一點,您需要創建一個通用模型Parameter
類,並將其用作表的類型。你可以把它抽象化並定義一個抽象的方法(或者把編輯器工廠委託給另一個類,但我會盡量保持這個儘可能簡單)。然後根據需要定義創建不同編輯器的子類。
這可能是這個樣子:
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
您將需要一個電池工廠和一個自定義'TableCell'實現。根據確切的要求(例如,如果和當「可編輯」屬性和任何給定項目的允許值列表可以更改),它可能相當簡單,或者相當複雜。 –