TreeTableView禁用父行中的任何单元格

时间:2015-12-31 16:17:27

标签: javafx-8 treetableview treetablecelleditor

如何禁用treetableview中父行中可编辑的任何单元格?请查看图片并查看示例代码。不久我想在行可扩展(根行或子根行)

时禁用行可编辑

这张照片是对的 enter image description here

但这不正确 enter image description here

**示例代码**

import javafx.application.Application;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
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 TreeTableExample extends Application {

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

    @Override
    @SuppressWarnings("unchecked")
    public void start(Stage stage) {

        HBox root = new HBox(createTable());
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.setTitle("Using a TreeTableView");
        stage.show();
    }

    public TreeTableView createTable() {

        TreeTableView<Person> treeTable = new TreeTableView<>();
        treeTable.setEditable(true);

        Callback<TreeTableColumn<Person, String>, 
            TreeTableCell<Person, String>> cellFactory
                = (TreeTableColumn<Person, String> p) -> new EditingCell();

        TreeTableColumn<Person, String> firstName = new TreeTableColumn<>("First Name");
        firstName.setCellValueFactory(new TreeItemPropertyValueFactory<>("firstName"));
        firstName.setCellFactory(cellFactory);
        firstName.setOnEditCommit((TreeTableColumn.CellEditEvent<Person, String> event) -> {
            if(event.getNewValue()!=null)
                event.getRowValue().getValue().setFirstName(event.getNewValue());
        });

        TreeTableColumn<Person, String> lastName = new TreeTableColumn<>("Last Name");
        lastName.setCellValueFactory(new TreeItemPropertyValueFactory<>("lastName"));
        lastName.setCellFactory(cellFactory);
        lastName.setOnEditCommit((TreeTableColumn.CellEditEvent<Person, String> event) -> {
            if(event.getNewValue()!=null)
                event.getRowValue().getValue().setLastName(event.getNewValue());
        });

        treeTable.getColumns().addAll(firstName, lastName);
        TreeItem<Person> root = new TreeItem<>();
        for (int i = 0; i < 5; i++) {
            root.getChildren().add(new TreeItem<>(new Person()));
        }
        treeTable.setRoot(root);
        return treeTable;
    }

    public class Person {

        private SimpleStringProperty firstName;
        private SimpleStringProperty lastName;

        public Person(){
            firstName = new SimpleStringProperty(this, "firstName");
            lastName = new SimpleStringProperty(this, "lastName");
        };

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String fName) {
            firstName.set(fName);
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String fName) {
            lastName.set(fName);
        }

    }

    class EditingCell extends TreeTableCell<Person, String> {

        private TextField textField;

        public EditingCell() {
        }

        @Override
        public void startEdit() {
            if (!isEmpty()) {
                super.startEdit();
                createTextField();
                setText(null);
                setGraphic(textField);
                textField.selectAll();
            }
        }

        @Override
        public void cancelEdit() {
            super.cancelEdit();

            setText((String) getItem());
            setGraphic(null);
        }

        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);

            if (empty) {
                setText(null);
                setGraphic(null);
            } else if (isEditing()) {
                if(!getTreeTableView().getTreeItem(getIndex()).isLeaf())
                    setEditable(false);
                if (textField != null) {
                    textField.setText(getString());
                }
                setText(null);
                setGraphic(textField);
            } else {
                setText(getString());
                setGraphic(null);
            }
        }

        private void createTextField() {
            textField = new TextField(getString());
            textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
            textField.focusedProperty().addListener(
                    (ObservableValue<? extends Boolean> arg0,
                            Boolean arg1, Boolean arg2) -> {
                        if (!arg2) {
                            commitEdit(textField.getText());
                        }
                    });
        }

        private String getString() {
            return getItem() == null ? "" : getItem();
        }
    }
}

运行它并双击根项目

make-individual-cell-editable-in-javafx-tableview我检查了解决方案适用于tableview,但treetaleview不起作用。

2 个答案:

答案 0 :(得分:2)

在决定是否致电TreeTableCell之前,似乎editable未正确检查其startEdit()属性。我认为这是一个错误。您可以通过startEdit()方法检查自己来解决此问题:

@Override
public void startEdit() {
    if (isEditable() && !isEmpty()) {
        super.startEdit();
        createTextField();
        setText(null);
        setGraphic(textField);
        textField.selectAll();
    }
}

现在在您的updateItem()方法中,您可以检查该行中的当前树项,并根据需要更新editable

@Override
public void updateItem(String item, boolean empty) {
    super.updateItem(item, empty);

    TreeItem<Person> treeItem = getTreeTableRow().getTreeItem();
    setEditable(treeItem != null &&  treeItem.isLeaf());

    if (empty) {
        setText(null);
        setGraphic(null);
    } else if (isEditing()) {
        if(!getTreeTableView().getTreeItem(getIndex()).isLeaf())
            setEditable(false);
        if (textField != null) {
            textField.setText(getString());
        }
        setText(null);
        setGraphic(textField);
    } else {
        setText(getString());
        setGraphic(null);
    }
}

答案 1 :(得分:0)

实际上我不同意other answer中的推理:核心TreeTableCell没有任何问题( 在实际开始编辑之前检查其可编辑性) - 而不是自定义单元格实现已破坏。特别是,updateItem用于设置可编辑属性的部分:

} else if (isEditing()) {
    if(!getTreeTableView().getTreeItem(getIndex()).isLeaf())
        setEditable(false);

除了在不将任何地方的可编辑状态重置为真时不完整(记住:重复使用单元格),我们允许超级首先开始编辑,只有之后开始了,它被禁用了。

通过在updateItem中无条件地设置可编辑性,修复了此逻辑错误(在另一个答案中,为方便起见,此处复制):

super.updateItem(item, empty);

TreeItem<Person> treeItem = getTreeTableRow().getTreeItem();
setEditable(treeItem != null &&  treeItem.isLeaf());

在实际配置编辑器之前,其他使用错误(如前所述)未完全检查单元状态。建议的修复 - 检查单元格的可编辑 - 并不完全,因为表/列可编辑性也可能被禁用。考虑到这一点,我倾向于让super执行其工作,只有在可编辑性实际发生变化时才配置编辑器,例如

super.startEdit();
// super changed state into editing 
if (isEditing()) {
   // create and install the textField
}  
相关问题