• category: swing folder: TabAreaPopupMenu title: JTabbedPaneのTabAreaで開くJPopupMenuを設定する tags: [JTabbedPane, JPopupMenu] author: aterai pubdate: 2024-01-29T05:46:34+09:00 description: JTabbedPaneのタブ上とTabArea内では異なるJPopupMenuを開くよう設定します。 image: https://drive.google.com/uc?id=1gYHccpOFLZywYrdW0agN_qhRAitbFgtF

概要

JTabbedPaneのタブ上とTabArea内では異なるJPopupMenuを開くよう設定します。

サンプルコード

JTabbedPane tabbedPane = new JTabbedPane() {
  private final JPopupMenu popup1 = makeTabPopupMenu();
  private final JPopupMenu popup2 = makeTabAreaPopupMenu();

  @Override public void updateUI() {
    super.updateUI();
    EventQueue.invokeLater(() -> {
      SwingUtilities.updateComponentTreeUI(popup1);
      SwingUtilities.updateComponentTreeUI(popup2);
      setComponentPopupMenu(popup1);
    });
  }

  @Override public Point getPopupLocation(MouseEvent e) {
    int idx = indexAtLocation(e.getX(), e.getY());
    if (idx < 0 && getTabAreaBounds().contains(e.getPoint())) {
      setComponentPopupMenu(popup2);
    } else {
      setComponentPopupMenu(popup1);
    }
    return super.getPopupLocation(e);
  }

  private Rectangle getTabAreaBounds() {
    Rectangle tabbedRect = getBounds();
    Rectangle compRect = Optional.ofNullable(getSelectedComponent())
        .map(Component::getBounds)
        .orElseGet(Rectangle::new);
    int tabPlacement = getTabPlacement();
    if (isTopBottomTabPlacement(tabPlacement)) {
      tabbedRect.height = tabbedRect.height - compRect.height;
      if (tabPlacement == BOTTOM) {
        tabbedRect.y += compRect.y + compRect.height;
      }
    } else {
      tabbedRect.width = tabbedRect.width - compRect.width;
      if (tabPlacement == RIGHT) {
        tabbedRect.x += compRect.x + compRect.width;
      }
    }
    return tabbedRect;
  }

  private boolean isTopBottomTabPlacement(int tabPlacement) {
    return tabPlacement == TOP || tabPlacement == BOTTOM;
  }
};
View in GitHub: Java, Kotlin

解説

  • タブ上用popup1TabArea内用popup22種類のJPopupMenuを用意
  • JTabbedPane#getPopupLocation(MouseEvent)をオーバーライドしてクリック位置によって使用するJPopupMenuを切り替える
    • JTabbedPane#getPopupLocation(MouseEvent)JTabbedPane#getComponentPopupMenu()nullで未設定の場合は実行されないので、初期状態で適当なJPopupMenuを設定しておく必要がある
    • TabArea内、かつJTabbedPane#indexAtLocation(...)が負でクリック位置がタブ上でない場合はTabArea内用のpopup2JTabbedPane#setComponentPopupMenu(popup2)で設定
    • それ以外の場合はタブ上用のpopup1JTabbedPane#setComponentPopupMenu(popup1)で設定
      • タブコンテナ内のコンポーネントにマウスリスナーが未設定の場合タブ上用のpopup1JPopupMenuとして使用される
  • ひとつのJPopupMenuJPopupMenu#show(invoker, x, y)をオーバーライドし、このxy座標で使用するJMenuItemを入れ替える方法もある
    • どちらを使用する場合も動作中にLookAndFeelを変更する場合は手動でSwingUtilities.updateComponentTreeUI(...)を実行して現在使用していないJPopupMenuJMenuItemLookAndFeelを更新する必要がある
  • JTabbedPane#setTabComponentAt(...)で設定したタブコンポーネントにJPopupMenuを設定して以下のようにJTabbedPane#getComponentPopupMenu()で切り替える方法もあるが、マウスクリックによるタブ移動が不可になる場合がある
@Override public JPopupMenu getComponentPopupMenu() {
  int idx = getSelectedIndex();
  Component c = getTabComponentAt(idx);
  JPopupMenu popup;
  if (idx>= 0 && c instanceof JComponent) {
    popup = ((JComponent) c).getComponentPopupMenu();
  } else {
    popup = super.getComponentPopupMenu();
  }
  return popup;
}

参考リンク

コメント