11

JTable's default behavior is changing focus to next cell and I want to force it to move focus to next component (e.g. JTextField) on TAB key pressed.
I overrided isCellEditable method of DefaultTableModel to always return false:

public boolean isCellEditable(int rowIndex, int columnIndex) {
    return false;
}

But it still doesn't change focus to next component!
How should I make JTable change focus to next component instead of next cell?

Ariyan
  • 14,760
  • 31
  • 112
  • 175
  • are we talking about Focus 1) inside JTable betweens cells 2) moving focus from JTable to (for example) JTextField and vice versa – mKorbel Aug 28 '12 at 07:39
  • @mKorbel: #2 , JTable's default behavior is changing focus to next cell and I want to force it to move focus to next component (e.g. `JTextField`) on TAB key pressed. – Ariyan Aug 28 '12 at 07:42

4 Answers4

15

The shift-/tab keys are used by default for transfering focus between components. JTable explicitly requests to handle the shift-/tab internally (by providing sets of focusTraversalKeys which doesn't include those).

Following the general rule (if there's specilized api available for a task, use that instead of rolling your own), the solution is to set traversal keys to again contain them:

Set<AWTKeyStroke> forward = new HashSet<AWTKeyStroke>(
        table.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
forward.add(KeyStroke.getKeyStroke("TAB"));
table.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forward);
Set<AWTKeyStroke> backward = new HashSet<AWTKeyStroke>(
        table.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
backward.add(KeyStroke.getKeyStroke("shift TAB"));
table.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backward);
Mike Argyriou
  • 1,250
  • 2
  • 18
  • 30
kleopatra
  • 51,061
  • 28
  • 99
  • 211
7

If you really want this, you need to change the default behavior of the tables action map.

ActionMap am = table.getActionMap();
am.put("selectPreviousColumnCell", new PreviousFocusHandler());    
am.put("selectNextColumnCell", new NextFocusHandler());    

Then you need a couple of actions to handle the traversal

public class PreviousFocusHandler extends AbstractAction {
    public void actionPerformed(ActionEvent evt) {
        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        manager.focusPreviousComponent();
    }
}

public class NextFocusHandler extends AbstractAction {
    public void actionPerformed(ActionEvent evt) {
        KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
        manager.focusNextComponent();
    }
}

Another approach would be to disable the underlying Action...

ActionMap am = table.getActionMap();
am.get("selectPreviousColumnCell").setEnabled(false);
am.get("selectNextColumnCell").setEnabled(false);

(haven't tested this)

The benefit of this approach is can enable/disable the behaviour as you need it without needing to maintain a reference to the old Actions

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
5
mKorbel
  • 109,525
  • 20
  • 134
  • 319
4

To reset to the standard keyboard bindings (typically TAB and SHIFT+TAB), simply specify null for the keystrokes parameter to Component.setFocusTraversalKeys:

table.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
table.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
Rangi Keen
  • 935
  • 9
  • 29