Skip to content
Advertisement

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

Tried on Ubuntu 20.04 in case it matters.
When multiple JTables are present, but you need to look at only the the last user selected row (or cell) of the last selected JTable, how can you reliably know which one that was? I’ve tried list select listeners and focus listeners, but all fail when you are editing a cell in both tables and you move between the same cells. For example, given the following code:

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);
            }
        });
    }
}

When you edit table 1, row 0, column 0 with anything new, and without pressing enter or clicking elsewhere other than table 2, row 1, column 0 and editing that one, when you click back on table 1, row 0, column 0, you don’t get any change notification (selection or focus). Going back and forth between editing both cells won’t let you know which one is currently being edited. The example above uses a button to print out the contents of the cell, but it can be any type of processing on the last selected cell that is needed.

Advertisement

Answer

You can detect focus change events on the editor’s Component by installing a FocusListener on it.

You can install your own editor (so that you have access to its installed Component) like so:

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));

… or, if you want this behaviour on the pre-installed editor’s 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 + '.');
    }
});

One of the above alternatives should go (by copy-paste) into the setupTable method. You can optionally combine that code with your ListSelectionListener (which you install on the ListSelectionModel) of the table. The FocusListener directly on the table itself seems not necessary for the purpose.

Also, don’t forget to change the second argument of the second call to setupTable (should be for example 2, not 1), otherwise use getSource(); on the FocusEvent received by the FocusListener (of the editor’s Component) methods.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement