Java Drag and Drop FAQ
Version 0.9
Here are the Frequently Asked Questions (FAQ) we've encountered in our Java Training seminars. Right now it is incomplete. It has not been updated for the JDK 1.4 improvements.
This document is Copyright 1998-1999 by Gene De Lisa and Rockhopper Technologies. Since we cannot maintain zillions of copies on websites we cannot even know about, mirroring this document is not allowed. Reproduction for you own use, and redistribution is allowed as long as this copyright is maintained. You may not make slight modifications and claim authorship or publish it.
The current HTML version is always available at http://www.rockhoppertech.com/
Answers
Introduction
What is Drag and Drop? (DnD)
It's not a dumb question. DnD is a data transfer API. The user transfers the data from one place to another by using the mouse (usually). One selects something with a mouse press, drags it (moves the mouse while keeping the mouse button pressed) and releases the mouse button someplace else. When the button is released the data is "dropped" at that location. The confusion is the use of the term in GUI builders. In those apps you can drag a component and place it someplace inside a container. You can do that with DnD too but you must realize that the "data" that is being transferred in this case is the (sometimes serialized) GUI bean. You don't need DnD if you simply want to drag images or components around a container.
Do I need Java 2 to use Drag and Drop?
Yes! You can drag components or graphics around a GUI in releases before Java 2 but that is not drag and drop. Remember that it is a data transfer API. IBM has a 1.1 DnD Bean that is really a workaround. You can get it at
http://www.alphaworks.ibm.com/ab.nsf/jbName/E4F2891D1D606E208525674C00682447
Do I need to use Swing (JFC components) to use Drag and Drop?
No. you can use DnD with heavyweight AWT components.
Applets
Can I use DnD with Applets?
Sort of. As of JDK1.2.1 you can drag from an Applet but not drop into one unless you do not create the drop targets in init or start. There is an example in the Rockhopper DnD library.
What sort of Applet security policy is needed?
Here is an example policy:
grant {
permission java.awt.AWTPermission "accessEventQueue";
permission java.awt.AWTPermission "setDropTarget";
permission java.awt.AWTPermission "accessClipboard";
permission java.awt.AWTPermission "acceptDropBetweenAccessControllerContexts";
permission java.awt.AWTPermission "listenToAllAWTEvents";
};
How do I set the applet security policy?
That's really not just a DnD question. This will do it with appletviewer:
appletviewer -J-Djava.security.policy=policy index.html
Operations
How can I implement a link operation?
One way is to transfer some sort or URI. This works fine between Java VMs or within the same VM. There is no way this can happen with native apps though. The spec. recomends against it.
Dragging
How do I drag from a component?
Easy question, long answer. You have to start by asking these questions:
- What is the data being transferred?
- Does a Transferable exist for your data?
- What actions make sense. Move, copy, link?
- Is it always going to be the same data type for this component?
- Is the UI delegate composed of several other components? (e.g. JFileChooser)
- Are you going to also drop on this component?
Once you've answered these questions you associate the Component with a DragSource, a DragSourceListener, a DragGestureListener and a Transferable for the data.
What is a good way to associate the required objects?
The worst way is to make your subclass implement all of the interfaces.
class DnDLabel extends JLabel
implements
DragSourceListener,
DragGestureListener,
Transferable,
PartrigeInAPearTree {}
This is similar to classes designed by OO beginners that have a single method of 10000 lines named "doit".
In this example you are saying that DnDLabel "behaves like a" DragSourceListener, DragGestureListener, and Transferable encouraging use in those roles by other components.
class Yeesh ... {
...
this.dragSource.createDefaultDragGestureRecognizer(
this,
DnDConstants.ACTION_COPY_OR_MOVE,
new DnDLabel() ); ???????????????????
You'd probably not do that so why say that it's possible? Another reason is you cannot reuse the DnDLabel very well as a Transferable. It would be better to create reusable Transferables for different datatypes (e.g. StringTransferable, BeanTransferable etc)
There are two better ways to do it. One way is to define inner classes for the listeners. They will have access to the outer class data, the code is modular (responsibilities are clear) and modeled correctly (you don't have the problems as in the first example). The DragGestureListener will get the "raw" data from the outer class and create a Transferable with it. (If the data is a String, it will create a StringTransferable passing the String into the constructor).
The other way is to create reusable adapters for the listeners that hold references to the GUI component. This is the approach taken in Rockhopper Technologies free DnD toolkit.
How do I make the drag image work?
You are probably using Windows if you can't. Ask the guys in Redmond why you can't. The safe way to try to do it is like this:
if(DragSource.isDragImageSupported() )
e.startDrag(this.cursor,
this.dragImage,
this.point,
transferable,
dsListener);
P.S. I read the system requirements label on a software package recently. It said "requires Windows NT or better". So I installed Unix.
When I drag from my own JFileChooser I cannot initiate the drag over any of the components!
If you subclass JFileChooser for use with DnD you can initiate a drag only where no components are showing. If you'd like to drag from anywhere there are two solutions. One is to write your own UI delegate and replace the list and combo box with your own DnD enabled versions. It's not too hard but the Metal authors haven't made it easy to subclass their UI. You'd have to copy the src and modify it. The second way is the glass pane trick.
Are there any good online tutorials on Java DnD?
Why yes. Here is the best one to start with. The second article in the series is here
Why bother with a DragGestureListener instead of just processing Mouse events?
The mouse gestures that initiate a DnD operation vary on different platforms. The DragGestureListener actually saves you a lot of work.
What are drag over effects?
They are cursor changes. If the cursor is over a drop site but the operation or DataFlavors won't be accepted, the cursor can use an international negation symbol through the "operation" cursor. By default the cursors used are similar to the native platform's cursors for each operation. Constants for them are defined in DragSource.
Can I use my own cursors?
Sure. Sort of. On Win32 (at least) you need to set the DragContext's cursor to null and then to your cursor in dragOver. Otherwise the default cursors will be set and then yours producing an annoying flicker. I don't know if this is a "feature".
What is the glass pane "trick"?
There are times you cannot use your DnD enabled classes. The Components in a JFileChooser for example are created by the UI delegate. (You could write your own delegate.) If you replace the JRootPane's glass pane with your own JPanel that has DnD capabilities you can forward the non DnD events to the content pane's children but intercept the DnD events. The hard part (but not impossible) is handling popups (both regular popups along with JMenus and JComboBoxes).
Dropping
How do I create a droppable component?
You need to associate it with two objects. A DropTarget and a DropTargetListener. Then you need to decide what DataFlavors and actions you'd like to accept.
What does the DropTargetListener do for me?
It does most of the work! It notifies the component to display "drag under effects", checks the validity of the current flavor and operation and handles the actual data transfer (the drop).
What are drag under effects?
They are visual cues provided by the GUI component. They can tell the user that:
- The cursor is or isn't over a dropsite
- The current operation is valid or invalid
- The current DataFlavor is valid or invalid
Simple ways to provide these effects are
- Modifying the Component's border
- Setting the selection (JList, JTree etc.)
How do I associate a Component with a DropTarget?
There a few ways. If you are making a subclass of a Component (e.g. MyDropTree) then you can pass a "this" reference into the DropTarget's constructor. If you are using the DropTarget with several components you can use these java.awt.Component methods:
public void setDropTarget(DropTarget dt); public DropTarget getDropTarget();
Can I DnD within the same component?
Sure! Just associate it with a DragSource, DropTarget and the usual gang of Listeners. One thing to think about is what does the copy action mean? For example if you copy one node of a JTree to another branch within the same JTree do you want to do a clone or copy on the drop. The usual answer is clone.
Transferables
Can I drag and drop my own objects?
Yes, if your class is Serializable. You need to define two DataFlavors and probably a Transferable.
public class Rockhopper extends Bird implements Serializable {
private String name; // String is serializable
private Image mugShot; // Cannot do this. Image is not serializable.
// (could make it transient and manually serialize)
}
public class RockhopperTransferable implements Transferable, ClipboardOwner {
public static DataFlavor rockhopperFlavor=null;
public static DataFlavor localRockhopperFlavor=null;
static {
try {
rockhopperFlavor =
new DataFlavor(com.rockhoppertech.Rockhopper.class,
"Non local Rockhopper");
localRockhopperFlavor = new
DataFlavor(DataFlavor.javaJVMLocalObjectMimeType +
"; class=com.rockhoppertech.Rockhopper",
"Local Rockhopper");
} catch(Exception e) {
System.err.println(e);
}
}
private Rockhopper penguin;
public RockhopperTransferable(Rockhopper rocky) {
this.penguin = rocky;
}
public Object getTransferData(...) {
... etc ...
return this.penguin;
}
etc.
Can I drag and drop images?
If you mean a java.awt.Image, no. Why? It's not serializable. You can drag a javax.swing.ImageIcon though!
Why can't I drop images into a native application?
There are several things you need to do first. You need a Transferable that can provide the image data in a format that the application likes. You will not be able to drop a serialized ImageIcon onto a native app for example. Most won't accept a binary stream even if you declare it's MIME type (e.g. image/jpeg) either.
You need to know what the native "clipboard" formats are. For example on Win32, DIB (device independent bitmap) and BITMAP are clipboard image formats. Learn the format and write an InputStream the can provide it. Then add your stream to a FlavorMap.
What is a FlavorMap and why do I need one?
Most native apps don't understand MIME types for data transfer. They have their own "clipboard" types. Java DataFlavors are based on MIME types. In order to provide a mapping between the win32 format TEXT and MIME types text/plain;charset=ascii you create a FlavorMap. Actually the default system flavormap does this type for you. An easy way to add mappings is to edit $JDKHOME/jre/lib/flavormap.properties. For our custom image stream we've added the following entry:
DIB=image/x-win-bmp;class=com.rockhoppertech.dnd.datatransfer.BitmapInputStream
Other Win32 clipboard formats are:
- WAVE
- RIFF
- PALETTE
- ENHMETAFILE
- METAFILEPICT
- DIB
- TIFF
How do I make the component scroll to where I want to drop?
Implement interface Autoscroll. details soon.
Can I copy this FAQ, remove your name and take credit for it myself?
Of course not. Why would anyone want to steal someone else's work?
Individual Swing components
What's the deal with the JTabbedPane?
There is a bug. You can DnD only with the first pane. The problem can be fixed by patching a single method in the tabbed pane. The example is in the dnd library available from the Rockhopper download page.
Resources
- The Drag and Drop Specification offers the final word on everything discussed here.
- Fixed bugs If you've tried to use DnD before and failed, it may have been due to a JDK bug!
- Motif drag and drop A seminal article discussing the details of drag and drop in X/Motif. If you're wondering why the Java API is structured the way it is, you'll want to read about how DnD is done on native platforms
Link to the official javadocs
- DropTarget
- DropTargetListener
- DragSource
- DragSourceListener
- DragGestureListener
- DataFlavor
- Clipboard
- ClipboardOwner
Articles on the data transfer API
- "Unfurling Java's data transfer API" discusses the data transfer API in the context of the clipboard
- "Java Tip 61: Cut, copy, and paste in Java"
Additional data transfer resources
- The MIME standard DataFlavors can be mapped to standard MIME types. Character encoding is also discussed
-
The
Transferableinterface encapsulates transferred data - The data transfer design specification
