在JTree中拖放节点

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

例如,sun提供的这允许在不同组件之间拖动到树中,而不是从树本身内拖动。

我还发现这可以让你将文本拖到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(“DnD JTree”);  f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  JPanel top = new JPanel(new BorderLayout());  JLabel dragLabel = new JLabel(“拖我:”);  JTextField text = new JTextField();  text.setDragEnabled(真);  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)); 返回true;  }};  JScrollPane pane = new JScrollPane(tree);  f.add(pane,BorderLayout.CENTER);  JPanel bottom = new JPanel();  JLabel comboLabel = new JLabel(“DropMode”); 字符串选项[] = {“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(组合);  f.add(bottom,BorderLayout.SOUTH);  f.setSize(300,400);  f.setVisible(真);  }};  EventQueue.invokeLater(浇道);  }} 

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

之前没有这样做,但快速的谷歌搜索在这里提出了同样的问题: 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 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 < 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); } } }