我有一个类结构如下:
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
答案 0 :(得分:0)
如果你认为问题在于你是DefaultMutableTreeNode的子类,那么试着让你的DataFlavor成为一个Object数组,或者更好的是一个ArrayList:
DataFlavor.javaJVMLocalObjectMimeType + ";class=java.util.ArrayList"
这样您就可以将copies
列表与您的可转让列表一起返回。也许它会避免这个问题。
这里有一个关于如何使用列表执行此操作的粗略概述:
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
import java.util.*;
import java.util.List;
/**
* Author: Denis Tulskiy
* Date: 1/5/11
*/
public class Test extends JFrame {
class NodeA extends DefaultMutableTreeNode {
NodeA(Object userObject) {
super(userObject);
}
}
class NodeB extends DefaultMutableTreeNode {
NodeB(Object userObject) {
super(userObject);
}
}
class NodeC extends DefaultMutableTreeNode {
NodeC(Object userObject) {
super(userObject);
}
}
private static class MyTransferHandler extends TransferHandler {
@Override
public int getSourceActions(JComponent c) {
return MOVE;
}
@Override
protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree) c;
ArrayList<TreeNode> nodes = new ArrayList<TreeNode>();
for (TreePath path : tree.getSelectionPaths()) {
DefaultMutableTreeNode component = (DefaultMutableTreeNode) path.getLastPathComponent();
nodes.add(component);
}
return new NodesTransferable(nodes);
}
@Override
public boolean canImport(TransferSupport support) {
return support.isDataFlavorSupported(NodesTransferable.getDataFlavor());
}
@Override
public boolean importData(TransferSupport support) {
if (!canImport(support)) {
return false;
}
JTree tree = (JTree) support.getComponent();
List<DefaultMutableTreeNode> data = null;
try {
data = (List<DefaultMutableTreeNode>) support.getTransferable().getTransferData(NodesTransferable.getDataFlavor());
} catch (UnsupportedFlavorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (data != null) {
Point dropPoint = support.getDropLocation().getDropPoint();
TreePath path = tree.getPathForLocation(dropPoint.x, dropPoint.y);
DefaultMutableTreeNode parent = (DefaultMutableTreeNode) path.getLastPathComponent();
for (DefaultMutableTreeNode node : data) {
node.removeFromParent();
parent.add(node);
}
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
model.reload();
}
return true;
}
}
static class NodesTransferable implements Transferable {
private static DataFlavor dataFlavor;
public static DataFlavor getDataFlavor() {
if (dataFlavor == null) {
try {
dataFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=java.util.ArrayList");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return dataFlavor;
}
private java.util.List<TreeNode> nodes;
NodesTransferable(List<TreeNode> nodes) {
this.nodes = nodes;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{getDataFlavor()};
}
@Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.match(dataFlavor);
}
@Override
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return nodes;
}
}
public Test() {
JTree tree = new JTree();
tree.setDragEnabled(true);
tree.setDropMode(DropMode.ON_OR_INSERT);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
NodeA child = new NodeA("nodea");
root.add(child);
child.add(new NodeB("nodeb"));
child.add(new NodeC("nodec"));
tree.setModel(new DefaultTreeModel(root));
tree.setTransferHandler(new MyTransferHandler());
setLayout(new BorderLayout());
add(tree, BorderLayout.CENTER);
setSize(300, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new Test().setVisible(true);
}
}