• category: swing folder: DraggablePopupMenu title: JPopupMenuにマウスドラッグで位置変更を可能にするヘッダを追加する tags: [JPopupMenu, MouseListener, JLabel, JWindow] author: aterai pubdate: 2022-10-31T00:03:07+09:00 description: JPopupMenuにJLabelで作成したヘッダを追加し、MouseListenerを追加してドラッグで位置変更を可能にします。 image: https://drive.google.com/uc?id=1bT2wG0hF2SSjNYBY5t23Xl-8_WCRHdPO hreflang:
       href: https://java-swing-tips.blogspot.com/2022/10/add-header-to-jpopupmenu-to-enable.html
       lang: en

概要

JPopupMenuJLabelで作成したヘッダを追加し、MouseListenerを追加してドラッグで位置変更を可能にします。

サンプルコード

class PopupHeaderMouseListener extends MouseAdapter {
  private final Point startPt = new Point();

  @Override public void mousePressed(MouseEvent e) {
    if (SwingUtilities.isLeftMouseButton(e)) {
      startPt.setLocation(e.getPoint());
    }
  }

  @Override public void mouseDragged(MouseEvent e) {
    Component c = e.getComponent();
    Window w = SwingUtilities.getWindowAncestor(c);
    if (w != null && SwingUtilities.isLeftMouseButton(e)) {
      if (w.getType() == Window.Type.POPUP) { // Popup$HeavyWeightWindow
        Point pt = e.getLocationOnScreen();
        w.setLocation(pt.x - startPt.x, pt.y - startPt.y);
      } else { // Popup$LightWeightWindow
        Container popup = SwingUtilities.getAncestorOfClass(
            JPopupMenu.class, c);
        Point pt = popup.getLocation();
        popup.setLocation(pt.x - startPt.x + e.getX(), pt.y - startPt.y + e.getY());
      }
    }
  }
}
View in GitHub: Java, Kotlin

解説

  • JPopupMenuのデフォルトレイアウトは垂直BoxLayoutなので、ヘッダとして使用するJLabelgetMaximumSize()をオーバーライドして最大幅をJPopupMenuの推奨幅以上に設定しておく
  • JPopupMenuが親JFrame外に表示されてPopup$HeavyWeightWindowになる場合
    • MouseEvent#getLocationOnScreen()で取得したデスクトップ領域の絶対位置にSwingUtilities.getWindowAncestor(header)で取得したJPopupMenuの親Windowを移動
    • JWindowをマウスで移動
  • JPopupMenuが親JFrame内に表示されてPopup$LightWeightWindowになる場合

参考リンク

コメント