2015-10-26 4 views
0

Итак, я пытался реализовать TableView, где вы можете редактировать столбец, просто щелкнув по нему, а затем сохраните редактирование, нажав клавишу ввода. Я взял много кода из ответа в потоке this. Это результат:Проблемы с реализацией редактируемого TableView <ObservableList <String>

import com.sun.javafx.collections.ObservableListWrapper; 

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.scene.Scene; 
import javafx.scene.control.TableCell; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableView; 
import javafx.scene.control.TextField; 
import javafx.scene.input.KeyCode; 
import javafx.stage.Stage; 

public class TestEditableTable extends Application { 

    public void start(Stage stage) { 

     TableView<ObservableList<String>> tableView = new TableView<ObservableList<String>>(); 
     tableView.setEditable(true); 

     // Some dummy data. 
     ObservableList<ObservableList<String>> dummyData = FXCollections.observableArrayList(); 
     ObservableList<String> firstRow = FXCollections.observableArrayList("Jack", "Smith"); 
     dummyData.add(firstRow); 
     ObservableList<String> secondRow = FXCollections.observableArrayList("Peter", "Smith"); 
     dummyData.add(secondRow); 

     TableColumn<ObservableList<String>, String> firstCol = new TableColumn<ObservableList<String>, String>(
       "First name"); 
     firstCol.setCellValueFactory(
       (TableColumn.CellDataFeatures<ObservableList<String>, String> param) -> new SimpleStringProperty(
         param.getValue().get(0))); 

     TableColumn<ObservableList<String>, String> secondCol = new TableColumn<ObservableList<String>, String>(
       "Last name"); 
     secondCol.setCellValueFactory(
       (TableColumn.CellDataFeatures<ObservableList<String>, String> param) -> new SimpleStringProperty(
         param.getValue().get(1))); 

     secondCol.setCellFactory(cell -> new EditableCell()); 

     tableView.getColumns().addAll(firstCol, secondCol); 

     tableView.getItems().addAll(dummyData); 

     Scene scene = new Scene(tableView); 
     stage.setScene(scene); 
     stage.show(); 
    } 

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

    class EditableCell extends TableCell<ObservableList<String>, String> { 

     private TextField textfield = new TextField(); 

     // When the user presses the enter button the edit is saved. 
     public EditableCell() { 
      setOnKeyPressed(e -> { 
       if (e.getCode().equals(KeyCode.ENTER)) { 
        commitEdit(textfield.getText()); 
       } 
      }); 
     } 

     @Override 
     public void updateItem(String item, boolean empty) { 
      super.updateItem(item, empty); 
      if (isEmpty()) { 
       setText(null); 
       setGraphic(null); 
      } else { 
       if (isEditing()) { 
        textfield.setText(item); 
        setGraphic(textfield); 
        setText(null); 
       } else { 
        setText(item); 
        setGraphic(null); 
       } 
      } 
     } 

     @Override 
     public void startEdit() { 
      super.startEdit(); 
      textfield.setText(getItem()); 
      setGraphic(textfield); 
      setText(null); 
     } 

     @Override 
     public void cancelEdit() { 
      super.cancelEdit(); 
      setGraphic(null); 
      setText(getItem()); 
     } 

     @Override 
     public void commitEdit(String value) { 
      super.commitEdit(value); 

      // This works. But gives me a "Discouraged access: The type 'ObservableListWrapper<String>' is not API (restriction on required library 'C:\Program Files\Java\jre1.8.0_60\lib\ext\jfxrt.jar')". 
      ObservableListWrapper<String> ob = ((ObservableListWrapper<String>) this.getTableRow().getItem()); 
      ob.set(1, value); 

      // I had to put this in a Platform.runLater(), otherwise the textfield remained open. 
      Platform.runLater(() -> { 
       setText(value); 
       setGraphic(null); 
      }); 
     } 
    } 
} 

И эта программа работает нормально. Ячейка редактируется при нажатии кнопки ввода. Но есть две основные проблемы:

  1. Как только я нажал enter, и ячейка была отредактирована. Я не могу изменить его снова, щелкнув по нему. Мне нужно нажать еще одну строку, чтобы иметь возможность редактировать ее снова. Настройка фокуса на родителя строки не сделала этого трюка.

  2. Код внутри commitEdit() работ. Но это уродливо, и использование ObservableListWrapper дает мне предупреждение «Отклоненный доступ: тип ObservableListWrapper» не является API (ограничение на требуемую библиотеку «C: \ Program Files \ Java \ jre1.8.0_60 \ lib \ ext \ jfxrt.jar «)». Также индекс ячейки жестко закодирован, что не работает, если я использую это во многих разных столбцах.

Ни один из указанных выше вопросов не является приемлемым.

Окончательная реализация должна поддерживать ограничение ввода в текстовом поле. Насколько я понимаю, это означает, что мне нужно иметь доступ к объекту TextField, отображаемому в ячейке, как в моей текущей реализации.

ответ

1

Вы регистрируете обработчик событий в качестве обработчика ключевых событий на ячейке. Имеет смысл регистрировать обработчик в текстовом поле, поскольку это элемент управления, на котором на самом деле происходит событие интереса. Также обратите внимание на то, что при нажатии клавиши «Ввод» срабатывают события пожаротушения TextField.

Так заменить

public EditableCell() { 
     setOnKeyPressed(e -> { 
      if (e.getCode().equals(KeyCode.ENTER)) { 
       commitEdit(textfield.getText()); 
      } 
     }); 
    } 

с

public EditableCell() { 
     textfield.setOnAction(e -> commitEdit(textfield.getText())); 
    } 

Это позволит убедиться, состояние редактирования надлежащим образом (что не происходит с обработчика событий, по причинам, я не могу достаточно выяснить,), поэтому он исправляет проблему «переиздания». Это также означает, что вам не нужно вручную переустанавливать текст и графику в commitEdit.

Для второй проблемы вы можете просто отказаться от ObservableList<String> вместо ObservableListWrapper<String>. Но учтите, что вы также можете просто сделать

@Override 
    public void commitEdit(String value) { 
     super.commitEdit(value); 
     ObservableList<String> row = getTableView().getItems().get(getIndex()); 
     row.set(1, value); 
    } 

, который не только избегает частного API, он полностью избегает опускания.

+0

Это помогло много. Благодаря! Я предполагаю, что могу исправить hardcoded 'row.set (1, value)', просто создав столбцы в цикле for динамически (сохраните имена столбцов в списке и создайте «TableColumn» для каждого элемента в списке имен столбцов) и передавая целое число цикла for в конструктор «EditableCell», если у меня много столбцов. –

0

Другим способом является замена JRE библиотеки на JDK библиотеки в вашем Buildpath Проект-> Build Path-> Настройка построить путь -1 Удалить JRE Library

-2 Добавить библиотеку -2.1 -> Выберите Java библиотеки, связанные с JDK Environnement

Все ошибки исчезнут

Смежные вопросы