---
category: swing
folder: DraggableToolTip
title: JToolTipの表示位置をマウスドラッグで変更可能にする
tags: [JToolTip, JPopupMenu]
tags: [JToolTip, JPopupMenu, MouseListener, JLabel, JWindow]
author: aterai
pubdate: 2025-08-04T01:44:23+09:00
description: JToolTipを親にして背景色などをJToolTip風に設定したJPopupMenuを作成し、その内部に配置したJLabelをドラッグして表示位置を変更します。
image: https://drive.google.com/uc?id=1T8mhF2H2r51ljwO7NFHvbpUY0AS7kLUD
---
* Summary [#summary]
JToolTipを親にして背景色などをJToolTip風に設定したJPopupMenuを作成し、その内部に配置したJLabelをドラッグして表示位置を変更します。
`JToolTip`を親にして背景色などを`JToolTip`風に設定した`JPopupMenu`を作成し、その内部に配置した`JLabel`をドラッグして表示位置を変更します。

#download(https://drive.google.com/uc?id=1T8mhF2H2r51ljwO7NFHvbpUY0AS7kLUD)

* Source Code Examples [#sourcecode]
#code(link){{
class ToolTipEditorPane extends JEditorPane {
  private final JPanel panel;

  protected ToolTipEditorPane(JPanel panel) {
    super();
    this.panel = panel;
  }

  @Override public JToolTip createToolTip() {
    JToolTip tip = super.createToolTip();
    tip.addHierarchyListener(e -> {
      boolean showing = e.getComponent().isShowing();
      if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && showing) {
        panel.setBackground(tip.getBackground());
        Container p = SwingUtilities.getAncestorOfClass(JPopupMenu.class, panel);
        if (p instanceof JPopupMenu) {
          // ((JPopupMenu) p).setLightWeightPopupEnabled(false);
          ((JPopupMenu) p).show(tip, 0, 0);
        }
      }
    });
    return tip;
  }
}

class DragLabel extends JLabel {
  private transient MouseAdapter handler;

  @Override public void updateUI() {
    removeMouseListener(handler);
    removeMouseMotionListener(handler);
    super.updateUI();
    handler = new PopupDragListener();
    addMouseListener(handler);
    addMouseMotionListener(handler);
    Color bgc = UIManager.getColor("ToolTip.background");
    if (bgc != null) {
      setBackground(bgc.darker());
    }
    setOpaque(true);
  }

  @Override public Dimension getPreferredSize() {
    return new Dimension(16, 64);
  }
}

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

  @Override public void mousePressed(MouseEvent e) {
    if (SwingUtilities.isLeftMouseButton(e)) {
      Component c = e.getComponent();
      Container popup = SwingUtilities.getAncestorOfClass(JPopupMenu.class, c);
      SwingUtilities.convertMouseEvent(c, e, popup);
      startPt.setLocation(e.getPoint());
    }
  }

  @Override public void mouseDragged(MouseEvent e) {
    if (SwingUtilities.isLeftMouseButton(e)) {
      Component c = e.getComponent();
      Window w = SwingUtilities.getWindowAncestor(c);
      // Popup$HeavyWeightWindow
      if (w != null && w.getType() == Window.Type.POPUP) {
        Point pt = e.getLocationOnScreen();
        w.setLocation(pt.x - startPt.x, pt.y - startPt.y);
      }
    }
  }
}
}}

* Description [#description]
- `JToolTip`が表示状態になったらその`JToolTip`を親にして`JPopupMenu#.show(tip, 0, 0)`で`JPopupMenu`を表示するよう`JEditorPane#createToolTip()`をオーバーライド
-- [[JToolTipの文字列を選択・コピー可能にする>Swing/SelectableToolTip]]と同様の方法
- `JPopupMenu`にドラッグ可能な`JLabel`を配置
-- [[JPopupMenuにマウスドラッグで位置変更を可能にするヘッダを追加する>Swing/DraggablePopupMenu]]の`MouseAdapter`とほぼ同一だが、親が`JFrame`などではなく`JToolTip`になるので`LightWeightWindow`を使用する`JPopupMenu`で位置変更ができない
-- これを回避するため、`JPopupMenu#setLightWeightPopupEnabled(false)`で常に`HeavyWeightWindow`を使用して`JPopupMenu`を開くよう設定

* Reference [#reference]
- [[JToolTipの文字列を選択・コピー可能にする>Swing/SelectableToolTip]]
- [[JPopupMenuにマウスドラッグで位置変更を可能にするヘッダを追加する>Swing/DraggablePopupMenu]]

* Comment [#comment]
#comment
#comment