---
category: swing
folder: ChangeSelectedTabAfterClicking
title: JTabbedPaneの選択タブ切り替えをマウスクリック後に変更する
tags: [JTabbedPane, MouseListener, JButton, JLayer]
author: aterai
pubdate: 2025-10-13T18:07:22+09:00
description: JTabbedPaneの選択タブ切り替えをマウスプレスの直後ではなく、クリック完了後に変更します。
image: https://drive.google.com/uc?id=
image: https://drive.google.com/uc?id=1XQtz40U9LkKgZT2f8Aqtlu-tH8RWt7xM
---
* Summary [#summary]
`JTabbedPane`の選択タブ切り替えをマウスプレスの直後ではなく、クリック完了後に変更します。

#download(https://drive.google.com/uc?id=)
#download(https://drive.google.com/uc?id=1XQtz40U9LkKgZT2f8Aqtlu-tH8RWt7xM)

* Source Code Examples [#sourcecode]
#code(link){{
class TabClickLayerUI extends LayerUI<JTabbedPane> {
  @Override public void installUI(JComponent c) {
    super.installUI(c);
    if (c instanceof JLayer) {
      ((JLayer<?>) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
    }
  }

  @Override public void uninstallUI(JComponent c) {
    if (c instanceof JLayer) {
      ((JLayer<?>) c).setLayerEventMask(0);
    }
    super.uninstallUI(c);
  }

  @Override protected void processMouseEvent(MouseEvent e, JLayer<? extends JTabbedPane> l) {
    JTabbedPane tabs = l.getView();
    if (Objects.equals(tabs, e.getComponent())) {
      if (e.getID() == MouseEvent.MOUSE_CLICKED) {
        updateSelectedTab(tabs, e);
      } else if (e.getID() == MouseEvent.MOUSE_PRESSED) {
        e.consume();
      }
    }
  }

  private static void updateSelectedTab(JTabbedPane tabs, MouseEvent e) {
    int index = SwingUtilities.isLeftMouseButton(e)
        ? tabs.indexAtLocation(e.getX(), e.getY())
        : -1;
    if (index >= 0 && tabs.isEnabledAt(index)) {
      tabs.setSelectedIndex(index);
      if (tabs.isRequestFocusEnabled()) {
        tabs.requestFocus(FocusEvent.Cause.MOUSE_EVENT);
      }
    }
  }
}
}}

* Description [#description]
- 上: デフォルト
-- `JTabbedPane`のデフォルトは`MetalLookAndFeel#createMouseListener(...)`などで生成された`MouseListener`が`mousePressed`イベントを受信したとき、`JTabbedPane#setSelectedIndex(index)`を実行して選択タブが変更される
-- このため、単純に`JTabbedPane`に`MouseListener`を追加しても`MetalLookAndFeel#createMouseListener(...)`で生成した`MouseListener`が先に実行されて動作を変更できない
- 中: `JTabbedPane#setTabComponentAt(...)`でタブコンポーネントを`JButton`に変更
-- タブコンポーネントとして`JButton`を設定し、その`JButton`に`ActionListener`を追加してマウスクリック後に`JTabbedPane#setSelectedIndex(index)`を実行する
-- タブコンポーネントの`JButton`に`MouseMotionListener`を追加し、マウス移動イベントを`JTabbedPane#dispatchEvent(...)`で転送することでロールオーバー状態を更新している
-- タブコンポーネントの`JButton`に`JButton#setInheritsPopupMenu(true)`を設定しても`JTabbedPane`本体に設定した`JPopupMenu`を呼び出せない?
- 下: `JLayer`でラップして`LayerUI#processMouseEvent(...)`をオーバーライド
-- `JTabbedPane`を`JLayer`でラップしてマウスイベントを上書きすることで選択タブ切り替えの挙動を変更する
-- `JTabbedPane`全体を`JLayer`でラップするため、子のタブコンテンツ(このサンプルでは`JScrollPane`や`JTextArea`)へのマウスイベントも上書きしてしまわないよう、`JLayer#getView()`で取得可能なラップされた`JTabbedPane`と`MouseEvent#getComponent()`で取得可能なイベント発生元のコンポーネントが同一の場合のみマウスイベントを上書きしている
--- `MouseEvent.MOUSE_PRESSED`の場合は`MouseEvent#consume()`を実行して消費して`MetalLookAndFeel#createMouseListener(...)`で生成した`MouseListener`の`mousePressed`を処理されないようにする
--- `MouseEvent.MOUSE_CLICKED`の場合は`JTabbedPane#setSelectedIndex(index)`を実行して選択タブを切り替える
-- マウスプレス後にマウスカーソル位置を変更するとクリックイベントが発生しないので、これを変更する場合は`MouseEvent.MOUSE_RELEASED`が対象タブ領域内で発生したら選択タブを切り替えるよう修正する必要がある

* Reference [#reference]
- [[JTabbedPaneのタブをマウスの中ボタンクリックで閉じる>Swing/MaskForButton]]
- [[JTabbedPaneのタブエリアをダブルクリックして新規タブを作成する>Swing/DoubleClickInTabAreaToCreateNewTab]]

* Comment [#comment]
#comment
#comment