TableView - 编辑焦点单元格

TableView - Edit focused cell

我有一个监听键盘事件的事件监听器。当我尝试使用按键事件进入编辑模式时,由于某些奇怪的原因,错误的单元格进入了编辑模式。

例如我想编辑一个单元格。我使用键盘箭头转到我要编辑的单元格,即聚焦的单元格。通过单击键盘上的字母,获得焦点的单元格应进入编辑模式。当我尝试编辑焦点单元格时,错误的单元格进入编辑模式。

private final class EditCell extends TableCell<SimpleStringProperty, String> implements GenericTable
{

    public EditCell()
    {
        // Add event listsner. table is a TableView
        table.setOnKeyPressed(keyEvent -> this.handleKeyPressed(keyEvent));
    }

    public void handleKeyPressed(KeyEvent key)
    {
        // Keyboard events
        if (key.getCode().isLetterKey())
        {
            if (!this.isEditing())
            {

                this.edit = true;

                // focus index
                int focusIndex = this.table.getSelectionModel().getFocusedIndex();

                this.changeTableCellFocus(this.table, focusIndex);

                this.startEdit();
            }
        }
    }


    // startEdit() function
    @Override
    public void startEdit()
    {
        if (this.edit)
        {
            LOGGER.info("Start editing on cell index: " + this.getIndex());
            super.startEdit();
            this.createTextField();
            this.setText(null);
            this.setGraphic(this.textField);
            this.textField.selectAll();
            this.textField.requestFocus();

            this.textField.setOnKeyPressed(keyEvent -> this.handleKeyPressed(keyEvent));

            this.textField.focusedProperty()
                    .addListener((observable, oldValue, newValue) -> this.onTextFieldFocusChange(observable,
                            oldValue,
                            newValue));
        }
    }

    // Change focus
    public void changeTableCellFocus(final TableView<?> table, final int focusIndex)
    {
        table.requestFocus();
        table.getSelectionModel().clearAndSelect(focusIndex);
        table.getFocusModel().focus(focusIndex);
    }
}

在进入编辑模式之前,我将焦点切换到单击的单元格,然后调用 startEdit() 方法。我试图调试这个问题,但没有成功。我注意到 focusIndex 与当前单元格索引不同。我不确定为什么索引不同。

您的代码存在的问题是每个单元格在创建时都在调用 table.setOnKeyPressed(...)。这与任何其他 set 方法一样工作,因此 table 上的 keyPressed 处理程序只是设置为最后创建的 EditCell 中的处理程序。您无法控制实际创建的单元格,这不一定(也不太可能)是恰好聚焦的单元格。

TableView 有足够的 API 供您直接从 table 进行管理。特别是

table.getFocusModel().getFocusedCell()

会给你一个 TablePosition 代表当前聚焦的单元格。从中您可以检索相应的行索引和 TableColumn。然后你只需要调用 table.edit(int row, TableColumn<...> column); 来指示相应的单元格进入编辑模式。

这是一个完整的例子。在文本字段中选择文本等方面,我没有做太多努力来进行编辑 "pretty",您可能想以某种方式实现编辑取消,但这应该可以帮助您入门。

import java.util.ArrayList;
import java.util.List;

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class TableViewEditOnType extends Application {


    @Override
    public void start(Stage primaryStage) {
        TableView<List<StringProperty>> table = new TableView<>();
        table.getSelectionModel().setCellSelectionEnabled(true);
        table.setEditable(true);

        for (int i = 0; i < 10; i++) {
            table.getColumns().add(createColumn(i));

            List<StringProperty> rowData = new ArrayList<>();
            table.getItems().add(rowData);
            for (int j = 0; j < 10 ; j++) {
                rowData.add(new SimpleStringProperty(String.format("Cell [%d, %d]", i, j)));
            }
        }

        table.setOnKeyTyped(event -> {
            TablePosition<List<StringProperty>, String> focusedCell = table.getFocusModel().getFocusedCell();
            if (focusedCell != null) {
                table.getItems().get(focusedCell.getRow()).get(focusedCell.getColumn()).set(event.getCharacter());
                table.edit(focusedCell.getRow(), focusedCell.getTableColumn());
            }
        });

        Scene scene = new Scene(new BorderPane(table), 880, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private TableColumn<List<StringProperty>, String> createColumn(int colIndex) {
        TableColumn<List<StringProperty>, String> col = new TableColumn<>("Column "+colIndex);
        col.setCellValueFactory(cellData -> cellData.getValue().get(colIndex));
        col.setCellFactory(column -> new EditCell());
        return col ;
    }

    private static class EditCell extends TableCell<List<StringProperty>, String> {

        private final TextField textField = new TextField();

        EditCell() {   
            textProperty().bind(itemProperty());
            setGraphic(textField);
            setContentDisplay(ContentDisplay.TEXT_ONLY);

            textField.setOnAction(evt -> commitEdit(textField.getText()));
            textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
                if (! isNowFocused) {
                    commitEdit(textField.getText());
                }
            });
        }

        @Override
        public void startEdit() {
            super.startEdit();
            textField.setText(getItem());
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            textField.requestFocus();          
        }

        @Override
        public void cancelEdit() {
            super.cancelEdit();
            setContentDisplay(ContentDisplay.TEXT_ONLY);
        }

        @Override
        public void commitEdit(String text) {
            super.commitEdit(text);
            setContentDisplay(ContentDisplay.TEXT_ONLY);
        }

    }

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