Unlike simple GUI components, JTree objects contain substructure, which makes implementing drag and drop for JTree controls more difficult than for simpler GUI components. In fact, I read in one newsgroup thread that adding drag and drop to a JTree is impossible.
The big stumbling block is that since the JTree's nodes are the objects being dragged, it appears that they should implement the drag-and-drop interfaces.
The truth is that each node is completely unaware that it is even contained in a JTree; there is no getTree() in the TreeNode interface. Hence, the drag and drop interfaces must be implemented by the class listening for the JTree events.
For illustration purposes, let's consider a JTree that displays a family tree. All females in the tree may have children.
Males in the tree don't have children. To distinguish between node types, you can force the male node icon to be the leaf
icon and females to be the internal node icon (which is a folder and implies the ability to have children). To do that, you
need to override the isLeaf() and getAllowsChildren() methods of the DefaultMutableTreeNode class (there are other ways, but that's probably the easiest). Only one class is used for all the node objects, male and
female. If a node is male, the isLeaf() method will always return true and the getAllowsChildren() method will always return false. The code will look similar to the following:
public boolean isLeaf() {
return isMale;
}
public boolean getAllowsChildren() {
return !isMale;
}
I'll continue by examining the specific drag-and-drop interfaces. From the java.awt.dnd package, there are DragGestureListener (drag gesture recognizer), DragSourceListener (drag source), and DropTargetListener (drop target). From the java.awt.datatransfer package, there is Transferable.
The Transferable interface will be implemented by the object that encapsulates the node data, but the rest of the interfaces will be implemented
by the class that listens to the JTree events (presumably a class that subclasses JTree).
The DragGestureListener interface is invoked when a DragGestureRecognizer object detects a drag-initiating gesture.
Below is an example code listing of this interface's only method. Its code will start the drag action.
1 public void dragGestureRecognized(DragGestureEvent e) {
2 DefaultMutableTreeNode dragNode = getSelectedNode();
3
4 if (dragNode != null) {
5 Transferable transferable =
6 (Transferable) dragNode.getUserObject();
7
8 Cursor cursor = selectCursor (e.getDragAction())
9
10 dragSource.startDrag(e, cursor, transferable, this);
11 }
12 }
13
14 private Cursor selectCursor (int action) {
15 return (action == DnDConstants.ACTION_MOVE) ?
16 DragSource.DefaultMoveDrop : DragSource.DefaultCopyDrop;
17 }
The following list explains the steps you take in Lines 2 through 10 in the above code: