2017-08-24 39 views
0

我實現了使用自定義單元格控件的treetable,並且在從單元格控件中持續更新數據時遇到問題。 具體如何調用commitEdit,updateControl或使用對象綁定來確保在每個單元格中所做的更改都保留在底層域對象中。如何使用自定義控件持久化javafx treetablecells的值

最初的問題Multiple Controls needed in JavaFX Tree Table Cell

在我的代碼下面你可以看到倒塌的時候使細胞保持數據和擴大樹表節點問題。

我將如何使用自定義單元格控件觸發更新並將數據保存到底層行對象?

import java.util.Arrays; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

import javafx.application.Application; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.beans.value.ObservableValue; 
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; 
import javafx.util.converter.BooleanStringConverter; 

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 StringProperty 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 = new SimpleStringProperty(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.get(); 
    } 
    public StringProperty valueProperty() { 
     return value; 
    } 

    public void setValue(String value) { 
     this.value.set(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 
    public void updateItem(String item, boolean empty) { 
     super.updateItem(item, empty); 
     if (empty) { 
      setText(null); 
      setGraphic(null); 
     } else { 
      setText(null); 
      System.out.println("updating getItem()" + getItem()); 
      System.out.println("getTableRow().getItem().getName() " + getTreeTableRow().getItem().getName()); 
      setGraphic(controlProvider.getControl(getTreeTableRow().getItem())); 
     } 
    } 

    protected void commitEdit() { 
     super.commitEdit(getItem()); 
     System.out.println("committing edit"); 
     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)); 
     field.valueProperty().bindBidirectional(checkBox.selectedProperty(), new BooleanStringConverter()); 
     checkBox.focusedProperty().addListener(new ChangeListener<Boolean>() { 
      @Override 
      public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { 
       if (!newValue) { 
        updateFromControl(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); 
     field.valueProperty().bindBidirectional(comboBox.valueProperty()); 

    } 

    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()); 
     field.valueProperty().bindBidirectional(textField.textProperty()); 
    } 

    @Override 
    public void updateFromControl(MyField field) { 
     field.setValue(textField.getText()); 
    } 

} 

} 

回答

2

我猜你需要通過對控制供應商傳遞細胞:

public interface MyEditingControlProvider { 
    public Control getControl(TreeTableCell<MyField, String> cell); 
    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(TreeTableCell<MyField, String> cell) { 
     if (field == null || field.getFieldType() == null) { 
      return null; 
     } else { 
      return providers.get(field.getFieldType()).getControl(cell); 
     } 
    } 

    @Override 
    public void updateFromControl(MyField field) { 
     providers.get(field.getFieldType()).updateFromControl(field); 
    } 

} 

然後個別的實現可以做,例如

public class CheckProvider implements MyEditingControlProvider { 
    private CheckBox checkBox; 


    @Override 
    public Control getControl(TreeTableCell<MyField, String> cell) { 
     if (checkBox == null) { 
      createCheckBox(cell); 
     } 
     return checkBox; 
    } 

    private void createCheckBox(TreeTableCell<MyField, String> cell) { 
     checkBox = new CheckBox("Check"); 
     MyField field = cell.getTreeTableRow().getItem(); 
     checkBox.setSelected(getBoolean(field)); 
     field.valueProperty().bindBidirectional(checkBox.selectedProperty(), new BooleanStringConverter()); 
     checkBox.setOnAction(cell.commitEdit(convertBooleanToYN(checkBox.isSelected()))); 
    } 

    // ... 

} 
相關問題