TreeTableView отключает любую ячейку в родительской строке

Как я могу отключить любую редактируемую ячейку в родительской строке в дереве таблицы? Пожалуйста, посмотрите фотографии и проверьте пример кода. Вскоре я хочу отключить редактируемую строку, если строка расширяемая (корневая строка или подкорневая строка)

эта картинка правильная введите здесь описание изображения

но это неверно введите здесь описание изображения

**Пример кода **

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 не работает.


person sakit    schedule 31.12.2015    source источник
comment
В реализации вашей ячейки вы можете вызвать setEditable(true) или setEditable(false) в методе updateItem(...), в зависимости от отображаемого элемента.   -  person James_D    schedule 31.12.2015
comment
@James_D спасибо за комментарий, но это не решает мою проблему. потому что, как вы можете видеть на картинке, зона для купания - это TreeItem. если я дважды щелкну S.No, просто просмотрите его в развернутом или свернутом виде. Но когда я дважды щелкаю по ячейке столбца «Имя элемента», он переходит в режим редактирования. Я хочу включить режим редактирования ячейки, только если строка является листом   -  person sakit    schedule 31.12.2015
comment
Идея заключается в том, что вы проверяете в методе updateItem, является ли элемент дерева листом или нет, и соответственно устанавливаете редактируемый флаг.   -  person James_D    schedule 31.12.2015
comment
я сделал но не получилось   -  person sakit    schedule 31.12.2015
comment
Тогда, вероятно, что-то не так с тем, как вы пытались это сделать.   -  person James_D    schedule 31.12.2015
comment
@Override public void updateItem(Integer item, boolean empty) { super.updateItem(item, empty); if (empty) { setText(null); setGraphic(null); } else{ if(!getTreeTableView().getTreeItem(getIndex()).isLeaf()) setEditable(false); ..... } } правильно или неправильно?   -  person sakit    schedule 31.12.2015
comment
Невозможно сказать от этого. Я рекомендую вам создать минимально воспроизводимый пример и отредактируйте свой вопрос, чтобы включить его.   -  person James_D    schedule 31.12.2015
comment
хорошо, я добавлю несколько примеров как можно скорее   -  person sakit    schedule 31.12.2015
comment
несвязанный: вам не нужны настраиваемые обработчики редактирования, если вы открыли свойства для Person (пример из учебника крайне неоптимален!)   -  person kleopatra    schedule 06.01.2016


Ответы (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);
    }
}
person James_D    schedule 02.01.2016
comment
большое спасибо. сейчас работает. Как вы упомянули, проблема в том, что я не проверял, доступна ли ячейка для редактирования или нет в методе startEdit(). - person sakit; 02.01.2016
comment
несвязанный: нет необходимости расширять область действия updateItem (до публики) - это строго для использования в самом классе (вежливый кашель :-) - person kleopatra; 06.01.2016

На самом деле я не согласен с рассуждениями в другом ответе: нет ничего плохого в ядре TreeTableCell (он делает проверьте его редактируемость перед тем, как начать редактирование) - вместо этого логика в реализации пользовательской ячейки нарушена. В частности, часть updateItem, которая устанавливает редактируемое свойство:

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

Помимо неполноты невозможности сбросить редактируемый объект обратно в значение true (помните: ячейки используются повторно), мы разрешаем super сначала начинать редактирование, и только после его запуска Отключено.

Эта логическая ошибка исправлена ​​(в другом ответе, скопированном здесь для удобства) безоговорочной установкой редактируемости в 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
}  
person kleopatra    schedule 06.01.2016