2012-03-29 6 views
5

Ich habe zwei JTrees mit einigen falschen Daten drin, was ich versuche zu tun ist in der Lage zu sein, jeden 'Job' (15663-1, 15663-2, etc) zu machen und einen Knoten für jeden zu erstellen, mit einem Knoten für jedes Teil darunter und die Komponenten an jedem Teil darunter. In zwei Bäumen, wie folgt aus:Wie implementiere ich intelligentes Drag & Drop von einem JTree zum anderen?

+------------------------------+------------------------------+ 
| PARTS TO BE SHIPPED   | SHIPPING BOX     | 
+------------------------------+------------------------------+ 
|[JOB]       |[JOB]       | 
|+------[part]     |+------[part]    | 
|  +------[component] |  +------[component] | 
|  +------[component] |  +------[component] | 
|+------[part]     |+------[part]     | 
|  +------[component] |  +------[component] | 
|[JOB]       |[JOB]       | 
|+------[part]     |+------[part]     | 
|  +------[component] |  +------[component] | 
|  +------[component] |  +------[component] | 
|+------[part]     |+------[part]     | 
|  +------[component] |  +------[component] | 
+------------------------------+------------------------------+ 

Damit angenommen ich zwei Schrauben in der Abdeckung in Job A haben in den ‚Teile verschifft werden‘ jtree und ich habe nichts in Joba in den Versandkarton, Wenn ich die Schrauben auf die Transportbox ziehe, sollte sie einen Eintrag für JobA machen, einen Eintrag für Teil A machen und einen Eintrag für die Komponente machen, dann möchte ich die Menge für diese Komponente eingeben und diese Menge von der Menge subtrahieren Teile werden versandt.

Also wenn ich einen Job namens 1553-4 habe und er hat eine Abdeckung mit vier Schrauben und ich ziehe die Schrauben in die Versandbox, dann sollte es einen Eintrag in der Versandbox, die sagt, "x Schrauben" dann Aufforderung Damit der Benutzer die Anzahl der Schrauben eingeben kann, die er gerade verpackt hat, sollte der jtree, wenn er zwei Schrauben verpackt, die 2 Schrauben ändern, die für diesen Auftrag noch vorhanden sind.

Ich habe eine Reihe von verschiedenen Drag & Drop-Tutorials gelesen und ich habe einige Beispiele, aber ich kann es einfach nicht bekommen. Jeder Rat oder jede Hilfe wäre willkommen.

Ich weiß, dass ich einen TranferHandler implementieren muss, aber ich bin mir nicht sicher, wie genau, es scheint zu viel Schnittstelle 'Magie' los zu sein und ich verstehe es wirklich nicht.

Dies ist, was ich habe, ich machen Knoten und so verstehen, hier ist das, was ich habe:

package com.protocase.examples; 


import java.awt.Dimension; 
import java.awt.HeadlessException; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTree; 
import javax.swing.tree.DefaultMutableTreeNode; 
import javax.swing.tree.DefaultTreeModel; 
import javax.swing.tree.MutableTreeNode; 

/** 
* @author DavidH 
*/ 
public class JTreeExample { 
    public static void main(String[] args) { 
     addTreesAndDisplay(); 

    } 

