我需要基於行對象的枚舉屬性值的JavaFX TreeTableCell中的不同可編輯控件。 在不同的情況下,我需要一個DatePicker,一個TextField,一個CheckBox,一個ComboBox或一個簡單的不可編輯的文本字段。JavaFX樹表格中需要多個控件單元格
我已經擴展了TreeTableCell並重寫updateItem來處理不同的情況,但是這變得非常麻煩。
是否可以根據行對象的屬性創建自定義CellFactory回調以返回不同的子類TreeTableCells?我該如何去做這件事?
public class MyCellFactory implements Callback<TreeTableColumn<MyField,String>,TreeTableCell<MyField,String>> {
@Override
public TreeTableCell<MyField, String> call(TreeTableColumn<MyField, String> param) {
return new MyCell();
}
}
public class MyCell extends TreeTableCell<MyField, String> {
private TextField textField;
private DatePicker datePicker;
private CheckBox checkBox;
private Text text;
private ComboBox<String> comboBox;
public MyCell() {
super();
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty || getTreeTableRow() == null) {
setText(null);
setGraphic(null);
} else {
MyField myField = (MyField) getTreeTableRow().getItem();
if (isEditing()) {
if (myField.getFieldType().equals(MyFieldType.CheckBox)) {
if (checkBox != null) {
checkBox.setSelected(getBoolean());
}
setText(null);
setGraphic(checkBox);
} else if (myField.getFieldType().equals(MyFieldType.Date)) {
if (datePicker != null) {
datePicker.setValue(getDate());
}
setText(null);
setGraphic(datePicker);
} else {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
}
//...
}
//...
}
我已經實現了James_D方法的SSCCE版本,但無法理解如何提交和更新對不同單元格的更改。我會發布修正版本。一旦我找到一個解決方案
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Control;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableCell;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.control.cell.TreeItemPropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class SampleApp extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@SuppressWarnings("unchecked")
@Override
public void start(Stage primaryStage) throws Exception {
TreeItem<MyField> fooFields = new TreeItem<MyField>(new MyField("Foo", "Foo", null, false, null));
TreeItem<MyField> fooText = new TreeItem<MyField>(new MyField("fooText", "fooText", "text", true, null));
TreeItem<MyField> fooCheck = new TreeItem<MyField>(new MyField("fooCheck", "fooCheck", "check", true, null));
List<String> fooCombos = Arrays.asList("foo Combo 1", "foo Combo 2");
TreeItem<MyField> fooCombo = new TreeItem<MyField>(
new MyField("fooCombo", "foo Combo", "combo", true, fooCombos));
fooFields.getChildren().addAll(fooText, fooCheck, fooCombo);
TreeItem<MyField> barFields = new TreeItem<MyField>(new MyField("Bar", "Bar", null, false, null));
TreeItem<MyField> barText = new TreeItem<MyField>(new MyField("barText", "barText", "text", true, null));
TreeItem<MyField> barCheck = new TreeItem<MyField>(new MyField("barCheck", "barCheck", "check", true, null));
List<String> barCombos = Arrays.asList("bar Combo 1", "bar Combo 2");
TreeItem<MyField> barCombo = new TreeItem<MyField>(
new MyField("barCombo", "bar Combo", "combo", true, barCombos));
barFields.getChildren().addAll(barText, barCheck, barCombo);
TreeItem<MyField> hiddenRoot = new TreeItem<MyField>(new MyField("hidden", "hidden", null, false, null));
hiddenRoot.getChildren().addAll(fooFields, barFields);
TreeTableView<MyField> treeTable = new TreeTableView<>(hiddenRoot);
treeTable.setEditable(true);
treeTable.setPrefWidth(400);
treeTable.setShowRoot(false);
TreeTableColumn<MyField, String> nameCol = new TreeTableColumn<MyField, String>("Name");
nameCol.setPrefWidth(150);
nameCol.setCellValueFactory(new TreeItemPropertyValueFactory<MyField, String>("name"));
TreeTableColumn<MyField, String> valueCol = new TreeTableColumn<MyField, String>("Value");
valueCol.setPrefWidth(250);
valueCol.setCellValueFactory(new TreeItemPropertyValueFactory<MyField, String>("value"));
valueCol.setCellFactory(new MyFieldCellFactory());
treeTable.getColumns().addAll(nameCol, valueCol);
HBox root = new HBox(treeTable);
root.setStyle("-fx-padding: 10;" + "-fx-border-style: solid inside;" + "-fx-border-width: 2;"
+ "-fx-border-insets: 5;" + "-fx-border-radius: 5;" + "-fx-border-color: blue;");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("Multi Control Tree Table View");
primaryStage.show();
}
public class MyField {
private String name;
private String value;
public String fieldType;
public boolean isEditable;
public List<String> comboVals;
public MyField(String name, String value, String fieldType, boolean isEditable, List<String> comboVals) {
super();
this.name = name;
this.value = value;
this.fieldType = fieldType;
this.isEditable = isEditable;
this.comboVals = comboVals;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getFieldType() {
return fieldType;
}
public void setFieldType(String fieldType) {
this.fieldType = fieldType;
}
public List<String> getComboVals() {
return comboVals;
}
public void setComboVals(List<String> comboVals) {
this.comboVals = comboVals;
}
public boolean isEditable() {
return isEditable;
}
public void setEditable(boolean isEditable) {
this.isEditable = isEditable;
}
}
public class MyFieldCellFactory
implements Callback<TreeTableColumn<MyField, String>, TreeTableCell<MyField, String>> {
@Override
public TreeTableCell<MyField, String> call(TreeTableColumn<MyField, String> param) {
return new MyFieldCell();
}
}
public class MyFieldCell extends TreeTableCell<MyField, String> {
private MyEditingControlProvider controlProvider = new MyCellEditingControlProvider();
public MyFieldCell() {
super();
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
MyField myField = getTreeTableRow().getItem();
setText(null);
setGraphic(controlProvider.getControl(myField));
}
}
protected void commitEdit() {
super.commitEdit(getItem());
MyField myField = getTreeTableRow().getItem();
controlProvider.updateFromControl(myField);
}
}
public interface MyEditingControlProvider {
public Control getControl(MyField field);
public void updateFromControl(MyField field);
}
public class MyCellEditingControlProvider implements MyEditingControlProvider {
private Map<String, MyEditingControlProvider> providers;
public MyCellEditingControlProvider() {
providers = new HashMap<>();
providers.put("check", new CheckProvider());
providers.put("combo", new ComboProvider());
providers.put("text", new TextProvider());
}
@Override
public Control getControl(MyField field) {
if (field == null || field.getFieldType() == null) {
return null;
} else {
return providers.get(field.getFieldType()).getControl(field);
}
}
@Override
public void updateFromControl(MyField field) {
providers.get(field.getFieldType()).updateFromControl(field);
}
}
public class CheckProvider implements MyEditingControlProvider {
private CheckBox checkBox;
@Override
public Control getControl(MyField field) {
if (checkBox == null) {
createCheckBox(field);
}
return checkBox;
}
private void createCheckBox(MyField field) {
checkBox = new CheckBox("Check");
checkBox.setSelected(getBoolean(field));
}
private Boolean getBoolean(MyField field) {
return field.getValue() == null ? false : convertYNToBoolean(field.getValue());
}
private Boolean convertYNToBoolean(String val) {
if (val != null && val.equals("Y")) {
return true;
} else {
return false;
}
}
private String convertBooleanToYN(Boolean val) {
if (val) {
return "Y";
} else {
return "N";
}
}
@Override
public void updateFromControl(MyField field) {
field.setValue(convertBooleanToYN(checkBox.isSelected()));
}
}
public class ComboProvider implements MyEditingControlProvider {
private ComboBox<String> comboBox;
@Override
public Control getControl(MyField field) {
if (comboBox == null) {
createComboBox(field);
}
return comboBox;
}
private void createComboBox(MyField field) {
comboBox = new ComboBox<String>();
comboBox.setEditable(true);
resetBox(field);
}
private void resetBox(MyField field) {
comboBox.getItems().clear();
comboBox.getItems().addAll(field.getComboVals());
}
@Override
public void updateFromControl(MyField field) {
field.setValue(comboBox.getValue());
}
}
public class TextProvider implements MyEditingControlProvider {
private TextField textField;
@Override
public Control getControl(MyField field) {
if (textField == null) {
createTextField(field);
}
return textField;
}
private void createTextField(MyField field) {
textField = new TextField(field.getValue());
}
@Override
public void updateFromControl(MyField field) {
field.setValue(textField.getText());
}
}
}
*「是否有可能要創建自定義CellFactory回調返回根據行對象的屬性不同的子類TreeTableCells?」 * 號:因爲這是由電池廠家提供的電池將用於被重用不同的項目,例如當用戶展開/摺疊表格中的節點或用戶滾動時。所以返回的單元格必須能夠處理所有情況。您的一般結構是正確的:您可能想要將控件的選擇分解到單獨的類中以簡化代碼。 –