4

Java でチャット クライアントをプログラミングしていますが、開いているすべてのチャットに対して 1 つの JDialog を使用したいと考えています。そこで、タブが 1 つのチャットを表す JTabbedPane を使用することにしました。

すべてのタブに JPanel を配置しました。これには、メッセージ履歴用の JTextPane と、ユーザーがメッセージを入力する JTextArea が含まれています。

使いやすさを向上させるために、JTextArea にフォーカスする機能を実装しました。

  1. 新しい ChatTab が開かれます
  2. ユーザーが ChatTabs 間で変更されます (JTabbedPane の ChangeListener が起動します)。

JDialog を拡張して JTabbedPane を表示するクラスChatWindowがあります。これは、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;
}
}

ChatTabクラスの focusInputField() メソッドは、単純次のようになります。

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

さて、それはタブが変更されたときのフォーカスです。それに加えて、新しいチャット タブが作成されたときに JTextArea がフォーカスされるようにも実装しました。これはクラスChatWindowControllerで処理されます。ChatWindowクラスに新しいタブを追加するときに呼び出すメソッドsetChatVisible()があります。

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

        chatWindow.focusInputField();
    }
}

ここに私の問題があります。新しいチャットタブを開くとフォーカスが機能します。ほとんどの場合、ユーザーがタブを変更したときにも機能しますが、複数の新しいチャット タブを開いて初めてタブを切り替えると、フォーカスしません。切り替え先のタブの JTextArea がフォーカスされません。ただし、もう一度切り替えると、常に機能します。

問題が何であるかを知っている人はいますか?私は本当にアイデアがありません。

4

1 に答える 1

4

断続的な障害は、不適切な同期が原因である可能性があります。いくつかのことを批判的に検討する必要があります。

  • イベント ディスパッチ スレッド(EDT)ですべての GUI 要素を作成したことを確認します。

  • 複数のスレッドを確実に使用しているため、すべての更新が EDT で行われることを確認してください

  • ここinvokeLater()に示すように、EDT でイベントを注文するために使用できます。

  • よりも優先requestFocusInWindow()requestFocus()ますが、両方を使用しないでください。

于 2013-02-17T16:27:21.440 に答える