Проблемы с реализацией редактируемого TableView<ObservableList <String>

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

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 Объект отображается в ячейке, как в моей текущей реализации.

2 ответа

Решение

Вы регистрируете обработчик события в качестве ключевого обработчика события в ячейке. Имеет смысл зарегистрировать обработчик в текстовом поле, поскольку это тот элемент управления, на котором действительно происходит интересующее событие. Обратите внимание, что TextFieldПожарные события при нажатии Enter.

Так замени

    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, но и полностью исключает уныние.

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

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

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

Другие вопросы по тегам