    private static void addTreesAndDisplay() throws HeadlessException { 
     JFrame frame = new JFrame(); 
     JPanel panel = new JPanel(); 


     JTree tree = new JTree(getTreeModel()); 
     tree.setDragEnabled(true); 
     tree.setPreferredSize(new Dimension(200,400)); 
     JScrollPane scroll = new JScrollPane(); 
     scroll.setViewportView(tree); 
     panel.add(scroll); 


     JTree secondTree = new JTree(getTreeModel()); 
     secondTree.setPreferredSize(new Dimension(200,400)); 
     secondTree.setDragEnabled(true); 
     JScrollPane secondScroll = new JScrollPane(); 
     secondScroll.setViewportView(secondTree); 
     panel.add(secondScroll); 


     frame.setContentPane(panel); 
     frame.pack(); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 

    private static DefaultTreeModel getTreeModel() { 
     MutableTreeNode root = new DefaultMutableTreeNode("15663-1"); 
     DefaultMutableTreeNode cover = new DefaultMutableTreeNode("Cover"); 
     DefaultMutableTreeNode base = new DefaultMutableTreeNode("Base"); 
     root.insert(cover, 0); 
     root.insert(base, 0); 
     cover.insert(new DefaultMutableTreeNode("2x PEMS"), 0); 
     cover.insert(new DefaultMutableTreeNode("2x SCREWS"), 0); 
     base.insert(new DefaultMutableTreeNode("4x SCREWS"), 0); 
     base.insert(new DefaultMutableTreeNode("4x HANDLES"), 0); 
     DefaultTreeModel model = new DefaultTreeModel(root); 
     return model; 
    } 
} 

ich für einen kurzen Drag nur freu und in eine JTree Beispiel des Ziehens fallen und ziehe aus ein JTree.

Antwort

3

Eine sehr kurze, einfache Einführung in Drag and Drop in Swing in meinen eigenen Worten und basierend auf meiner eigenen Erfahrung (die hauptsächlich mit Drag-and-Drop in JDK1.5 war, so dass neue Funktionalität bereits vorhanden sein könnte).

Es gibt zwei Teile in einer Drag-and-Drop-Operation. Zuerst gibt es den Widerstand von der Quellkomponente. Die TransferHandler of the source component erstellt eine Transferable, die ein Container für die Daten ist, die in der Drag-and-Drop-Operation ausgetauscht werden. Abhängig von den Daten kann es unterschiedliche Darstellungen der Daten geben (die DataFlavor s genannt werden). Wenn Sie beispielsweise eine URL per Drag-and-Drop in einen Texteditor ziehen, wird höchstwahrscheinlich die URL zum aktuellen Dokument hinzugefügt. Aber wenn Sie es auf einen Webbrowser legen, hoffen Sie, dass es diese URL öffnet. Wo also die erste nur an Klartext interessiert ist, interessiert sich die zweite für ein komplexeres Objekt.

Der zweite Teil ist der Tropfen. Zuerst wird entschieden, ob der aktuelle Standort ein gutes Drop-Ziel ist. Es ist Aufgabe des Transfer-Handlers der Zielkomponente, zu entscheiden, ob er den Drop akzeptiert. In der Regel wird dies dadurch erreicht, dass geprüft wird, ob es die in Transferable enthaltenen Daten verarbeiten kann, indem man die Transferable nach den Daten für eine bestimmte DataFlavor fragt (Anmerkung: die Flavor muss bekannt sein, sowohl die Quell- als auch die Zielkomponente). Wenn es das Ablegen akzeptiert und der Benutzer die Maus freigibt, kann es mit der Verarbeitung der Daten in Transferable fortfahren und hoffentlich etwas Nützliches damit tun.

Aber wie immer sind die Swing tutorials ein sehr guter Ausgangspunkt.Nachdem Sie durch sie gegangen sind, können Sie wahrscheinlich eine ausführlichere Frage (wenn Sie noch irgendwelche haben, da Ihre Anforderung eher trivial ist)

+0

Dies ist eine großartige Erklärung. Ich weiß, dass ich TransferHandler erweitern muss, aber muss ich den DataFlavor erweitern? Also muss ich den Transfer-Handler auf meiner Quellenliste erweitern und ihm mitteilen, was zu tun ist, um ihn in eine übertragbare Version zu packen (eine Klasse, die ein Objekt besitzt und übertragbar erweitert) und dann einen zweiten Transfer-Handler für das Ziel schreibt (außer natürlich, der erste Transfer-Handler weiß beides zu tun? Wo kommen die Dataflavors her? – davidahines

+1

Der DataFlavor ist nur eine Möglichkeit anzugeben, welche Art von Daten im "Übertragbaren" (für den Absender) verfügbar ist und wie der Empfänger eine bestimmte Art von Daten anfordert. Stellen Sie sich das wie eine Art Etikett vor wie in einem Bibliotheksbuch, wo Sie sagen können "Gib mir das Mystery Buch" vs "Gib mir das romantische Zeug" – Robin

+0

Danke, ich werde diese Tutorials ausprobieren. – davidahines

2

Auf Theorie glaube ich, Robin hat Ihre Frage gut beantwortet. Also unten ist die Implementierung, die ich gemacht habe. Zusammenfassend lässt sich sagen, dass die Implementierung die oberen zwei Label und die unteren beiden Scrollpanels umfasst, ziehen Sie von links nach rechts. Es gibt noch kleinere Dinge wie vor dem Import, ein Dialog sollte erscheinen und der Benutzer fragen, wie viel Menge zu fallen ist (und dann die arithmetische Operation machen), aber ich denke, das können deine Hausaufgaben sein? ;-) Lass es mich wissen, wenn du weitere Hilfe brauchst.

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.datatransfer.DataFlavor; 
import java.awt.datatransfer.UnsupportedFlavorException; 
import java.io.IOException; 

import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTree; 
import javax.swing.SwingUtilities; 
import javax.swing.TransferHandler; 
import javax.swing.tree.DefaultMutableTreeNode; 
import javax.swing.tree.DefaultTreeModel; 
import javax.swing.tree.MutableTreeNode; 
import javax.swing.tree.TreePath; 

public class JTreeExample extends JPanel 
{ 
    private JTree tree; 
    private DefaultTreeModel treeModel; 


    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 

