Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Focus-requests when switching tabs in JTabbedPane

843804Jun 2 2003 — edited Mar 19 2009
I have a tabbed pane with a JTextArea in each tab. I would like to switch focus to the corresponding area each time I select a tab or create a new one. A ChangeListener can detect tab selections and call requestFocusInWindow() on the newly chosen tab's text area.

For some reason, the focus only switches sporadically. Sometimes the caret appears to stay, sometimes it only blinks once, and sometimes it never appears. My friend's workaround is to call requestFocusInWindow() again after the setSelectedIndex() calls, along with a Thread.sleep() delay between them. Oddly, in my test application the delay and extra focus-request call are only necessary when creating tabs automatically, rather than through a button or shortcut key.

Does the problem lie in separate thread access on the same objects? I tried using "synchronized" to no avail, but EventQueue.invokeLater() on the focus request worked. Unfortunately, neither the delay nor invokeLater worked in all situations in my real-world application. Might this be a Swing bug, or have I missed something?

Feel free to tinker with my test application:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;

/**Creates a tabbed pane with scrollable text areas in each tab.
 * Each time a tab is created or selected, the focus should switch to the
 * text area so that the cursor appears and the user can immediately type
 * in the area.
 */
public class FocusTest2 extends JFrame {
	private static JTabbedPane tabbedPane = null;
	private static JTextArea[] textAreas = new JTextArea[100];
	private static int textAreasIndex = 0;
	private static JButton newTabButton = null;

	/**Creates a FocusTest2 object and automatically creates several
	 * tabs to demonstrate the focus switching.  A delay between creating
	 * the new tab and switching focus to it is apparently necessary to
	 * successfully switch the focus.  This delay does not seem to be
	 * necessary when the user fires an action to create new tabs, though.
	 * @param args
	 */
	public static void main(String[] args) {
		FocusTest2 focusTest = new FocusTest2();
		focusTest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		focusTest.show();
		//Opens several tabs.
		for (int i = 0; i < 4; i++) {
			try {
				//adding the tab should automatically invoke setFocus()
				//through the tabbed pane's ChangeListener, but for some
				//reason the focus often doesn't switch or at least doesn't
				//remain in the text area.  The workaround is to pause
				//for a moment, then call setFocus() directly 
				addTabbedPaneTab();
				//without this delay, the focus only switches sporadically to
				//the text area
				Thread.sleep(100);
				setFocus();
				//extra delay simply for the user to view the tab additions
				Thread.sleep(1900); 
			} catch (InterruptedException e) {
			}
		}
	}

	/**Adds a new tab, titling it according to the index of its text area.
	 * Using "synchronized" here doesn't seem to solve the focus problem.
	 */
	public static void addTabbedPaneTab() {
		if (textAreasIndex < textAreas.length) { //ensure that array has room
			textAreas[textAreasIndex] = new JTextArea();
			//title text area with index number
			tabbedPane.addTab(
				textAreasIndex + "",
				new JScrollPane(textAreas[textAreasIndex]));
			tabbedPane.setSelectedIndex(textAreasIndex++);
		}
	}

	/**Constructs the tabbed pane interface.
	 */
	public FocusTest2() {
		setSize(300, 300);
		tabbedPane = new JTabbedPane();
		//Action to create new tabs
		Action newTabAction = new AbstractAction("New") {
			public void actionPerformed(ActionEvent evt) {
				addTabbedPaneTab();
			}
		};
		//in my real-world application, adding new tabs via a button successfully
		//shifted the focus, but doing so via the shortcut key did not;
		//both techniques work here, though
		newTabAction.putValue(
			Action.ACCELERATOR_KEY,
			KeyStroke.getKeyStroke("alt T"));
		newTabAction.putValue(Action.SHORT_DESCRIPTION, "New");
		newTabAction.putValue(Action.MNEMONIC_KEY, new Integer('T'));
		newTabButton = new JButton(newTabAction);
		Container container = getContentPane();
		container.add(tabbedPane, BorderLayout.CENTER);
		container.add(newTabButton, BorderLayout.SOUTH);

		//switch focus to the newly selected tab, including newly created ones
		tabbedPane.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent evt) {
				//note that no delay is necessary for some reason
				setFocus();
			}
		});
	}

	/**Sets the focus onto the selected tab's text area.  The cursor should
	 * blink so that the user can start typing immediately.  In tests without
	 * the delay during the automatic tab creation in main(), the cursor 
	 * sometimes only blinked once in the text area.
	 */
	public static void setFocus() {
		if (tabbedPane == null) //make sure that the tabbed Pane is valid
			return;
		int i = tabbedPane.getSelectedIndex();
		if (i < 0) //i returns -1 if nothing selected
			return;
		int index = Integer.parseInt(tabbedPane.getTitleAt(i));
		textAreas[index].requestFocusInWindow();
	}

}
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Apr 16 2009
Added on Jun 2 2003
9 comments
991 views