Search code examples
javaswingfocusjtabbedpanechangelistener

Focusing a JTextArea in a JTabbedPane


I'm programming a chat client in Java, where I'd like to have one single JDialog for all open chats. So I decided to work with a JTabbedPane where a tab represents a single chat.

I put a JPanel into every tab, which simply contains a JTextPane for the message history and a JTextArea where users input their messages.

For a better usability I implemented a feature that focuses the JTextArea when

  1. a new ChatTab is opened
  2. the user changes between the ChatTabs (the ChangeListener of the JTabbedPane fires)

I have a class ChatWindow, which extends JDialog and displays the JTabbedPane. This is where I implemented the ChangeListener.

private JTabbedPane chatTabPane;
private List<ChatTab> chatTabs;

public ChatWindow() {
    chatTabs = new ArrayList<ChatTab>();

    JPanel chatWindowPanel = new JPanel(new BorderLayout());

    chatTabPane = new JTabbedPane(JTabbedPane.TOP);
    chatWindowPanel.add(chatTabPane);

    this.add(chatWindowPanel, BorderLayout.CENTER);

    chatTabPane.addChangeListener(new ChangeListener() {

        @Override
        public void stateChanged(ChangeEvent arg0) {
            focusInputField();
        }
    });
}

public ChatTab addChatTab(Contact contact) {
    ChatTab newChatTab = new ChatTab();
    chatTabs.add(newChatTab);
    chatTabPane.addTab(contact.toString(), null, newChatTab.getPanel());
    return newChatTab;
}

public void focusInputField() {
    for (ChatTab chatTab : chatTabs) {
        if(chatTab.getPanel() == chatTabPane.getSelectedComponent()) {
            chatTab.focusInputField();
        }
    }
}

public JTabbedPane getChatTabs() {
    return chatTabPane;
}
}

The method focusInputField() in the class ChatTab simply looks like this:

public void focusInputField() {
    inputField.requestFocusInWindow();
    inputField.requestFocus();
}

Okay, that's for the focus when the tab is changed. Beside that, I have also implemented that the JTextArea is focused when a new chat tab is created. That is handled in the class ChatWindowController. There is a method setChatVisible() that I call when I add a new tab to the ChatWindow class:

public void setChatVisible() {
    if(!chatWindow.isVisible()) {
        chatWindow.setVisible(true);

        chatWindow.focusInputField();
    }
}

So here is my problem: The focus works when I open a new chattab. In most cases it also works when the user changes the tabs, BUT it does not focus when I opened more than one new chat tab and switch between the tabs FOR THE FIRST TIME. The JTextArea of the tab where I switched to does not focus. However, when I switch again it works all the time.

Does anyone know what the problem could be? I'm really out of ideas.


Solution

  • Intermittent failure may result from incorrect synchronization. Several thing should be examined critically:

    • Verify that you construct all GUI elements on the event dispatch thread (EDT).

    • As you are surely using multiple threads, verify that all updates occur on the EDT, for example.

    • You can use invokeLater() to order events on the EDT, as shown here.

    • Prefer requestFocusInWindow() over requestFocus(), but don't use both.