首页 文章

在JTree中拖放节点

提问于
浏览
10

我很难创建一个JTree,它允许通过在JTree中拖放节点来重组节点 . 这似乎应该相对简单 . 我在线查看了一些示例,但我似乎无法在自己的代码中实现它 .

例如,sun提供的this允许在不同组件之间拖动到树中,但不允许从树本身内拖动 .

我还发现这可以让你将文本拖到JTree中,但不能在树中拖动 .

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.tree.*;

public class DndTree {

    public static void main(String args[]) {
        Runnable runner = new Runnable()  {

            public void run() {
                JFrame f = new JFrame("D-n-D JTree");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                JPanel top = new JPanel(new BorderLayout());
                JLabel dragLabel = new JLabel("Drag me:");
                JTextField text = new JTextField();
                text.setDragEnabled(true);
                top.add(dragLabel, BorderLayout.WEST);
                top.add(text, BorderLayout.CENTER);
                f.add(top, BorderLayout.NORTH);

                final JTree tree = new JTree();
                final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
                tree.setTransferHandler(new TransferHandler()  {

                    public boolean canImport(TransferHandler.TransferSupport support) {
                        if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)
                                || !support.isDrop()) {
                            return false;
                        }

                        JTree.DropLocation dropLocation =
                                (JTree.DropLocation) support.getDropLocation();

                        return dropLocation.getPath() != null;
                    }

                    public boolean importData(TransferHandler.TransferSupport support) {
                        if (!canImport(support)) {
                            return false;
                        }

                        JTree.DropLocation dropLocation =
                                (JTree.DropLocation) support.getDropLocation();

                        TreePath path = dropLocation.getPath();

                        Transferable transferable = support.getTransferable();

                        String transferData;
                        try {
                            transferData = (String) transferable.getTransferData(
                                    DataFlavor.stringFlavor);
                        } catch (IOException e) {
                            return false;
                        } catch (UnsupportedFlavorException e) {
                            return false;
                        }

                        int childIndex = dropLocation.getChildIndex();
                        if (childIndex == -1) {
                            childIndex = model.getChildCount(path.getLastPathComponent());
                        }

                        DefaultMutableTreeNode newNode =
                                new DefaultMutableTreeNode(transferData);
                        DefaultMutableTreeNode parentNode =
                                (DefaultMutableTreeNode) path.getLastPathComponent();
                        model.insertNodeInto(newNode, parentNode, childIndex);

                        TreePath newPath = path.pathByAddingChild(newNode);
                        tree.makeVisible(newPath);
                        tree.scrollRectToVisible(tree.getPathBounds(newPath));

                        return true;
                    }
                });

                JScrollPane pane = new JScrollPane(tree);
                f.add(pane, BorderLayout.CENTER);

                JPanel bottom = new JPanel();
                JLabel comboLabel = new JLabel("DropMode");
                String options[] = {"USE_SELECTION",
                    "ON", "INSERT", "ON_OR_INSERT"
                };
                final DropMode mode[] = {DropMode.USE_SELECTION,
                    DropMode.ON, DropMode.INSERT, DropMode.ON_OR_INSERT};
                final JComboBox combo = new JComboBox(options);
                combo.addActionListener(new ActionListener()  {

                    public void actionPerformed(ActionEvent e) {
                        int selectedIndex = combo.getSelectedIndex();
                        tree.setDropMode(mode[selectedIndex]);
                    }
                });
                bottom.add(comboLabel);
                bottom.add(combo);
                f.add(bottom, BorderLayout.SOUTH);
                f.setSize(300, 400);
                f.setVisible(true);
            }
        };
        EventQueue.invokeLater(runner);
    }
}

任何参考或建议都会很棒 . 谢谢

