TreeTableView : setting a row not editable

拜拜、爱过 提交于 2019-11-29 17:09:29

The base problem is that none of the editable (nor the pseudo-editable like CheckBoxXX) Tree/Table cells respect the editability of the row they are contained in. Which I consider a bug.

To overcome, you have to extend the (pseudo) editable cells and make them respect the row's editable. The exact implementation is different for pseudo- vs. real editing cells. Below are in-line examples, for frequent usage you would make them top-level and re-use.

CheckBoxTreeTableCell: subclass and override updateItem to re-bind its disabled property like

colSelected.setCellFactory(c -> {
    TreeTableCell cell = new CheckBoxTreeTableCell() {

        @Override
        public void updateItem(Object item, boolean empty) {
            super.updateItem(item, empty);
            if (getGraphic() != null) {
                getGraphic().disableProperty().bind(Bindings
                        .not(
                              getTreeTableView().editableProperty()
                             .and(getTableColumn().editableProperty())
                             .and(editableProperty())
                             .and(getTreeTableRow().editableProperty())
                    ));
            }
        }

    };
    return cell;
});

For a real editing cell, f.i. TextFieldTreeTableCell: override startEdit and return without calling super if the row isn't editable

colName.setCellFactory(c -> {
    TreeTableCell cell = new TextFieldTreeTableCell() {

        @Override
        public void startEdit() {
            if (getTreeTableRow() != null && !getTreeTableRow().isEditable()) return;
            super.startEdit();
        }

    };
    return cell;
});

Now you can toggle the row's editability as you do, changed the logic a bit to guarantee full cleanup in all cases:

ttv.setRowFactory(table-> {
    return new TreeTableRow<Person>(){
        @Override
        public void updateItem(Person pers, boolean empty) {
            super.updateItem(pers, empty);
            // tbd: check for nulls!
            boolean isTopLevel = table.getRoot().getChildren().contains(treeItemProperty().get());
            if (!isEmpty() && isTopLevel) {
                //                        if(isTopLevel){
                setStyle("-fx-background-color:lightgrey;");
                setEditable(false); 
            }else{
                setEditable(true);
                setStyle("-fx-background-color:white;");

            }
        }
    };
});

If you want disable a specific Cell then handle the disable logic in the CellFactory rather than in RowFactory. The static method forTreeTableColumn(..) is a convinient method for quick use. But that is not the only way. You can still create your own factory for CheckBoxTreeTableCell.

So instead of

colSelected.setCellFactory(CheckBoxTreeTableCell.forTreeTableColumn(colSelected));

set the cellfactory as below, and this should work for you.

colSelected.setCellFactory(new Callback<TreeTableColumn<Person, Boolean>, TreeTableCell<Person, Boolean>>() {
            @Override
            public TreeTableCell<Person, Boolean> call(TreeTableColumn<Person, Boolean> column) {
                return new CheckBoxTreeTableCell<Person, Boolean>(){
                    @Override
                    public void updateItem(Boolean item, boolean empty) {
                        super.updateItem(item, empty);
                        boolean isTopLevel = column.getTreeTableView().getRoot().getChildren().contains(getTreeTableRow().getTreeItem());
                        setEditable(!isTopLevel);
                    }
                };
            }
        });
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!