概要

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

スクリーンショット

Swing/DraggablePopupMenu.png

サンプルコード

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になる場合:

参考リンク

コメント