Mac Java - Image drag and drop

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.