У меня есть структура классов следующим образом:
DefaultMutableTreeNode
|_
BCStructure
|_
| Module
|_
| Section
|_
Page
Модуль, Раздел и Страница - это то, что я фактически использую в своем JTree. Если вы запустите пример кода ниже, перетаскивание работает. Обратите внимание, что он использует DefaultMutableTreeNodes. Однако, если я помещаю код в свое реальное приложение, которое использует подклассы DefualtMutableTreeNode, он не работает.
Проходя по коду, я заметил две интересные области. Первое это:
class TreeTransferHandler extends TransferHandler {
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler() {
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType
+ ";class=\""
+ javax.swing.tree.DefaultMutableTreeNode[].class.getName()
+ "\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch (ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
Здесь он устанавливает DataFlavor. Он устанавливает его в массив DefualtMutableTreeNode, который я считаю правильным, поскольку DefaultMutableTreeNode является суперклассом моих узлов. Но это была та область, где я думал, что проблема может заключаться.
Другой момент заключается в том, что при отладке этого кода я получаю следующее:
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
до перетаскивания. Я предполагаю, что он возвращает DataFlavor, который не нравится хорошо. Вот почему я думаю, что с DataFlavor что-то не так. Есть ли что-то еще, что мне нужно сделать / изменить, чтобы это работало с подклассами? Есть идеи или предложения?
Спасибо!
Полный пример кода:
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.tree.*;
public class TreeDragAndDrop {
private JScrollPane getContent() {
JTree tree = new JTree();
tree.setDragEnabled(true);
tree.setDropMode(DropMode.ON_OR_INSERT);
tree.setTransferHandler(new TreeTransferHandler());
tree.getSelectionModel().setSelectionMode(
TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
expandTree(tree);
return new JScrollPane(tree);
}
private void expandTree(JTree tree) {
DefaultMutableTreeNode root =
(DefaultMutableTreeNode)tree.getModel().getRoot();
Enumeration e = root.breadthFirstEnumeration();
while(e.hasMoreElements()) {
DefaultMutableTreeNode node =
(DefaultMutableTreeNode)e.nextElement();
if(node.isLeaf()) continue;
int row = tree.getRowForPath(new TreePath(node.getPath()));
tree.expandRow(row);
}
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new TreeDragAndDrop().getContent());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
class TreeTransferHandler extends TransferHandler {
DataFlavor nodesFlavor;
DataFlavor[] flavors = new DataFlavor[1];
DefaultMutableTreeNode[] nodesToRemove;
public TreeTransferHandler() {
try {
String mimeType = DataFlavor.javaJVMLocalObjectMimeType +
";class=\"" +
javax.swing.tree.DefaultMutableTreeNode[].class.getName() +
"\"";
nodesFlavor = new DataFlavor(mimeType);
flavors[0] = nodesFlavor;
} catch(ClassNotFoundException e) {
System.out.println("ClassNotFound: " + e.getMessage());
}
}
public boolean canImport(TransferHandler.TransferSupport support) {
if(!support.isDrop()) {
return false;
}
support.setShowDropLocation(true);
if(!support.isDataFlavorSupported(nodesFlavor)) {
return false;
}
// Do not allow a drop on the drag source selections.
JTree.DropLocation dl =
(JTree.DropLocation)support.getDropLocation();
JTree tree = (JTree)support.getComponent();
int dropRow = tree.getRowForPath(dl.getPath());
int[] selRows = tree.getSelectionRows();
for(int i = 0; i 0 &&
target.getLevel() 0 && selRows.length == 1)
return false;
// first may have children.
for(int i = 1; i selRows.length-1) {
// Not all children of first are selected.
return false;
}
}
}
return true;
}
protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree)c;
TreePath[] paths = tree.getSelectionPaths();
if(paths != null) {
// Make up a node array of copies for transfer and
// another for/of the nodes that will be removed in
// exportDone after a successful drop.
List copies =
new ArrayList();
List toRemove =
new ArrayList();
DefaultMutableTreeNode node =
(DefaultMutableTreeNode)paths[0].getLastPathComponent();
DefaultMutableTreeNode copy = copy(node);
copies.add(copy);
toRemove.add(node);
for(int i = 1; i node.getLevel()) { // child node
copy.add(copy(next));
// node already contains child
} else { // sibling
copies.add(copy(next));
toRemove.add(next);
}
}
DefaultMutableTreeNode[] nodes =
copies.toArray(new DefaultMutableTreeNode[copies.size()]);
nodesToRemove =
toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]);
return new NodesTransferable(nodes);
}
return null;
}
/** Defensive copy used in createTransferable. */
private DefaultMutableTreeNode copy(TreeNode node) {
return new DefaultMutableTreeNode(node);
}
protected void exportDone(JComponent source, Transferable data, int action) {
if((action & MOVE) == MOVE) {
JTree tree = (JTree)source;
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
// Remove nodes saved in nodesToRemove in createTransferable.
for(int i = 0; i