      @Override 
      public void run() 
      { 
       createAndShowGUI();    
      } 
     }); 
    } 

    private static void createAndShowGUI() 
    { 
     JFrame frame = new JFrame("My Warehouse"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     JTreeExample newContentPane = new JTreeExample(); 
     newContentPane.setOpaque(true); 
     frame.setContentPane(newContentPane); 

     frame.pack(); 
     frame.setVisible(true); 
    } 

    public JTreeExample() 
    { 
     setLayout(new GridLayout(1, 3)); 
     JLabel lbl_parts = new JLabel("PARTS TO BE SHIPPED");  
     tree = new JTree(getTreeModel()); 
     tree.setDragEnabled(true);   
     tree.setPreferredSize(new Dimension(200,400)); 
     JScrollPane scroll = new JScrollPane(); 
     scroll.setViewportView(tree); 

     JLabel lbl_ship = new JLabel("SHIPPING BOX"); 
     treeModel = getTreeModel(); 
     JTree secondTree = new JTree(treeModel); 
     secondTree.setPreferredSize(new Dimension(200,400));   
     secondTree.setTransferHandler(new TransferHandler() { 

      @Override 
      public boolean importData(TransferSupport support) 
      { 
       if (!canImport(support)) 
       { 
        return false; 
       } 

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

       TreePath path = dl.getPath(); 
       int childIndex = dl.getChildIndex(); 

       String data; 
       try 
       { 
        data = (String) support.getTransferable().getTransferData(DataFlavor.stringFlavor); 
       } 
       catch (UnsupportedFlavorException e) 
       { 
        return false;     
       } 
       catch (IOException e) 
       { 
        return false;     
       } 

       if (childIndex == -1) 
       { 
        childIndex = tree.getModel().getChildCount(path.getLastPathComponent()); 
       } 

       DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(data); 
       DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) path.getLastPathComponent(); 
       treeModel.insertNodeInto(newNode, parentNode, childIndex); 

       tree.makeVisible(path.pathByAddingChild(newNode)); 
       tree.scrollRectToVisible(tree.getPathBounds(path.pathByAddingChild(newNode))); 

       return true; 
      } 

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

       support.setShowDropLocation(true); 
       if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) 
       { 
        System.err.println("only string is supported"); 
        return false;     
       } 

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

       TreePath path = dl.getPath(); 

       if (path == null) 
       { 
        return false;     
       } 
       return true; 
      }      
     }); 
     JScrollPane secondScroll = new JScrollPane(); 
     secondScroll.setViewportView(secondTree); 

     JPanel topPanel = new JPanel(new BorderLayout()); 
     topPanel.add(lbl_parts, BorderLayout.NORTH); 
     topPanel.add(scroll, BorderLayout.CENTER); 

     JPanel btmPanel = new JPanel(new BorderLayout()); 
     btmPanel.add(lbl_ship, BorderLayout.NORTH); 
     btmPanel.add(secondScroll, BorderLayout.CENTER); 

     add(topPanel); 
     add(btmPanel);   

    } 

    private static DefaultTreeModel getTreeModel() 
    { 
     MutableTreeNode root = new DefaultMutableTreeNode("15663-1");       

     DefaultMutableTreeNode cover = new DefaultMutableTreeNode("Cover"); 
     cover.insert(new DefaultMutableTreeNode("2x PEMS"), 0); 
     cover.insert(new DefaultMutableTreeNode("2x SCREWS"), 0); 
     root.insert(cover, 0); 

     DefaultMutableTreeNode base = new DefaultMutableTreeNode("Base"); 
     base.insert(new DefaultMutableTreeNode("4x SCREWS"), 0); 
     base.insert(new DefaultMutableTreeNode("4x HANDLES"), 0); 
     root.insert(base, 0); 

     DefaultTreeModel model = new DefaultTreeModel(root); 
     return model; 
    } 
} 
+0

Diese Lösung funktioniert sehr gut für Strings und zeigt mir, was eine gute Implementierung von importData und canImport macht, aber wenn meine Knoten Objekte (Teile) halten, muss ich dann auch exportData nicht implementieren? – davidahines

+2

Dah, es wird Mühe und Zeit brauchen, um all das herauszufinden und umzusetzen, einschließlich des einen, den ich in der Antwort erwähnt habe. So lernen und wachsen wir. Ich würde definitiv gerne diesen Beispielcode vervollständigen, der leider mit hektischen Arbeitsplänen verbunden ist. Aber ich werde den Code in der obigen Antwort mit dem Rest der Voraussetzungen aktualisieren, wenn ich Freizeit habe. – Jasonw

+0

Ja, das ist mehr als genug, ich habe den Rest selbst erledigt. Was ich wirklich nicht verstanden habe, ist, welche Methoden zu implementieren/zu überschreiben sind, da es scheint, als ob es verschiedene Möglichkeiten gibt, Drag & Drop zu machen. – davidahines