user3164187
user3164187

Reputation: 1432

JavaFX : TreeTableView with CheckComboBoxCell not updating the cell properly

I have the following code to create a TreeTableView with a CheckComboBox in one column.

public class TreeTableViewSample extends Application {

    List<Employee> employees = Arrays.<Employee>asList(
            new Employee("Ethan Williams", ""),
            new Employee("Emma Jones", ""),
            new Employee("Michael Brown", ""),
            new Employee("Anna Black", ""),
            new Employee("Rodger York", ""),
            new Employee("Susan Collins", ""));

    final TreeItem<Employee> root = new TreeItem<>(new Employee("Department", ""));
    final TreeItem<Employee> root1 = new TreeItem<>(new Employee("Executive Department", ""));
    final TreeItem<Employee> root2 = new TreeItem<>(new Employee("Sales Department", ""));

    public static void main(String[] args) {
        Application.launch(TreeTableViewSample.class, args);
    }

    @Override
    public void start(Stage stage) {
        root.setExpanded(true);

        employees.stream().forEach((employee) -> {
            root1.getChildren().add(new TreeItem<>(employee));
            root2.getChildren().add(new TreeItem<>(employee));
        });
        root.getChildren().addAll(root1, root2);
        stage.setTitle("Tree Table View Sample");
        final Scene scene = new Scene(new Group(), 400, 400);
        scene.setFill(Color.LIGHTGRAY);
        Group sceneRoot = (Group) scene.getRoot();

        TreeTableColumn<Employee, String> empColumn
                = new TreeTableColumn<>("Employee");
        empColumn.setPrefWidth(150);
        empColumn.setCellValueFactory(
                (TreeTableColumn.CellDataFeatures<Employee, String> param)
                -> new ReadOnlyStringWrapper(param.getValue().getValue().getName())
        );

        TreeTableColumn<Employee, String> emailColumn
                = new TreeTableColumn<>("Email");
        emailColumn.setPrefWidth(190);
        emailColumn.setEditable(true);

        emailColumn.setCellFactory((TreeTableColumn<Employee, String> p) -> new CheckComboCell());

        emailColumn.setCellValueFactory(
                (TreeTableColumn.CellDataFeatures<Employee, String> param)
                -> new ReadOnlyStringWrapper(param.getValue().getValue().getEmail())
        );

        TreeTableView<Employee> treeTableView = new TreeTableView<>(root);
        treeTableView.setEditable(true);
        treeTableView.getColumns().setAll(empColumn, emailColumn);
        sceneRoot.getChildren().add(treeTableView);
        stage.setScene(scene);
        stage.show();
    }

    public class Employee {

        private SimpleStringProperty name;
        private SimpleStringProperty email;

        public SimpleStringProperty nameProperty() {
            if (name == null) {
                name = new SimpleStringProperty(this, "name");
            }
            return name;
        }

        public SimpleStringProperty emailProperty() {
            if (email == null) {
                email = new SimpleStringProperty(this, "email");
            }
            return email;
        }

        private Employee(String name, String email) {
            this.name = new SimpleStringProperty(name);
            this.email = new SimpleStringProperty(email);
        }

        public String getName() {
            return name.get();
        }

        public void setName(String fName) {
            name.set(fName);
        }

        public String getEmail() {
            return email.get();
        }

        public void setEmail(String fName) {
            email.set(fName);
        }
    }

}

Cell Factory Class

 public class CheckComboCell extends TreeTableCell<TreeTableViewSample.Employee, String> {

    private final ComboBox<CheckComboCellModel> cb = new ComboBox<CheckComboCellModel>() {
        @SuppressWarnings("restriction")
        @Override
        protected javafx.scene.control.Skin<?> createDefaultSkin() {
            return new ComboBoxListViewSkin<CheckComboCellModel>(this) {
                @Override
                protected boolean isHideOnClickEnabled() {
                    return false;
                }
            };
        }
    };

    private final ObservableList<CheckComboCellModel> items = FXCollections.observableArrayList();
    private final Tooltip tooltip = new Tooltip();

    public CheckComboCell() {
        super();
        populateAllocationType();
        cb.setItems(items);

        cb.setCellFactory((ListView<CheckComboCellModel> p) -> new ListCell<CheckComboCellModel>() {
            private final CheckBox checkBox = new CheckBox();
            private BooleanProperty booleanProperty;

            {
                checkBox.setOnAction(e -> getListView().getSelectionModel().select(getItem()));
            }

            @Override
            protected void updateItem(CheckComboCellModel item, boolean empty) {
                super.updateItem(item, empty);
                if (!empty) {
                    checkBox.setText(item.toString());
                    if (booleanProperty != null) {
                        checkBox.selectedProperty().unbindBidirectional(booleanProperty);
                    }
                    booleanProperty = item.checkProperty();
                    checkBox.selectedProperty().bindBidirectional(booleanProperty);
                    setGraphic(checkBox);
                } else {
                    setGraphic(null);
                    setText(null);
                }
            }
        });

        cb.setButtonCell(new ListCell<CheckComboCellModel>() {
            @Override
            protected void updateItem(CheckComboCellModel item, boolean empty) {
                super.updateItem(item, empty);
                String selected = cb.getItems().stream().filter(i -> i.getCheck())
                        .map(i -> i + "").collect(Collectors.joining(","));
                setText(selected);
            }
        });

        setGraphic(null);
    }

    private void populateAllocationType() {
        items.add(new CheckComboCellModel("mail_1"));
        items.add(new CheckComboCellModel("mail_2"));
        items.add(new CheckComboCellModel("mail_3"));
        items.add(new CheckComboCellModel("mail_4"));
        items.add(new CheckComboCellModel("mail_5"));
    }

    @Override
    public void startEdit() {
        if (!isEditable() || !getTreeTableView().isEditable() || !getTableColumn().isEditable()) {
            return;
        }
        super.startEdit();
        setGraphic(cb);
    }

    @Override
    public void commitEdit(String value) {
        super.commitEdit(value);
        setGraphic(null);
        setText(cb.getButtonCell().getText());
    }

    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setGraphic(null);
        setText(cb.getButtonCell().getText());
    }

    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
            setText(this.cb.getButtonCell().getText());
            setGraphic(null);
        }
    }
}

Model class

public class CheckComboCellModel {
     private final BooleanProperty check = new SimpleBooleanProperty(false);
    private final StringProperty item = new SimpleStringProperty();

    public CheckComboCellModel() {
    }

    public CheckComboCellModel(String item) {
        this.item.set(item);
    }

    public CheckComboCellModel(String item, Boolean check) {
        this.item.set(item);
        this.check.set(check);
    }

    public BooleanProperty checkProperty() {
        return check;
    }

    public Boolean getCheck() {
        return check.getValue();
    }

    public void setCheck(Boolean value) {
        check.set(value);
    }

    public StringProperty itemProperty() {
        return item;
    }

    public String getItem() {
        return item.getValueSafe();
    }

    public void setItem(String value) {
        item.setValue(value);
    }

    @Override
    public String toString() {
        return item.getValue();
    }

}

With this i get what i expect (i.e) a Column with CheckComboBox. But the issue is:

The application looks like this:

The application looks like this:

I selected some values

I selected some values

The values are updated in cell

The values are updated in cell

But when the node is minimized

But when the node is minimized

The updated value is displayed in next node. What i am doing wrong ? How can i solve this?

Upvotes: 1

Views: 158

Answers (0)

Related Questions