---
category: swing
folder: NavigateSelectedTab
title: JTabbedPaneのカーソルキーによるタブ選択遷移の動作を変更する
tags: [JTabbedPane, ActionMap, InputMap]
author: aterai
pubdate: 2022-11-07T00:04:34+09:00
description: JTabbedPaneのカーソルキーによるタブ選択遷移を変更してループ不可、またはタブにフォーカスがない場合でも移動可能に設定します。
image: https://drive.google.com/uc?id=14CLheWN2b7q8Q531gPA1Mn1g05BEBuzQ
---
* 概要 [#summary]
`JTabbedPane`のカーソルキーによるタブ選択遷移を変更してループ不可、またはタブにフォーカスがない場合でも移動可能に設定します。

#download(https://drive.google.com/uc?id=14CLheWN2b7q8Q531gPA1Mn1g05BEBuzQ)

* サンプルコード [#sourcecode]
#code(link){{
InputMap im0 = tabs.getInputMap(JComponent.WHEN_FOCUSED);
InputMap im1 = tabs.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
ActionMap am = tabs.getActionMap();

String prev = "navigatePrevious";
am.put(prev, new TabNavigateAction(tabs, am.get(prev)));
im0.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), prev);
im1.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.ALT_DOWN_MASK), prev);
im0.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), prev);
im1.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.ALT_DOWN_MASK), prev);

String next = "navigateNext";
am.put(next, new TabNavigateAction(tabs, am.get(next)));
im0.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), next);
im1.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.ALT_DOWN_MASK), next);
im0.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), next);
im1.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK), next);
// ...
class TabNavigateAction extends AbstractAction {
  private final JTabbedPane tabs;
  private final transient Action action;

  protected TabNavigateAction(JTabbedPane tabbedPane, Action action) {
    super();
    this.tabs = tabbedPane;
    this.action = action;
  }

  @Override public void actionPerformed(ActionEvent e) {
    if (action != null && action.isEnabled()) {
      boolean isWrap = tabs.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT;
      boolean isAltDown = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
      Object name = action.getValue(Action.NAME);
      int base = tabs.getSelectedIndex();
      boolean prev = Objects.equals(name, "navigatePrevious") && base != 0;
      boolean next = Objects.equals(name, "navigateNext") && base != tabs.getTabCount() - 1;
      if (isWrap || isAltDown || prev || next) {
        action.actionPerformed(new ActionEvent(tabs,
            ActionEvent.ACTION_PERFORMED, null,
            e.getWhen(), e.getModifiers()));
      }
    }
  }
}
}}

* 解説 [#explanation]
- タブ自体にフォーカスが存在し、かつタブレイアウトが`JTabbedPane.SCROLL_TAB_LAYOUT`の場合:
-- KBD{←}、KBD{↑}キーにループ不可に設定した`navigatePrevious`アクションを割り当て
-- KBD{→}、KBD{↓}キーにループ不可に設定した`navigateNext`アクションを割り当て
- タブがフォーカスコンポーネントの祖先(タブ自体にフォーカスが存在する場合も含む)の場合:
-- KBD{Alt + ←}、KBD{Alt + ↑}キーにデフォルトの`navigatePrevious`アクションを割り当て
-- KBD{Alt+→}、KBD{Alt+↓}キーにデフォルトの`navigateNext`アクションを割り当て
-- KBD{Alt + →}、KBD{Alt + ↓}キーにデフォルトの`navigateNext`アクションを割り当て

* 参考リンク [#reference]
- [[JTabbedPaneのタブ選択をマウスホイールで変更する>Swing/MouseWheelTabCycling]]
- [[JTabbedPaneのタブスクロールボタンで連続スクロールを実行する>Swing/ScrollTabsActionRepeater]]
- [[JTabbedPaneのタブ選択で表示状態になったタブコンポーネントにフォーカスを移動する>Swing/RequestFocusForVisibleComponent]]

* コメント [#comment]
#comment
#comment