如何使用自定义控件

时间:2017-08-24 18:00:12

标签: javafx

我使用自定义单元格控件实现了treetable,并且无法保持来自单元格控件的更新数据。 具体来说,我如何调用commitEdit,updateControl或使用对象绑定来确保在每个单元格中进行的更改都保留在底层域对象中。

最初的问题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());
    }

}

}

1 个答案:

答案 0 :(得分: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())));
    }

    // ...

}