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.