I have a class that is a custom swing component that extends JComponent. I am trying to make it so that the subcomponents of this custom component will be focus traversable by simply pressing TAB or SHIFT+TAB. Instead, they only seem to be traversable by pressing CTRL+TAB or CTRL+SHIFT+TAB by default no matter what I specify otherwise. I have referred to the answer from here although my component is not a JTextArea, and I have tried setting the focus traverse keys directly with the code below in the constructor, but to no avail.
setFocusCycleRoot(true);
setFocusTraversalKeysEnabled(true);
Set<AWTKeyStroke> forwardKeys = new HashSet<>();
forwardKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys);
Set<AWTKeyStroke> backwardKeys = new HashSet<>();
backwardKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK));
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, backwardKeys);
I also tried to add a key listener to the component to effectively do the same thing with the code below, but that also did not work.
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_TAB) {
if (e.isShiftDown()) {
transferFocusBackward();
} else {
transferFocus();
}
e.consume();
}
}
});
I find that I get exactly the behavior I want if I do not include either of the code blocks above, but rather override the isManagingFocus() method to always return true, but I would rather not do this as isManagingFocus() is deprecated.
Yes, I know this question is five years old, and yes, I know that I'm the one who originally submitted it. However, I have returned to this issue and finally found a way to solve it. The main impetus behind this question was to preserve the functionality of a component while eliminating the use of deprecated code. The isManagingFocus()
method of JComponent
is deprecated, but overriding it to always return "true" caused a component to be focus traversable by TAB and SHIFT+TAB, without the CTRL key, which is the functionality that I wanted to preserve.
Looking at the source code for the JComponent
constructor where isManagingFocus()
was called, I found a way to adapt that code in a non-deprecated way in my custom component's constructor that would preserve the same behavior that the component had before. I was surprisingly close in my attempt five years ago, basically missing the additional InputEvent.CTRL_DOWN_MASK
modifier when setting the focus keys. Here is what I did:
Set<KeyStroke> managingFocusForwardTraversalKeys;
Set<KeyStroke> managingFocusBackwardTraversalKeys;
synchronized (JComponent.class) {
managingFocusForwardTraversalKeys = new HashSet<KeyStroke>(1);
managingFocusForwardTraversalKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.CTRL_DOWN_MASK));
managingFocusBackwardTraversalKeys = new HashSet<KeyStroke>(1);
managingFocusBackwardTraversalKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK));
}
//The old deprecated way of doing this that isManagingFocus() would trigger in the JComponent constructor.
//LookAndFeel.installProperty(this, "focusTraversalKeysForward", managingFocusForwardTraversalKeys);
//LookAndFeel.installProperty(this, "focusTraversalKeysBackward", managingFocusBackwardTraversalKeys);
//The new way of doing this
setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, managingFocusForwardTraversalKeys);
setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, managingFocusBackwardTraversalKeys);