Java Swing drag and drop FAQ: How do I get Java/Swing image drag and drop working on Mac OS X?
I've been working on several new Swing applications for Mac OS X recently, and most of these applications include features like image processing, copy and paste clipboard interaction, and in today's example, dealing with drag and drop events on the Mac.
I couldn't get the "typical" Java/Swing drag and drop techniques to work on the Mac ... frankly, I don't know why, and since I solved the problem with a slightly different approach, I don't really care. But I would like to share with you what worked for me.
Getting drag and drop to work with images on Mac OS X
I was able to get drag and drop working on my Mac system using the following code. First, I created a subclass of a JFrame I named my subclass MetaFrame, but you can name yours anything you'd like.
Second, I defined a class variable named dropTarget that is an instance of a DropTarget:
private DropTarget dropTarget;
Next, I created a JPanel, made the background white, instantiated my dropTarget, using the JPanel as an argument to the constructor, and then placed the panel in the content pane of my JFrame:
JPanel panel = new JPanel(); panel.setBackground(Color.WHITE); dropTarget = new DropTarget(panel,new DropTargetImplementation(this, panel)); getContentPane().add(panel, BorderLayout.CENTER);
Next, I created a class named DropTargetImplementation that extends the DropTargetAdapter class, and put this code inside my MetaFrame class. As you can see, this class handles a lot of the heavy lifting:
private class DropTargetImplementation extends DropTargetAdapter
{
MetaFrame metaFrame;
JPanel panel;
public DropTargetImplementation(MetaFrame metaFrame, JPanel panel)
{
this.metaFrame = metaFrame;
this.panel = panel;
}
public void drop(DropTargetDropEvent e)
{
System.err.println("The DropPanel received the DropEvent");
// Called when the user finishes or cancels the drag operation.
Transferable transferable = e.getTransferable();
try
{
if (transferable.isDataFlavorSupported(DataFlavor.imageFlavor))
{
e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
Image image = (Image) transferable.getTransferData(DataFlavor.imageFlavor);
e.getDropTargetContext().dropComplete(true);
metaFrame.addImage(image);
}
else
{
System.err.println("DROP::That wasn't an image!");
e.rejectDrop();
}
}
catch (IOException ioe)
{
ioe.printStackTrace();
e.rejectDrop();
}
catch (UnsupportedFlavorException ufe)
{
ufe.printStackTrace();
e.rejectDrop();
}
}
public void dragEnter(DropTargetDragEvent e)
{
// called when the user is dragging and enters our target
panel.setBackground(Color.GREEN);
}
public void dragExit(DropTargetEvent e)
{
// called when the user is dragging and leaves our target
panel.setBackground(Color.WHITE);
}
public void dragOver(DropTargetDragEvent e)
{
// called when the user is dragging and moves over our target
panel.setBackground(Color.GREEN);
}
} // end of DropTargetImpl class
As you can see from that code, the drop method does most of the hard work. I won't describe it too much here; if you're going to work with image processing a lot you're going to want to learn about the classes used in that method by reading the Javadoc and working with more code samples.
My favorite part about that code -- besides the part where the drag and drop of images actually works -- is turning the background of the panel green when the user is about to drop an image onto the panel/frame. I like applications that actively give this sort of feedback to the user.
What didn't work for me
As mentioned, I didn't get the "traditional" approach to work on my Mac OS X 10.5.7 system, using Java 1.5.0_16. By that I mean that I tried defining an extended JPanel, like this:
public class DropPanel extends JPanel implements DropTargetListener
and then using that DropPanel in my MetaFrame, but it just wouldn't work. In this class I was also trying to highlight my JPanel with a green color when I hovered over the panel/frame with an image that I wanted to drop, but with this code the panel would never turn green. For some reason it wasn't getting the drop event.

