Animate JTree Drops #27
Chapter 3, Tables and Trees
|
139
HACK
If you wanted to hack further, you could make this and other small func-
tions like it each separate decorators. Then you could combine them at will,
depending on the needs of your application.
Wrapping Up
This table model decorator is now part of the main Lucene distribution. It’s
part of a new lucene-contrib project for Swing. In addition to this table
model decorator, there is also a list decorator. I imagine the search logic is
going to beef up, so definitely check out the Lucene site for more informa-
tion. You can get read-only web access to the Lucene repository at http://svn.
apache.org/repos/asf/lucene/java/trunk/contrib/swing/. Also note that because
these models are officially part of lucene-contrib, they are going to be distrib-
uted with all new Lucene builds. So, they are going to come free with
Lucene in the future.
—Jonathan Simon
H A C K
#27
Animate JTree Drops Hack #27
Who said working with tree paths was hard? Now you can reorganize tree
hierarchies with drag-and-drop.
JTrees are great for representing hierarchy, but they’re not so hot as control
widgets. You might want to drag items inside a tree, or accept a drop from
some other part of your application, and it turns out not to be well suited to
that. The problem is that the
JTree isn’t really a container, so from the
Swing programmer’s point of view, you see the tree’s visual representation,
but not the nodes within it.
The goal of this hack is to take a
JTree, like the one shown in Figure 3-11,
and allow you to reorganize it through drag-and-drop. The bulk of the work
will be in animating and handling the drop. The payoff is that making a sin-
gle tree reorderable will also get you most of the way to making it a good
drag-and-drop participant with the rest of your application, since support-
ing drag-and-drop within the
JTree requires you to make the tree a drag
source and a drop target.
The Code
If any of the forgoing sounds familiar, it should. Bringing drag-and-drop to
the
JTree is very similar to supporting it for the JList. In fact, the JTree and
the
JList have a lot in common—both use cell renderers, both are typically
put in
JScrollPanes, etc.
140
|
Chapter 3, Tables and Trees
#27 Animate JTree Drops
HACK
In fact, the code for this hack started as a straight port of the reorderable
JList hack
[Hack #17], with obvious changes for the different helper classes
(
TreeCellRenderer instead of ListCellRenderer) and different handling of the
model, since tree models are hierarchical.
To recap what needs to be done:
The tree needs to implement the
DragGestureListener (to start a drag),
the
DropTargetListener (to handle the drop), and the DragSourceListener
(only to get the end-of-drop callback).
The drag-and-drop implementations need to use the coordinates pro-
vided by drag-and-drop events to map to nodes of the tree as either the
node to drag or as potential drop targets.
The renderer needs to use information about whether a to-be-rendered
cell is the drop target and to offer suitable visual feedback.
The drop handling needs to remove the dragged node from its old loca-
tion and insert it at its new location.
Example 3-16 shows the main class (minus two inner classes that will be
introduced shortly).
Figure 3-11. JTree with drag-and-drop reordering
Example 3-16. JTree with drag-and-drop support
public class DnDJTree extends JTree
implements DragSourceListener, DropTargetListener, DragGestureListener {
static DataFlavor localObjectFlavor;
static {
try {
Animate JTree Drops #27
Chapter 3, Tables and Trees
|
141
HACK
localObjectFlavor =
new DataFlavor (DataFlavor.javaJVMLocalObjectMimeType);
} catch (ClassNotFoundException cnfe) { cnfe.printStackTrace( ); }
}
static DataFlavor[] supportedFlavors = { localObjectFlavor };
DragSource dragSource;
DropTarget dropTarget;
TreeNode dropTargetNode = null;
TreeNode draggedNode = null;
public DnDJTree ( ) {
super( );
setCellRenderer (new DnDTreeCellRenderer( ));
setModel (new DefaultTreeModel(new DefaultMutableTreeNode("default")));
dragSource = new DragSource( );
DragGestureRecognizer dgr =
dragSource.createDefaultDragGestureRecognizer (this,
DnDConstants.ACTION_MOVE,
this);
dropTarget = new DropTarget (this, this);
}
// DragGestureListener
public void dragGestureRecognized (DragGestureEvent dge) {
System.out.println ("dragGestureRecognized");
// find object at this x,y
Point clickPoint = dge.getDragOrigin( );
TreePath path = getPathForLocation (clickPoint.x, clickPoint.y);
if (path == null) {
System.out.println ("not on a node");
return;
}
draggedNode = (TreeNode) path.getLastPathComponent( );
Transferable trans = new RJLTransferable (draggedNode);
dragSource.startDrag (dge,Cursor.getDefaultCursor( ),
trans, this);
}
// DragSourceListener events
public void dragDropEnd (DragSourceDropEvent dsde) {
System.out.println ("dragDropEnd( )");
dropTargetNode = null;
draggedNode = null;
repaint( );
}
public void dragEnter (DragSourceDragEvent dsde) {}
public void dragExit (DragSourceEvent dse) {}
public void dragOver (DragSourceDragEvent dsde) {}
public void dropActionChanged (DragSourceDragEvent dsde) {}
// DropTargetListener events
public void dragEnter (DropTargetDragEvent dtde) {
System.out.println ("dragEnter");
Example 3-16. JTree with drag-and-drop support (continued)

Get Swing Hacks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.