概要

ドラッグ中のカーソル位置をDragSourceMotionListenerで取得し、そこにアイコンを追加したWindowを移動することで、JFrameの外側でもドラッグアイコンを表示します。

サンプルコード

final JWindow window = new JWindow();
window.add(label);
//window.setAlwaysOnTop(true);
//com.sun.awt.AWTUtilities.setWindowOpaque(window, false); // JDK 1.6.0
window.setBackground(new Color(0x0, true)); // JDK 1.7.0
DragSource.getDefaultDragSource().addDragSourceMotionListener(new DragSourceMotionListener() {
  @Override public void dragMouseMoved(DragSourceDragEvent dsde) {
    window.setLocation(dsde.getLocation());
  }
});
view all

解説

上記のサンプルでは、JPanel中に配置したJLabel(アイコン)をDrag & Dropで別のJPanelなど(親のJFrameが異なる場合も可)に移動することができます。ドラッグ中のJLabelは透明化したWindowに配置され、ドラッグに合わせてそのWindowを移動しているので、JFrameの外でもドラッグアイコンが表示可能になっています。 ドラッグ中のカーソル位置取得には、MouseMotionListenerを使用する方法もありますが、このサンプルのようなTransferHandlerを使ったドラッグではMouseMotionListenerでマウスイベントを取得することができないので、DefaultDragSourceDragSourceMotionListenerを追加してドラッグ中のカーソル位置を取得しています。

  • 注:
    • DragSourceDragEvent#getLocation()で取得した位置は、スクリーン座標系なので、そのままWindow#setLocation(...)で使用可能
    • Point pt = tgtLabel.getLocation();で取得したドラッグ対象JLabelの位置は、親コンポーネントの座標系なので、SwingUtilities.convertPointToScreen(pt, parent);で変換する必要がある

参考リンク

コメント

  • OSXなどの場合はどうなるか不明(テストしていない)。 -- aterai
  • OSXでも表示しましたよ。ただクリックした時にアイコン周りに枠が表示されるのですが、その位置がアイコンとずれてます -- nsby
    • ありがとうございます。Bug ID: 4874070 invoking DragSource's startDrag with an Image renders no image on dragあたりの修正の詳しい内容がよく分かっていないので、逆にMac OS Xでは競合する(二重になる)のでは?と思っていました。「アイコン周りの枠」はオフセットを変更するか、クリックした時点でJPanelからは削除してしまえば、何とかなるかもしれません。 -- aterai
  • Web Startで起動すると、window.setAlwaysOnTop(true);AccessControlExceptionが発生するのを修正。 -- aterai
  • ドラッグ中カーソルが点滅するので、dragMouseMoved内で無駄にWindow#setVisible(true);を実行しないように修正(TransferHandler#getSourceActions(...)内でドラッグ開始時に一回だけ実行する)。 -- aterai