Oi chará!
Vamos lá:
O primeiro passo é você criar uma Tree que faça o scrolling automático, caso o usuário posicione o mouse em suas extremidades. Sem isso, seu usuário vai ficar frustrado caso tente arrastar o componente para um nó que não está visivel. A classe abaixo é uma "autoscrolling tree", com esse intuito:
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.dnd.Autoscroll;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.JTree;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
public class JAutoScrollingTree extends JTree implements Autoscroll {
private static final int MARGIN = 12;
public JAutoScrollingTree() {
super();
}
public JAutoScrollingTree(Object[] value) {
super(value);
}
public JAutoScrollingTree(Vector< ? > value) {
super(value);
}
public JAutoScrollingTree(Hashtable< ? , ? > value) {
super(value);
}
public JAutoScrollingTree(TreeNode root) {
super(root);
}
public JAutoScrollingTree(TreeNode root, boolean asksAllowsChildren) {
super(root, asksAllowsChildren);
}
public JAutoScrollingTree(TreeModel newModel) {
super(newModel);
}
public void autoscroll(Point p) {
int realrow = getRowForLocation(p.x, p.y);
Rectangle outer = getBounds();
realrow = (p.y + outer.y <= MARGIN ? realrow < 1 ? 0 : realrow - 1
: realrow < getRowCount() - 1 ? realrow + 1 : realrow);
scrollRowToVisible(realrow);
}
public Insets getAutoscrollInsets() {
Rectangle outer = getBounds();
Rectangle inner = getParent().getBounds();
return new Insets(inner.y - outer.y + MARGIN, inner.x - outer.x
+ MARGIN, outer.height - inner.height - inner.y + outer.y
+ MARGIN, outer.width - inner.width - inner.x + outer.x
+ MARGIN);
}
}
O segundo passo é definir o seu DragSourceListener. Esse é o cara que vai aceitar o Drag and Drop quando o usuário começar a faze-lo. No meu caso, coloquei uma referência não só à árvore como também ao form que contém a árvore. Assim, posso acessar métodos do form que me sejam úteis.
Esse cara abaixo fará o editor realizar um "cut" em qualquer nó que esteja sendo movido. Quando o usuário soltar o nó, um paste será dado (isso será feita na outra classe, abaixo dela), fazendo assim a movimentação.
Note que eu não desejo cut para o nó raiz. Isso é uma particularidade do meu sistema, que você poderá remover para sua tree.
class TreeDragSource implements DragSourceListener, DragGestureListener {
private DragSource source;
protected DragGestureRecognizer recognizer;
private DefaultMutableTreeNode oldNode;
private JTree sourceTree;
private JEditionPanel editor;
public TreeDragSource(JTree tree, JEditionPanel editor, int actions) {
sourceTree = tree;
source = new DragSource();
recognizer = source.createDefaultDragGestureRecognizer(sourceTree,
actions, this);
this.editor = editor;
}
/*
* Drag Gesture Handler
*/
public void dragGestureRecognized(DragGestureEvent dge) {
oldNode = (DefaultMutableTreeNode) sourceTree.getLastSelectedPathComponent();
if (oldNode == sourceTree.getModel().getRoot())
return;
this.editor.cut();
source.startDrag(dge, DragSource.DefaultMoveDrop,
NullTransferable.getInstance(), this);
}
public void dragEnter(DragSourceDragEvent dsde) {}
public void dragExit(DragSourceEvent dse) {}
public void dragOver(DragSourceDragEvent dsde) {}
public void dropActionChanged(DragSourceDragEvent dsde) {}
public void dragDropEnd(DragSourceDropEvent dsde) {}
}
Agora, você deve implementar o seu DropTargetListener. Esse é o cara que responde quando o mouse é liberado em algum lugar. Como eu disse anteriormente, eu movo os nós dando um "cut" quando a movimentação inicia, e um paste, quando ela termina.
class TreeDropTarget implements DropTargetListener {
DropTarget target;
JTree targetTree;
private JEditionPanel editor;
public TreeDropTarget(JTree tree, JEditionPanel editor) {
targetTree = tree;
target = new DropTarget(targetTree, this);
this.editor = editor;
}
public void dragEnter(DropTargetDragEvent dtde) {
dtde.acceptDrag(DnDConstants.ACTION_MOVE);
}
public void dragOver(DropTargetDragEvent dtde) {
dtde.acceptDrag(DnDConstants.ACTION_MOVE);
}
public void drop(DropTargetDropEvent dtde) {
//Gets the node where the user released the mouse in parent.
Point pt = dtde.getLocation();
JTree tree = (JTree) dtde.getDropTargetContext().getComponent();
TreePath parentpath = tree.getClosestPathForLocation(pt.x, pt.y);
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) parentpath.getLastPathComponent();
try {
dtde.acceptDrop(dtde.getDropAction());
editor.pasteInto(parent); //Paste the cutted node into parent
dtde.dropComplete(true);
} catch (Exception e) {
throw new RuntimeException(e);
try {
dtde.rejectDrop();
} catch (Exception e1) {
throw new RuntimeException(e);
}
}
}
public void dragExit(DropTargetEvent dte) {}
public void dropActionChanged(DropTargetDragEvent dtde) {}
}
Finalmente, falta colocar tudo para trabalhar junto.
Na construção da sua tree faça:
private JTree getTreeTests() {
if (treeTests == null) {
treeTests = new JAutoScrollingTree(getRoot());
ds = new TreeDragSource(treeTests, this, DnDConstants.ACTION_MOVE);
dt = new TreeDropTarget(treeTests, this);
//Restante de sua inicialização
As atributos ds e dt são, respectivamente, um TreeDragSource e um TreeDropTarget.