2015-12-31 4 views
2

Как отключить любую ячейку, редактируемую в родительской строке в treetableview? Посмотрите фотографии и проверьте код образца. Вскоре я хочу, чтобы отключить строку редактируемой, если строка является расширяемой (корень строки или к югу от корневой строки)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 не работает.

+0

В вашей реализации ячейки, вы можете назвать 'setEditable (истина)' или 'setEditable (false) 'в методе' updateItem (...) ', в зависимости от отображаемого элемента. –

+0

@James_D благодарит за ваш комментарий, но это не решит мою проблему. потому что, как вы можете видеть на картине «Купание», это ** TreeItem **. если я дважды нажму на S. Нет, просто просмотрите расширенный или свернутый. Но когда я дважды нажимаю на ячейку столбца «Имя элемента», вступает в режим редактирования. Я хочу разрешить режим редактирования ячейки только в том случае, если строка является листом. – sakit

+0

Идея заключается в том, что вы проверяете метод 'updateItem', является ли элемент дерева листом или нет, и установите соответствующий отредактированный флаг. –

ответ

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); 
    } 
} 
+0

Большое вам спасибо. теперь работает. Как вы упомянули, проблема в том, что я не проверял, что ячейка редактируема или нет в методе startEdit() – sakit

+1

не связана: нет необходимости расширять область действия updateItem (публично) - это строго для использования в самом классе (вежливый кашель:) – kleopatra

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.startEdit(); 
// super changed state into editing 
if (isEditing()) { 
    // create and install the textField 
}