概要

JTabbedPaneのスクロールタブレイアウトで矢印ボタンを押下中はスクロールが持続するよう設定します。

サンプルコード

class ActionRepeatHandler extends MouseAdapter implements ActionListener {
  // BasicScrollBarUI scrollSpeedThrottle
  private final static int scrollSpeedThrottle = 60; // delay in milli seconds
  private final Timer timer;
  private final Action action;
  private JButton button;

  protected ActionRepeatHandler(Action action) {
    super();
    this.action = action;
    timer = new Timer(scrollSpeedThrottle, this);
    timer.setInitialDelay(300);
  }

  @Override public void actionPerformed(ActionEvent e) {
    Object o = e.getSource();
    if (o instanceof Timer && button != null) {
      if (!button.getModel().isPressed() && timer.isRunning()) {
        timer.stop();
        button = null;
      } else {
        Component c = SwingUtilities.getAncestorOfClass(JTabbedPane.class, button);
        action.actionPerformed(new ActionEvent(c,
            ActionEvent.ACTION_PERFORMED, null,
            e.getWhen(), e.getModifiers()));
      }
    }
  }

  @Override public void mousePressed(MouseEvent e) {
    if (SwingUtilities.isLeftMouseButton(e) && e.getComponent().isEnabled()) {
      button = (JButton) e.getComponent();
      timer.start();
    }
  }

  @Override public void mouseReleased(MouseEvent e) {
    timer.stop();
    button = null;
  }

  @Override public void mouseExited(MouseEvent e) {
    if (timer.isRunning()) {
      timer.stop();
    }
  }
}
View in GitHub: Java, Kotlin

解説

  • SCROLL_TAB_LAYOUTを設定されたJTabbedPaneのタブスクロールボタンは矢印キーやJScrollBarの矢印ボタンなどとは異なり、連続スクロール機能は実装されていない
  • JTabbedPaneの子要素を検索して前方スクロールボタンと後方スクロールボタンを取得し、それぞれMouseListenerActionListenerを追加
  • MouseListener#mousePressed(...)Timerを起動し、JButton#getModel()#isPressed()とボタンが押下中の場合は対応する前方または後方スクロールアクションを繰り返し実行する
    • 繰り返しの間隔はBasicScrollBarUIprivate final static int scrollSpeedThrottle = 60;と同じ60msに設定
    • 前方または後方スクロールアクションはJTabbedPane#getActionMap().get("scrollTabsForwardAction")JTabbedPane#getActionMap().get("scrollTabsBackwardAction")で取得
    • JTabbedPane間でタブのドラッグ&ドロップ移動ではJButton#doClick()を繰り返し実行してスクロールしているが、このサンプルではMouseListener#mouseReleased(...)イベントでTimerを中断しているのでこの方法は使用できない
    • 代わりにTimerActionEventJTabbedPaneActionEventに変換してAction#actionPerformed(ActionEvent)を実行している

参考リンク

コメント