JTabbedPaneの選択タブ切り替えをマウスクリック後に変更する
Total: 87, Today: 2, Yesterday: 0
Posted by aterai at
Last-modified:
Summary
JTabbedPaneの選択タブ切り替えをマウスプレスの直後ではなく、クリック完了後に変更します。
Screenshot

Advertisement
Source Code Examples
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);
}
}
}
}
View in GitHub: Java, KotlinDescription
- 上: デフォルト
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が対象タブ領域内で発生したら選択タブを切り替えるよう修正する必要がある