2011-01-03 15 views
10

Tengo dificultades para crear un JTree que permita reorganizar los nodos arrastrándolos y soltándolos en el JTree. Parece que debería ser relativamente simple. He analizado ejemplos en línea, pero parece que no puedo implementarlo en mi propio código.Nodos de arrastrar y colocar en JTree

Por ejemplo, this proporcionado por sun permite arrastrar entre los diferentes componentes en el árbol, pero no desde dentro del mismo árbol.

Y también he encontrado esto que le permite arrastrar texto en el JTree, pero no dentro del árbol.

 

 

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

Cualquier referencia o sugerencia sería genial. Gracias

Respuesta

21

No he hecho esto antes, pero una búsqueda rápida en Google encontró la misma pregunta aquí: http://www.coderanch.com/t/346509/GUI/java/JTree-drag-drop-inside-one tiene una implementación en funcionamiento que puede ver.

Este es el código relevante que Craig Wood colocado:

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); 
     } 
    } 
} 
+4

Más adelante en el hilo alguien señaló un error (después de su respuesta fue publicada). El método 'copy (TreeNode)' debe ser 'privado DefaultMutableTreeNode copy (nodo TreeNode) {return node.clone();}' – Paul

+1

hay un pequeño problema. no podemos mover un nodo después del último nodo de una hoja. – redfox26

+0

La publicación indica más adelante que el método publicado por Paul no compila y debe ser: private DefaultMutableTreeNode copy (nodo TreeNode) { DefaultMutableTreeNode n = (DefaultMutableTreeNode) node; return (DefaultMutableTreeNode) n.clone(); } – Ted

Cuestiones relacionadas