1 回答

  • 23

    以前没有这样做,但快速谷歌搜索在这里提出了同样的问题:http://www.coderanch.com/t/346509/GUI/java/JTree-drag-drop-inside-one它有一个可以看到的工作实现 .

    以下是Craig Wood发布的相关代码:

    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 < selRows.length; i++) {
                if(selRows[i] == dropRow) {
                    return false;
                }
            }
            // Do not allow MOVE-action drops if a non-leaf node is
            // selected unless all of its children are also selected.
            int action = support.getDropAction();
            if(action == MOVE) {
                return haveCompleteNode(tree);
            }
            // Do not allow a non-leaf node to be copied to a level
            // which is less than its source level.
            TreePath dest = dl.getPath();
            DefaultMutableTreeNode target =
                (DefaultMutableTreeNode)dest.getLastPathComponent();
            TreePath path = tree.getPathForRow(selRows[0]);
            DefaultMutableTreeNode firstNode =
                (DefaultMutableTreeNode)path.getLastPathComponent();
            if(firstNode.getChildCount() > 0 &&
                   target.getLevel() < firstNode.getLevel()) {
                return false;
            }
            return true;
        }
    
        private boolean haveCompleteNode(JTree tree) {
            int[] selRows = tree.getSelectionRows();
            TreePath path = tree.getPathForRow(selRows[0]);
            DefaultMutableTreeNode first =
                (DefaultMutableTreeNode)path.getLastPathComponent();
            int childCount = first.getChildCount();
            // first has children and no children are selected.
            if(childCount > 0 && selRows.length == 1)
                return false;
            // first may have children.
            for(int i = 1; i < selRows.length; i++) {
                path = tree.getPathForRow(selRows[i]);
                DefaultMutableTreeNode next =
                    (DefaultMutableTreeNode)path.getLastPathComponent();
                if(first.isNodeChild(next)) {
                    // Found a child of first.
                    if(childCount > 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<DefaultMutableTreeNode> copies =
                    new ArrayList<DefaultMutableTreeNode>();
                List<DefaultMutableTreeNode> toRemove =
                    new ArrayList<DefaultMutableTreeNode>();
                DefaultMutableTreeNode node =
                    (DefaultMutableTreeNode)paths[0].getLastPathComponent();
                DefaultMutableTreeNode copy = copy(node);
                copies.add(copy);
                toRemove.add(node);
                for(int i = 1; i < paths.length; i++) {
                    DefaultMutableTreeNode next =
                        (DefaultMutableTreeNode)paths[i].getLastPathComponent();
                    // Do not allow higher level nodes to be added to list.
                    if(next.getLevel() < node.getLevel()) {
                        break;
                    } else if(next.getLevel() > 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 < nodesToRemove.length; i++) {
                    model.removeNodeFromParent(nodesToRemove[i]);
                }
            }
        }
    
        public int getSourceActions(JComponent c) {
            return COPY_OR_MOVE;
        }
    
        public boolean importData(TransferHandler.TransferSupport support) {
            if(!canImport(support)) {
                return false;
            }
            // Extract transfer data.
            DefaultMutableTreeNode[] nodes = null;
            try {
                Transferable t = support.getTransferable();
                nodes = (DefaultMutableTreeNode[])t.getTransferData(nodesFlavor);
            } catch(UnsupportedFlavorException ufe) {
                System.out.println("UnsupportedFlavor: " + ufe.getMessage());
            } catch(java.io.IOException ioe) {
                System.out.println("I/O error: " + ioe.getMessage());
            }
            // Get drop location info.
            JTree.DropLocation dl =
                    (JTree.DropLocation)support.getDropLocation();
            int childIndex = dl.getChildIndex();
            TreePath dest = dl.getPath();
            DefaultMutableTreeNode parent =
                (DefaultMutableTreeNode)dest.getLastPathComponent();
            JTree tree = (JTree)support.getComponent();
            DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
            // Configure for drop mode.
            int index = childIndex;    // DropMode.INSERT
            if(childIndex == -1) {     // DropMode.ON
                index = parent.getChildCount();
            }
            // Add data to model.
            for(int i = 0; i < nodes.length; i++) {
                model.insertNodeInto(nodes[i], parent, index++);
            }
            return true;
        }
    
        public String toString() {
            return getClass().getName();
        }
    
        public class NodesTransferable implements Transferable {
            DefaultMutableTreeNode[] nodes;
    
            public NodesTransferable(DefaultMutableTreeNode[] nodes) {
                this.nodes = nodes;
             }
    
            public Object getTransferData(DataFlavor flavor)
                                     throws UnsupportedFlavorException {
                if(!isDataFlavorSupported(flavor))
                    throw new UnsupportedFlavorException(flavor);
                return nodes;
            }
    
            public DataFlavor[] getTransferDataFlavors() {
                return flavors;
            }
    
            public boolean isDataFlavorSupported(DataFlavor flavor) {
                return nodesFlavor.equals(flavor);
            }
        }
    }
    

相关问题