I noticed a strange focus traversal behavior of JTabbedPane.
During tab traversal (when the user's intention is just to switch between tabs), the focus is transferred to a component outside of the tabs (if there is a component after/below the JTabbedPane component), if using Java 6. For example, if using the SSCCE below...
import java.awt.BorderLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class TabbedPaneTest extends JPanel {
public TabbedPaneTest() {
super(new BorderLayout());
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Tab 1", buildPanelWithChildComponents());
tabbedPane.setMnemonicAt(0, KeyEvent.VK_1);
tabbedPane.addTab("Tab 2", buildPanelWithChildComponents());
tabbedPane.setMnemonicAt(1, KeyEvent.VK_2);
tabbedPane.addTab("Tab 3", buildPanelWithChildComponents());
tabbedPane.setMnemonicAt(2, KeyEvent.VK_3);
tabbedPane.addTab("Tab 4", buildPanelWithChildComponents());
tabbedPane.setMnemonicAt(3, KeyEvent.VK_4);
JPanel panel = new JPanel(new BorderLayout());
panel.add(tabbedPane);
JButton button = new JButton("Dummy component that gains focus when switching tabs");
panel.add(button, BorderLayout.SOUTH);
/*
* To replicate the focus traversal issue, please follow these steps -
* 1) Run this program in Java 6; and then
* 2) Click on a child component inside any tab; and then
* 3) Click on any other tab (or use the mnemonic keys ALT + 1 to ALT 4).
*/
button.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
System.err.println("Gained focus (not supposed to when just switching tabs).");
}
});
add(new JScrollPane(panel));
}
private JPanel buildPanelWithChildComponents() {
JPanel panel = new JPanel();
BoxLayout boxlayout = new BoxLayout(panel, BoxLayout.PAGE_AXIS);
panel.setLayout(boxlayout);
panel.add(Box.createVerticalStrut(3));
for (int i = 0; i < 4; i++) {
panel.add(new JTextField(10));
panel.add(Box.createVerticalStrut(3));
}
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Test for Java 6");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TabbedPaneTest());
frame.pack();
frame.setVisible(true);
}
});
}
}
... Then we can replicate this behavior by following these steps:
3) Click on any other tab (or use the mnemonic keys 'ALT + 1' to 'ALT + 4').
At step 3 (upon selecting any other tab), the focus would go to the component below the JTabbedPane first (hence the printed message in the console), before actually going to the selected tab.
This does not occur in Java 7, so I'm assuming it is a bug that is fixed. And I know that Oracle suggests that we should use Java 7 nowadays.
The problem is: We need to stick to Java 6 for a certain application. So I'm looking for a way to fix this issue for all our JTabbedPane components while using Java 6.
So, is there a way to prevent JTabbedPanes from passing the focus to components outside of the tabs during tab traversal (e.g. when users are just switching between tabs), in Java 6?
Note: I've read the release notes between Java 6u45 to Java 7u15, but I was unable to find any changes related to the JTabbedPane component. So any pointers on this would be deeply appreciated.