Java JTable 如何在按下回车键时将焦点从编辑模式下的当前单元格转移到下一个单元格

Cod*_*Cat 5 java swing jtable key-bindings tablecelleditor

让我介绍一下我的问题的场景。我希望在 JTable 中呈现数据库表的内容。有了这个 JTable,我应该能够插入新行、删除行以及更新现有行的字段内容。

\n\n

第一个期望的行为是,当单元格获得焦点时,如果它是可编辑的,则它会直接进入编辑模式,并且如果它是字母数字内容,则选择所有内容。(文本、数字、日期等)

\n\n

下一个期望的行为是Enter按键作为按键工作Tab,即,按下Enter按键焦点必须向前(从左到右)或向后转移到下一个单元格(如果这是可编辑的,则进入编辑模式)。

\n\n

为了满足第一个要求,我使用以下方法覆盖 JTable 类的changeSelection 方法。

\n\n
@Override\npublic void changeSelection(int row, int column, boolean toggle, boolean extend) {\n    super.changeSelection(row, column, toggle, extend);\n    if (editCellAt(row, column)) {\n        Component editor = getEditorComponent();\n        editor.requestFocusInWindow();\n        if (editor instanceof JFormattedTextField) {\n            ((JFormattedTextField) editor).select(0,\n                    ((JFormattedTextField) editor).getText().length());\n        } else if (editor instanceof JTextField) {\n            ((JTextField) editor).selectAll();\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在阅读了大量文档和帖子后,很明显解决问题的最合适方法是通过使用键绑定,基本上,读完之后,解决方案是将键的行为分配给TabEnter,我也这么做了。

\n\n
private void tableConfiguration() {\n    //Configuramos la tabla para que en el caso de que pierda el foco finalice la edici\xc3\xb3n \n    putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);        \n    //Cambiamos el comportamiento por defecto de la tecla enter para que actue como TAB\n    getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)\n            .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "selectNextColumnCell");\n    // cambiamos Shift+Enter para que se comporte como Shift+Tab\n    getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)\n            .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK),\n            "selectPreviousColumnCell");\n    //configuramos el comportamiento por defecto que queremos que tenga nuestro grid\n    setSelectionMode(ListSelectionModel.SINGLE_SELECTION);//seleccion simple de celda\n    setCellSelectionEnabled(true);//muestra la celda activa seleccionada\n    getTableHeader().setReorderingAllowed(false);//no permite reordenar por columnas\n    setRowHeight(26);//altura de la fila\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如您在代码部分中看到的,它们被分配给按键Enter以及按键Shift+Enter的行为。TabShift+Tab

\n\n

我遇到的问题是密钥Enter有意外的行为。当单元格获得焦点时,直接进入编辑模式,当我按下该Enter键时,它完成编辑,但它不会将焦点转移到下一个单元格,我需要再次按下该键Enter才能得到它。Tab按键Shift+Tab按预期工作,奇怪的是,Shift+Enter按键也工作得很好,完成编辑,移动到上一个单元格并在编辑模式下开始。

\n\n

我试图按照不同的策略来纠正这种行为,覆盖editingStoppedJTable 类的方法,通过TableCellEditor类,以不同的方式使用监听器等,但我无法纠正这种行为,所以我现在陷入困境。有人有建议或解决方案吗?我究竟做错了什么?

\n\n

问候,

\n

tra*_*god 3

如此处所示,您可以获得对原始Action关联的引用"selectNextColumnCell"(通常与 关联)Tab,并在您的实现中调用它editingStopped()。下面的简化示例还将该操作与按 相关联Enter。结果是,按下Enter与按下 具有相同的效果Tab,即使按键也结束编辑。

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;

public class TestTableKeyBinding {

    private final String name = "selectNextColumnCell";

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            new TestTableKeyBinding();
        });
    }

    TestTableKeyBinding() {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        String[] headers = new String[]{"apples", "bananas"};
        String[][] data = new String[][]{{"1", "2"}, {"3", "4"}, {"5", "6"}};
        JTable table = new JTable(data, headers) {
            @Override
            public void editingStopped(ChangeEvent e) {
                super.editingStopped(e);
                this.getActionMap().get(name).actionPerformed(
                    new ActionEvent(this, ActionEvent.ACTION_FIRST, name));
            }
        };
        table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
            .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), name);
        table.setCellSelectionEnabled(true);
        f.add(new JScrollPane(table));
        f.pack();
        f.setSize(new Dimension(320, 240));
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }
}
Run Code Online (Sandbox Code Playgroud)