TreeNode DnD问题的子类

时间:2011-01-04 16:37:16

标签: java swing jtree drag-and-drop

我有一个类结构如下:

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 

1 个答案:

答案 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);
    }
}