2011-01-04 8 views
0

Ich habe eine Strukturklasse wie folgt:Subclass von TreeNode DnD Ausgabe

 
DefaultMutableTreeNode 
|_ 
    BCStructure 
    |_ 
    | Module 
    |_ 
    | Section 
    |_ 
    Page 

Modul, Abschnitt und Seite ist, was ich eigentlich in meinem JTree verwenden. Wenn Sie den folgenden Beispielcode ausführen, funktioniert das Ziehen und Ablegen. Beachten Sie, dass es DefaultMutableTreeNodes verwendet. Wenn ich jedoch den Code in meine reale Anwendung lege, die die Unterklassen von DefualtMutableTreeNode verwendet, funktioniert es nicht.

Beim Durchlaufen des Codes habe ich zwei Bereiche von Interesse bemerkt. Das erste ist das:

 

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

Dies ist, wo es den DataFlavor setzt. Es wird auf ein DefualtMutableTreeNode-Array gesetzt, von dem ich annehme, dass es korrekt ist, da DefaultMutableTreeNode die Super-Klasse meiner Knoten ist. Aber das war ein Bereich, in dem ich dachte, das Problem könnte liegen.

Der andere Punkt ist während diesen Code debuggen, bekomme ich so weit:

 

     public DataFlavor[] getTransferDataFlavors() { 
      return flavors; 
     } 
 

vor dem Drag & Drop ausfällt. Ich nehme an, dass es einen DataFlavor zurückgibt, der nicht gut ist. Deshalb denke ich, dass etwas mit dem DataFlavor nicht stimmt. Gibt es noch etwas, was ich tun/ändern muss, damit dies mit Unterklassen funktioniert? Irgendwelche Ideen oder Vorschläge?

Danke!

kompletter Beispielcode:

 

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

Gibt es eine Fehlermeldung oder eine Art Ausnahme? Können Sie auf "funktioniert nicht" erweitern? – jzd

+0

Nein, es gibt keine Fehlermeldung. Es lässt einfach nicht zu, dass die Drag & Drop-Operation stattfindet. Wenn Sie versuchen, einen Knoten zu ziehen und abzulegen, ruft er die Funktionen korrekt auf. Es gibt nur etwas, das nicht richtig eingestellt ist, damit mein JTree akzeptieren kann, dass meine Unterklassen ziehen und ablegen können. – user489041

+0

Könnten Sie versuchen, MySubDefaultMutableTreeNode stattdessen in der Codezeichenfolge mimeType = DataFlavor.javaJVMLocalObjectMimeType + "; class = \" "+ javax.swing.tree.MySubDefaultMutableTreeNode []. Class.getName() +" \ ""; – StanislavL

Antwort

0

Wenn Sie das Problem denken, dass Sie die DefaultMutableTreeNode Unterklasse, versuchen Sie Ihren DataFlavor macht ein Array von Objekt zu sein, oder noch besser, eine Arraylist:

DataFlavor.javaJVMLocalObjectMimeType + ";class=java.util.ArrayList" 

Auf diese Weise können Sie Ihre copies Liste zusammen mit Ihrer übertragbaren zurückgeben. Vielleicht wird es das Problem vermeiden.

hier ist eine grobe Skizze, wie diese mit Listen zu tun:

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

Interessanter Vorschlag. Ich werde es jetzt ausprobieren – user489041

+0

Ich habe noch einen Gedanken gehabt. Mein JTree ist in einem JScrollPane. Müsste ich Änderungen an JScrollPane vornehmen, damit der enthaltene JTree Drag & Dropable sein kann? – user489041

+0

@ user489041: Nein, JScrollPane stört dnd nicht. –