如果只有一个查询按钮,您如何可靠地知道从多个表中选择了哪一个 JTable 行?

How do you reliably know which JTable row has been selected from multiple tables if there is only one query button?

尝试 Ubuntu 20.04 以防万一。
当存在多个 JTable,但您只需要查看最后一个 selected JTable 的最后一个用户 selected 行(或单元格)时,您如何可靠地知道那是哪一个?我试过列出 select 听众和焦点听众,但是当您在两个 table 中编辑一个单元格并且在相同的单元格之间移动时,都失败了。例如,给定以下代码:

package test;

import java.awt.FlowLayout;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;

public class TableRowSelect {
    private String lastSelectedValue = "";
    
    public TableRowSelect() {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Test row selection");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            Object[][] table1Data1 = new Object[][] {
                new Object[] {
                    "1: Row1Col1", "1: Row1 Col2",
                },
                new Object[] {
                    "1: Row2 Col1", "1: Row2Col2",
                },
            };
            Object[][] table1Data2 = new Object[][] {
                new Object[] {
                    "2: Row1Col1", "2: Row1 Col2",
                },
                new Object[] {
                    "2: Row2 Col1", "2: Row2Col2",
                },
            };
            Object[] columnNames1 = new Object[] {
                "Col1", "Col2",
            };
            JButton button = new JButton("Show Row");
            button.addActionListener((e) -> {
                System.out.println("Value: " + lastSelectedValue);
            });
            JTable table1 = new JTable(table1Data1, columnNames1);
            setupTable(table1, 1);
            JTable table2 = new JTable(table1Data2, columnNames1);
            setupTable(table2, 1);
            JScrollPane table1Pane = new JScrollPane(table1);
            JScrollPane table2Pane = new JScrollPane(table2);
            
            frame.setLayout(new FlowLayout());
            frame.add(table1Pane);
            frame.add(table2Pane);
            frame.add(button);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
    
    public static void main(String[] args) {
        new TableRowSelect();
    }
    
    private void setupTable(JTable table, int tableNumber) {
        table.getSelectionModel().addListSelectionListener((e) -> {
            int selectedRow = table.getSelectedRow();
            System.out.println("Selected a row in table " + tableNumber + ": " + selectedRow);
            if (!e.getValueIsAdjusting() && (selectedRow != -1)) {
                lastSelectedValue = table.getModel().getValueAt(selectedRow, 0).toString();
            }
        });
        table.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {
                System.out.println("Focused on a row in table " + tableNumber);
                int selectedRow = table.getSelectedRow();
                if (selectedRow != -1) {
                    lastSelectedValue = table.getModel().getValueAt(selectedRow, 0).toString();
                }
            }
            @Override
            public void focusLost(FocusEvent e) {
                System.out.println("Lost focus on a row in table " + tableNumber);
            }
        });
    }
}

当您使用任何新内容编辑 table 1,第 0 行,第 0 列,并且除了 table 2,第 1 行,第 0 列之外,没有按回车键或点击其他地方并编辑那个,当您返回 table 1,第 0 行,第 0 列时,您不会收到任何更改通知(selection 或 focus)。在编辑两个单元格之间来回切换不会让您知道当前正在编辑哪个单元格。上面的示例使用一个按钮来打印出单元格的内容,但它可以是对最后一个需要的 selected 单元格的任何类型的处理。

您可以通过在编辑器上安装 FocusListener 来检测编辑器 Component 上的焦点更改事件。

您可以像这样安装自己的编辑器(这样您就可以访问已安装的 Component):

final JTextField editorComp = new JTextField();
editorComp.addFocusListener(new FocusListener() {
    @Override
    public void focusGained(FocusEvent e) {
        System.out.println("Focus gained on editor component of table " + tableNumber + '.');
    }

    @Override
    public void focusLost(FocusEvent e) {
        System.out.println("Focus lost from editor component of table " + tableNumber + '.');
    }
});
table.setDefaultEditor(Object.class, new DefaultCellEditor(editorComp));

... 或者,如果您希望在预安装编辑器的 Component:

上执行此操作
((DefaultCellEditor) table.getDefaultEditor(Object.class)).getComponent().addFocusListener(new FocusListener() {
    @Override
    public void focusGained(FocusEvent e) {
        System.out.println("Focus gained on editor component of table " + tableNumber + '.');
    }

    @Override
    public void focusLost(FocusEvent e) {
        System.out.println("Focus lost from editor component of table " + tableNumber + '.');
    }
});

上述备选方案之一应该(通过复制粘贴)进入 setupTable 方法。您可以选择将该代码与 table 的 ListSelectionListener(安装在 ListSelectionModel 上)相结合。直接在 table 上的 FocusListener 本身似乎没有必要。

此外,不要忘记将第二次调用的第二个参数更改为 setupTable(例如应该是 2,而不是 1),否则使用 getSource(); 关于 FocusEventFocusListener(编辑者的 Component)方法接收。