• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JFrameの外側でもドラッグアイコンを表示する
#navi(../)
#tags(DragAndDrop, JWindow, ImageIcon, JFrame)
RIGHT:Posted by &author(aterai); at 2012-08-06
*JFrameの外側でもドラッグアイコンを表示する [#c4f3f6cb]
ドラッグ中のカーソル位置をDragSourceMotionListenerで取得し、そこにアイコンを追加したWindowを移動することで、JFrameの外側でもドラッグアイコンを表示します。
ドラッグ中のカーソル位置を``DragSourceMotionListener``で取得し、そこにアイコンを追加した``Window``を移動することで、``JFrame``の外側でもドラッグアイコンを表示します。

-&jnlp;
-&jar;
-&zip;

//#screenshot
#ref(https://lh4.googleusercontent.com/-HM5QzW5AZlk/UB9iFlbSZMI/AAAAAAAABQM/fggojAo0b-E/s800/DragSourceMotionListener.png)

**サンプルコード [#f394f0f4]
#code(link){{
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(0, true)); // JDK 1.7.0
DragSource.getDefaultDragSource().addDragSourceMotionListener(new DragSourceMotionListener() {
  @Override public void dragMouseMoved(DragSourceDragEvent dsde) {
    window.setLocation(dsde.getLocation());
    window.setVisible(true);
  }
});
}}

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

-注: DragSourceDragEvent#getLocation() で取得できる位置は、スクリーン上でのマウス位置なので、MouseEvent#getPoint() の場合のようにSwingUtilities.convertPointToScreen(pt, c); で変換しなくて良い 
-注: ``DragSourceDragEvent#getLocation()``で取得できる位置は、スクリーン上でのマウス位置なので、``MouseEvent#getPoint()``の場合のように``SwingUtilities.convertPointToScreen(pt, c);``で変換しなくて良い 

**参考リンク [#jda9a30f]
- [[JLayerを使ってJTabbedPaneのタブの挿入位置を描画する>Swing/DnDLayerTabbedPane]]

**コメント [#y921464d]
- OSXなどの場合はどうなるか不明(テストしていない)。 -- [[aterai]] &new{2012-08-06 (月) 15:50:35};
- OSXでも表示しましたよ。ただクリックした時にアイコン周りに枠が表示されるのですが、その位置がアイコンとずれてます -- [[nsby]] &new{2012-08-07 (火) 11:04:46};
-- ありがとうございます。[http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4874070 Bug ID: 4874070 invoking DragSource's startDrag with an Image renders no image on drag]あたりの修正の詳しい内容がよく分かっていないので、逆にMac OS Xでは競合する(二重になる)のでは?と思っていました。「アイコン周りの枠」はオフセットを変更するか、クリックした時点でJPanelからは削除してしまえば、何とかなるかもしれません。 -- [[aterai]] &new{2012-08-07 (火) 14:19:12};
-- ありがとうございます。[http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4874070 Bug ID: 4874070 invoking DragSource's startDrag with an Image renders no image on drag]あたりの修正の詳しい内容がよく分かっていないので、逆にMac OS Xでは競合する(二重になる)のでは?と思っていました。「アイコン周りの枠」はオフセットを変更するか、クリックした時点で``JPanel``からは削除してしまえば、何とかなるかもしれません。 -- [[aterai]] &new{2012-08-07 (火) 14:19:12};
- Web Start で起動すると、``window.setAlwaysOnTop(true);``で``AccessControlException``が発生するのを修正。 -- [[aterai]] &new{2012-12-07 (金) 18:20:23};

#comment