JTree Drag and Drop / drop - Probleme

Status
Nicht offen für weitere Antworten.

dndopf

Mitglied
Hi, ich habe folgendes Problem mit meinen Transferhandler!
Um innerhalb meines Baumes einen Knoten abzulegen nutze ich insertNodeInto!
Löschen will ich dann mit draggedNode.removeFromParent.
Das Problem ist, das teilweise beim droppen er quasi einen neuen Root Knoten anlegt ( keine Ahnung warum ) und
damit funktioniert natürlich auch nicht mehr removeFromParent.

Hat jemand ne Idee woran das liegen könnte?

Code:
import java.awt.*;

import javax.swing.*;
import javax.swing.tree.*;

import java.awt.dnd.*;
import java.awt.datatransfer.*;
import java.awt.image.*;
import java.awt.geom.*;

public class DndTreeTransferHandler implements DragGestureListener,
        DragSourceListener, DropTargetListener {

    private DndTree tree;

    private DragSource dragSource; // dragsource

    private DropTarget dropTarget; //droptarget

    private static VDM_TreeNode draggedNode;

    private VDM_TreeNode draggedNodeParent;

    private static BufferedImage image = null; //buff image

    private Rectangle rect2D = new Rectangle();

    private boolean drawImage;

    protected DndTreeTransferHandler(DndTree tree, int action, boolean drawIcon) {
        this.tree = tree;
        drawImage = drawIcon;
        dragSource = new DragSource();
        dragSource.createDefaultDragGestureRecognizer(tree, action, this);
        dropTarget = new DropTarget(tree, action, this);
    }

    /* Methods for DragSourceListener */
    public void dragDropEnd(DragSourceDropEvent dsde) {

        draggedNode.getRoot();
        draggedNode.getLevel();

        System.out.println(draggedNode.getRoot());
        System.out.println(draggedNode.getLevel());

        if (dsde.getDropAction() == DnDConstants.ACTION_MOVE
                && draggedNodeParent != null) {

            draggedNode.removeFromParent();

            ((DefaultTreeModel) tree.getModel())
                    .nodeStructureChanged(draggedNodeParent);

        } else if (dsde.getDropAction() == DnDConstants.ACTION_MOVE
                && draggedNodeParent == null) {

                        
            ((DefaultTreeModel) tree.getModel())
            	.nodeStructureChanged(draggedNodeParent);

        }

    }

    public final void dragEnter(DragSourceDragEvent dsde) {
        int action = dsde.getDropAction();
        if (action == DnDConstants.ACTION_COPY) {
            dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyDrop);
        } else {
            if (action == DnDConstants.ACTION_MOVE) {
                dsde.getDragSourceContext().setCursor(
                        DragSource.DefaultMoveDrop);
            } else {
                dsde.getDragSourceContext().setCursor(
                        DragSource.DefaultMoveNoDrop);
            }
        }
    }

    public final void dragOver(DragSourceDragEvent dsde) {
        int action = dsde.getDropAction();
        if (action == DnDConstants.ACTION_COPY) {
            dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyDrop);
        } else {
            if (action == DnDConstants.ACTION_MOVE) {
                dsde.getDragSourceContext().setCursor(
                        DragSource.DefaultMoveDrop);
            } else {
                dsde.getDragSourceContext().setCursor(
                        DragSource.DefaultMoveNoDrop);
            }
        }
    }

    public final void dropActionChanged(DragSourceDragEvent dsde) {
        int action = dsde.getDropAction();
        if (action == DnDConstants.ACTION_COPY) {
            dsde.getDragSourceContext().setCursor(DragSource.DefaultCopyDrop);
        } else {
            if (action == DnDConstants.ACTION_MOVE) {
                dsde.getDragSourceContext().setCursor(
                        DragSource.DefaultMoveDrop);
            } else {
                dsde.getDragSourceContext().setCursor(
                        DragSource.DefaultMoveNoDrop);
            }
        }
    }

    public final void dragExit(DragSourceEvent dse) {
        dse.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
    }

    /* Methods for DragGestureListener */
    public final void dragGestureRecognized(DragGestureEvent dge) {
        TreePath path = tree.getSelectionPath();
        if (path != null) {
            draggedNode = (VDM_TreeNode) path.getLastPathComponent();
            draggedNodeParent = (VDM_TreeNode) draggedNode.getParent();
            if (drawImage) {
                Rectangle pathBounds = tree.getPathBounds(path); //getpathbounds
                // of
                // selectionpath
                JComponent lbl = (JComponent) tree.getCellRenderer()
                        .getTreeCellRendererComponent(
                                tree,
                                draggedNode,
                                false,
                                tree.isExpanded(path),
                                ((DefaultTreeModel) tree.getModel())
                                        .isLeaf(path.getLastPathComponent()),
                                0, false);//returning the label
                lbl.setBounds(pathBounds);//setting bounds to lbl
                image = new BufferedImage(lbl.getWidth(), lbl.getHeight(),
                        java.awt.image.BufferedImage.TYPE_INT_ARGB_PRE);//buffered
                // image
                // reference
                // passing
                // the
                // label's
                // ht
                // and
                // width
                Graphics2D graphics = image.createGraphics();//creating the
                // graphics for
                // buffered image
                graphics.setComposite(AlphaComposite.getInstance(
                        AlphaComposite.SRC_OVER, 0.5f)); //Sets the Composite
                // for the Graphics2D
                // context
                lbl.setOpaque(false);
                lbl.paint(graphics); //painting the graphics to label
                graphics.dispose();
            }
            dragSource.startDrag(dge, DragSource.DefaultMoveNoDrop, image,
                    new Point(0, 0), new TransferableNode(draggedNode), this);
        }
    }

    /* Methods for DropTargetListener */

    public final void dragEnter(DropTargetDragEvent dtde) {
        Point pt = dtde.getLocation();
        int action = dtde.getDropAction();
        if (drawImage) {
            paintImage(pt);
        }
        if (canPerformAction(tree, draggedNode, action, pt)) {
            dtde.acceptDrag(action);
        } else {
            dtde.rejectDrag();
        }
    }

    public final void dragExit(DropTargetEvent dte) {
        if (drawImage) {
            clearImage();
        }
    }

    public final void dragOver(DropTargetDragEvent dtde) {
        Point pt = dtde.getLocation();
        int action = dtde.getDropAction();
        if (drawImage) {
            paintImage(pt);
        }
        if (canPerformAction(tree, draggedNode, action, pt)) {
            dtde.acceptDrag(action);
        } else {
            dtde.rejectDrag();
        }
    }

    public final void dropActionChanged(DropTargetDragEvent dtde) {
        Point pt = dtde.getLocation();
        int action = dtde.getDropAction();
        if (drawImage) {
            paintImage(pt);
        }
        if (canPerformAction(tree, draggedNode, action, pt)) {
            dtde.acceptDrag(action);
        } else {
            dtde.rejectDrag();
        }
    }

    public final void drop(DropTargetDropEvent dtde) {
        try {
            if (drawImage) {
                clearImage();
            }
            int action = dtde.getDropAction();
          
            Transferable transferable = dtde.getTransferable();
            Point pt = dtde.getLocation();
            if (transferable
                    .isDataFlavorSupported(TransferableNode.NODE_FLAVOR)
                    && canPerformAction(tree, draggedNode, action, pt)) {
                TreePath pathTarget = tree
                        .getClosestPathForLocation(pt.x, pt.y);
                VDM_TreeNode node = (VDM_TreeNode) transferable
                        .getTransferData(TransferableNode.NODE_FLAVOR);
                VDM_TreeNode newParentNode = (VDM_TreeNode) pathTarget
                        .getLastPathComponent();
                
                               
                if (executeDrop(tree, node, newParentNode, action)) {
                    
                    dtde.acceptDrop(DnDConstants.ACTION_MOVE);
                    dtde.getDropTargetContext().dropComplete(true);

                    return;
                }
            }
            dtde.rejectDrop();
            dtde.dropComplete(false);
        } catch (Exception e) {
            System.out.println(e);
            dtde.rejectDrop();
            dtde.dropComplete(false);
        }
    }

    private final void paintImage(Point pt) {
        tree.paintImmediately(rect2D.getBounds());
        rect2D.setRect((int) pt.getX(), (int) pt.getY(), image.getWidth(),
                image.getHeight());
        tree.getGraphics().drawImage(image, (int) pt.getX(), (int) pt.getY(),
                tree);
    }

    private final void clearImage() {
        tree.paintImmediately(rect2D.getBounds());
    }

    public boolean canPerformAction(DndTree target, VDM_TreeNode draggedNode,
            int action, Point location) {
        TreePath pathTarget = target.getPathForLocation(location.x, location.y);
        if (pathTarget == null) {
            target.setSelectionPath(null);
            return (false);
        } else if (action == DnDConstants.ACTION_MOVE) {
            VDM_TreeNode parentNode = (VDM_TreeNode) pathTarget
                    .getLastPathComponent();

            if (parentNode == draggedNode.getParent()
                    && draggedNodeParent != null) {
                return (false);
            } else {
                return (true);
            }
        } else {
            return (false);
        }
    }

    public boolean executeDrop(DndTree target, VDM_TreeNode draggedNode,
            VDM_TreeNode newParentNode, int action) {
        if (action == DnDConstants.ACTION_MOVE) {
            ((DefaultTreeModel) target.getModel()).insertNodeInto(draggedNode,
                    newParentNode, newParentNode.getChildCount());
            TreePath treePath = new TreePath(draggedNode.getPath());
            target.scrollPathToVisible(treePath);
            target.setSelectionPath(treePath);
            return (true);
        }
        return (false);
    }

}
 

André Uhres

Top Contributor
Hier ist ein funktionierendes Beispiel:
Code:
/*****************************************************************************************************
* Simple_Tree.java
 *author: Ulrich Hilger
 *[url]http://articles.lightdev.com/tree/tree_article.pdf[/url]
 *
 *Für "Drag and Drop" muss man erstmal "setDragEnabled" aufrufen
 *und einen "Transferhandler" setzen (NodeMoveTransferHandler).
 *Ausserdem braucht man einen "Transferable" (GenericTransferable), der
 *die Nodes transportieren kann.
 *Erkennt der Transferhandler eine "drag" Operation, dann erzeugt er einen "Transferable" 
 *und transportiert diesen beim drop von einem Node zum anderen.
 *
 *Ausserdem setzen wir hier auch noch ein "DropTarget".
 *DropTarget implementiert die Schnittstelle "DropTargetListener", die einige Methoden hat,
 *welche während der Drag-Operation von Swing automatisch aufgerufen werden 
 *(dragOver, dragExit, drop). Dadurch kann man "autoscroll" und 
 *"automatic node expansion" implementieren (Einzelheiten siehe Klasse "TreeDropTarget").
 *
 *Oft sind die Nodes von einem Tree nicht nur einfache Strings, sondern kompliziertere Objekte.
 *Damit beim Editieren das original Objekt nicht verloren geht und wir trotzdem 
 *den Namen eines Nodes ändern können, brauchen wir einen eigenen "TreeCellEditor" (UserTreeCellEditor).
 *Dieser wird mit "setCellEditor" an den Tree gebunden (Einzelheiten siehe Klasse "UserTreeCellEditor").
****************************************************************************************************/
package treeDnD1;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.tree.DefaultTreeCellRenderer;
public class Simple_Tree extends JFrame {
    public Simple_Tree() {
        initComponents();
        tree.setDragEnabled(true);
        tree.setShowsRootHandles(true);
        NodeMoveTransferHandler th = new NodeMoveTransferHandler();
        tree.setTransferHandler(th);
        tree.setDropTarget(new TreeDropTarget(th));
        tree.setCellEditor(new UserTreeCellEditor(tree,(DefaultTreeCellRenderer)tree.getCellRenderer()));
        tree.setEditable(true);
    }
    private void initComponents(){
        scroller = new JScrollPane();
        tree = new JTree();
        toolbar = new JToolBar();
        neuB = new JButton();
        runterB = new JButton();
        hochB = new JButton();
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        scroller.setViewportView(tree);
        getContentPane().add(scroller, BorderLayout.CENTER);
        neuB.setText("Add node");
        neuB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                addNode();
            }
        });
        toolbar.add(neuB);
        runterB.setText("Move up");
        runterB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                move(UP);
            }
        });
        toolbar.add(runterB);
        hochB.setText("Move down");
        hochB.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                move(DOWN);
            }
        });
        toolbar.add(hochB);
        getContentPane().add(toolbar, BorderLayout.NORTH);
        pack();
    }
    private void addNode(){
        TreePath selectedPath = tree.getSelectionPath();
        if(selectedPath != null){
            Object o = selectedPath.getLastPathComponent();
            if(o != null){
                DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) o;
                DefaultMutableTreeNode newChild = new DefaultMutableTreeNode("new node "+count++);
                ((DefaultTreeModel)tree.getModel())
                .insertNodeInto(newChild, selectedNode, selectedNode.getChildCount());
                TreePath newPath = selectedPath.pathByAddingChild(newChild);
                tree.setSelectionPath(newPath);
                tree.startEditingAtPath(newPath);
            }
        }
    }
    private void move(final int direction){
        DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
        MutableTreeNode moveNode = (MutableTreeNode) tree.getLastSelectedPathComponent();
        if(moveNode == null) return ;
        MutableTreeNode parent = (MutableTreeNode) moveNode.getParent();
        if(parent == null) return ;
        int targetIndex = model.getIndexOfChild(parent, moveNode) + direction;
        if(targetIndex < 0 || targetIndex >= parent.getChildCount()) return;
        model.removeNodeFromParent(moveNode);
        model.insertNodeInto(moveNode, parent, targetIndex);
        //make the node visible by scroll to it
        TreeNode[] nodes = model.getPathToRoot(moveNode);
        TreePath path = new TreePath(nodes);
        tree.scrollPathToVisible(path);
        //select the newly added node
        tree.setSelectionPath(path);
    }
    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Simple_Tree().setVisible(true);
            }
        });
    }
    public JButton neuB;
    public JButton runterB;
    public JButton hochB;
    public JScrollPane scroller;
    public JToolBar toolbar;
    public JTree tree;
    private int count=1;
    private final int UP = -1;
    private final int DOWN = 1;
}




/*****************************************************************************************************
 * NodeMoveTransferHandler.java
 *author: Ulrich Hilger
 *[url]http://articles.lightdev.com/tree/tree_article.pdf[/url]
 *
 * Der NodeMoveTransferHandler erweitert die Klasse "TransferHandler" und
 * überschreibt die Methode "createTransferable"
 * in der festgelegt wird, was zu Beginn der Drag-Operation geschieht.
 * Dort wird einfach nur festgestellt, ob die Komponente ein JTree ist
 * und alle selektierten Tree Paths werden in einem Array an den "GenericTransferable"
 * weitergegeben. Ausserdem wird hier die Methode "createDragImage" aufgerufen, um 
 * ein halbdurchsichtiges Bild der zu verschiebenden Nodes zu erzeugen.
 *
 * Sobald der Benutzer die Maustaste loslässt, ruft Swing automatisch die Methode "exportDone" auf.
 * Dort wird festgestellt, ob ein Node selektiert ist, und dieser dient dann als Target Node (Ziel).
 * Dann werden alle Tree Paths vom Transferable geholt und jeder wird zum neuen
 * Parent Node verschoben (addNodes), bzw. zwischen zwei Nodes eingefügt (insertNodes).
 *
 * Die Methode "createDragImage" benutzt den "cell renderer" vom Tree um die Komponenten
 * zu holen, durch die die zu verschiebenden Nodes dargestellt werden (gewöhnlich JLabels).
 * Sie erzeugt dann ein halbdurchsichtiges BufferedImage und zeichnet die Labels darauf.
 * Das fertige Bild wird über die Methode "getDragImage" an die aufrufende Methode zurückgegeben
 * (das ist die Methode "paintImage" der Klasse "TreeDropTarget").
 ****************************************************************************************************/
package treeDnD1;

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.image.*;
import java.io.*;
import javax.swing.*;
import javax.swing.tree.*;
public class NodeMoveTransferHandler extends TransferHandler {
    public NodeMoveTransferHandler() {
        super();
    }
    protected Transferable createTransferable(JComponent c) {
        Transferable t = null;
        if(c instanceof JTree) {
            JTree tree = (JTree) c;
            t = new GenericTransferable(tree.getSelectionPaths());
            dragPath = tree.getSelectionPaths();
            createDragImage(tree);
        }
        return t;
    }
    protected void exportDone(JComponent source, Transferable data, int action) {
        if(source instanceof JTree) {
            JTree tree = (JTree) source;
            DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
            TreePath currentPath = tree.getSelectionPath();
            if(currentPath != null) {
                addNodes(currentPath, model, data);
            } else {
                insertNodes(tree, model, data);
            }
        }
        dragPath = null;
        super.exportDone(source, data, action);
    }
    private void addNodes(TreePath currentPath, DefaultTreeModel model, Transferable data) {
        MutableTreeNode targetNode = (MutableTreeNode) currentPath.getLastPathComponent();
        try {
            TreePath[] movedPaths = (TreePath[]) data.getTransferData(DataFlavor.stringFlavor);
            for(int i = 0; i < movedPaths.length; i++) {
                MutableTreeNode moveNode = (MutableTreeNode) movedPaths[i].getLastPathComponent();
                if(!moveNode.equals(targetNode)) {
                    MutableTreeNode oldParent = (MutableTreeNode) moveNode.getParent();
                    int oldIndex = model.getIndexOfChild(oldParent, moveNode);
                    if(oldParent == null) return ;
                    model.removeNodeFromParent(moveNode);
                    try{
                        model.insertNodeInto(moveNode, targetNode, targetNode.getChildCount());
                    }catch(IllegalArgumentException ex){
                        model.insertNodeInto(moveNode, oldParent, oldIndex);
                    }
                }
            }
        } catch (UnsupportedFlavorException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void insertNodes(JTree tree, DefaultTreeModel model, Transferable data) {
        Point location = ((TreeDropTarget) tree.getDropTarget()).getMostRecentDragLocation();
        TreePath path = tree.getClosestPathForLocation(location.x, location.y);
        MutableTreeNode targetNode = (MutableTreeNode) path.getLastPathComponent();
        MutableTreeNode parent = (MutableTreeNode) targetNode.getParent();
        try {
            TreePath[] movedPaths = (TreePath[]) data.getTransferData(DataFlavor.stringFlavor);
            for(int i = 0; i < movedPaths.length; i++) {
                MutableTreeNode moveNode = (MutableTreeNode) movedPaths[i].getLastPathComponent();
                if(!moveNode.equals(targetNode)) {
                    MutableTreeNode oldParent = (MutableTreeNode) moveNode.getParent();
                    int oldIndex = model.getIndexOfChild(oldParent, moveNode);
                    if(oldParent == null) return ;
                    model.removeNodeFromParent(moveNode);
                    try{
                        model.insertNodeInto(moveNode, parent, model.getIndexOfChild(parent, targetNode));
                    }catch(IllegalArgumentException ex){
                        model.insertNodeInto(moveNode, oldParent, oldIndex);
                    }
                }
            }
        } catch (UnsupportedFlavorException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public int getSourceActions(JComponent c) {
        return TransferHandler.MOVE;
    }
    public BufferedImage[] getDragImage() {
        return image;
    }
    private void createDragImage(JTree tree) {
        if (dragPath != null) {
            try {
                image = new BufferedImage[dragPath.length];
                for (int i = 0; i < dragPath.length; i++) {
                    Rectangle pathBounds = tree.getPathBounds(dragPath[i]);
                    TreeCellRenderer r = tree.getCellRenderer();
                    DefaultTreeModel m = (DefaultTreeModel)tree.getModel();
                    boolean nIsLeaf = m.isLeaf(dragPath[i].getLastPathComponent());
                    MutableTreeNode draggedNode = (MutableTreeNode) dragPath[i].getLastPathComponent();
                    JComponent lbl = (JComponent)r.getTreeCellRendererComponent(tree, draggedNode, false ,
                            tree.isExpanded(dragPath[i]),nIsLeaf, 0,false);
                    lbl.setBounds(pathBounds);
                    BufferedImage img = new BufferedImage(lbl.getWidth(), lbl.getHeight(),
                            BufferedImage.TYPE_INT_ARGB_PRE);
                    Graphics2D graphics = img.createGraphics();
                    graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
                    lbl.setOpaque(false);
                    lbl.paint(graphics);
                    graphics.dispose();
                    image[i] = img;
                }
            } catch (RuntimeException re) {}
        }
    }
    private TreePath[] dragPath;
    private BufferedImage[] image;
}








/*****************************************************************************************************
 * TreeDropTarget.java
 *author: Ulrich Hilger
 *[url]http://articles.lightdev.com/tree/tree_article.pdf[/url]
 *
 *TreeDropTarget erweitert die Klasse "DropTarget", welche die Schnittstelle "DropTargetListener" implementiert.
 *DropTargetListener hat einige Methoden, die während der Drag-Operation automatisch von Swing
 *aufgerufen werden (dragOver, dragExit, drop). Dadurch können wir "autoscroll" und
 *"automatic node expansion" implementieren.
 *"autoscroll" bedeutet, den sichbaren Teil vom Tree so im Fenster zu verschieben,
 *daß man immer den Node sehen kann, über dem man während der Drag-Operation angekommen ist.
 *Swing ruft während der Drag-Operation automatisch die "dragOver" Methode auf.
 *Dort können wir also auch unsere Methode "autoscroll" aufrufen.
 *In "autoscroll" prüfen wir, ob der Node, der gerade verschoben wird,
 *ausserhalb eines bestimmten Bereichs des sichtbaren Rechtecks vom Tree ist.
 *Im zutreffenden Fall wird mit "scrollRectToVisible" ein neues Rechteck sichtbar gemacht.
 *
 *Ein "collapsed node" muss "expanded" werden, damit seine Kinder sichtbar werden und
 *man auf sie einen drop ausführen kann. Die Funktion "automatic node expansion" wird ebenfalls
 *in der Methode "dragOver" implementiert. Dort rufen wir die Methode "updateDragMark" auf,
 *die mehrere Funktionen erfüllt:
 *  - sie markiert einen Node über dem man gerade einen Drag ausführt (markNode),
 *  - sie expandiert diesen Node, wenn er "collapsed" ist (auch in markNode),
 *  - sie zeichnet einen "insert marker", wenn der zu verschiebende Node gerade
 *    zwischen zwei Nodes ist (paintInsertMarker).
 *
 *Damit man immer sieht, welche Nodes gerade verschoben werden, brauchen wir eine eigene
 *"paintImage"-Methode, die ebenfalls in dragOver aufgerufen wird.
 *Die Methode "paintImage" nimmt die aktuelle Mausposition vom DropTargetDragEvent
 *und zeichnet ein eigenes Bild. Das eigentliche Bild wird aber in der Klasse "NodeMoveTransferHandler"
 *erstellt, weil nur dort bekannt ist, welche Nodes gerade verschoben werden.
 *Deshalb wurde dort die Variable "dragPath" eingeführt, die in der Methode "createTransferable"
 *initialisiert wird und in der Methde "createDragImage" benutzt wird, um das Bild vom "dragPath"
 *zu zeichnen.
 *
 ****************************************************************************************************/
package treeDnD1;
import java.awt.*;
import java.awt.dnd.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.tree.*;

public class TreeDropTarget extends DropTarget {
    public TreeDropTarget(NodeMoveTransferHandler h) {
        super();
        this.handler = h;
    }
    public void dragOver(DropTargetDragEvent dtde) {
        JTree tree = (JTree) dtde.getDropTargetContext().getComponent();
        Point loc = dtde.getLocation();
        updateDragMark(tree, loc);
        paintImage(tree, loc);
        autoscroll(tree, loc);
        super.dragOver(dtde);
    }
    public void dragExit(DropTargetDragEvent dtde) {
        clearImage((JTree) dtde.getDropTargetContext().getComponent());
        super.dragExit(dtde);
    }
    public void drop(DropTargetDropEvent dtde) {
        clearImage((JTree) dtde.getDropTargetContext().getComponent());
        super.drop(dtde);
    }
    private final void paintImage(JTree tree, Point location) {
        Point pt = new Point(location);
        BufferedImage[] image = handler.getDragImage();
        if(image != null) {
            tree.paintImmediately(rect2D.getBounds());
            rect2D.setLocation(pt.x-15, pt.y-15);
            int wRect2D = 0;
            int hRect2D= 0;
            for (int i = 0; i < image.length; i++) {
                tree.getGraphics().drawImage(image[i], pt.x-15, pt.y-15, tree);
                pt.y += image[i].getHeight();
                if(wRect2D < image[i].getWidth())
                    wRect2D = image[i].getWidth();
                hRect2D += image[i].getHeight();
            }
            rect2D.setSize(wRect2D, hRect2D);
        }
    }
    private final void clearImage(JTree tree) {
        tree.paintImmediately(rect2D.getBounds());
    }
    private Insets getAutoscrollInsets() {
        return autoscrollInsets;
    }
    private void autoscroll(JTree tree, Point cursorLocation) {
        Insets insets = getAutoscrollInsets();
        Rectangle outer = tree.getVisibleRect();
        Rectangle inner = new Rectangle(
                outer.x+insets.left,
                outer.y+insets.top,
                outer.width-(insets.left+insets.right),
                outer.height-(insets.top+insets.bottom));
        if (!inner.contains(cursorLocation))  {
            Rectangle scrollRect = new Rectangle(
                    cursorLocation.x-insets.left,
                    cursorLocation.y-insets.top,
                    insets.left+insets.right,
                    insets.top+insets.bottom);
            tree.scrollRectToVisible(scrollRect);
        }
    }
    public void updateDragMark(JTree tree, Point location) {
        mostRecentLocation = location;
        int row = tree.getRowForPath(tree.getClosestPathForLocation(location.x, location.y));
        TreePath path = tree.getPathForRow(row);
        if(path != null) {
            Rectangle rowBounds = tree.getPathBounds(path);
      /*
       * find out if we have to mark a tree node or if we
       * have to draw an insertion marker
       */
            int rby = rowBounds.y;
            int topBottomDist = insertAreaHeight / 2;
            // x = top, y = bottom of insert area
            Point topBottom = new Point(rby - topBottomDist, rby + topBottomDist);
            if(topBottom.x <= location.y && topBottom.y >= location.y) {
                // we are inside an insertArea
                paintInsertMarker(tree, location);
            } else {
                // we are inside a node
                markNode(tree, location);
            }
        }
    }
    public Point getMostRecentDragLocation() {
        return mostRecentLocation;
    }
    private void markNode(JTree tree, Point location) {
        TreePath path = tree.getClosestPathForLocation(location.x, location.y);
        if(path != null) {
            if(lastRowBounds != null) {
                Graphics g = tree.getGraphics();
                g.setColor(Color.white);
                g.drawLine(lastRowBounds.x, lastRowBounds.y,
                        lastRowBounds.x + lastRowBounds.width, lastRowBounds.y);
            }
            tree.setSelectionPath(path);
            tree.expandPath(path);
        }
    }
    private void paintInsertMarker(JTree tree, Point location) {
        Graphics g = tree.getGraphics();
        tree.clearSelection();
        int row = tree.getRowForPath(tree.getClosestPathForLocation(location.x, location.y));
        TreePath path = tree.getPathForRow(row);
        if(path != null) {
            Rectangle rowBounds = tree.getPathBounds(path);
            if(lastRowBounds != null) {
                g.setColor(Color.white);
                g.drawLine(lastRowBounds.x, lastRowBounds.y,
                        lastRowBounds.x + lastRowBounds.width, lastRowBounds.y);
            }
            if(rowBounds != null) {
                g.setColor(Color.black);
                g.drawLine(rowBounds.x, rowBounds.y, rowBounds.x + rowBounds.width, rowBounds.y);
            }
            lastRowBounds = rowBounds;
        }
    }
    private Rectangle lastRowBounds;
    private int insertAreaHeight = 8;
    private Insets autoscrollInsets = new Insets(20, 20, 20, 20);
    private Rectangle rect2D = new Rectangle();
    private NodeMoveTransferHandler handler;
    private Point mostRecentLocation;
}



/*****************************************************************************************************
* GenericTransferable.java
 *author: Ulrich Hilger
 *[url]http://articles.lightdev.com/tree/tree_article.pdf[/url]
*
 * Diese Klasse ist sehr allgemein gehalten und kann dadurch auch einen Array 
 * von selektierten Tree Paths im Objekt "data" beinhalten.
 * Das Objekt wird dem Konstruktor übergeben und über die Methode "getTransferData" wieder zurückgegeben.
 * Obschon hier "DataFlavor.stringFlavor" benutzt wird, wird dies aber in der Implementation ignoriert.
****************************************************************************************************/
package treeDnD1;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
public class GenericTransferable implements Transferable {
  public GenericTransferable(Object data) {
    super();
    this.data = data;
  }
  public DataFlavor[] getTransferDataFlavors() {
    return flavors;
  }
  public boolean isDataFlavorSupported(DataFlavor flavor) {
    return true;
  }
  public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
    return data;
  }
  private Object data;
  private static final DataFlavor[] flavors = new DataFlavor[1];
  static {
    flavors[0] = DataFlavor.stringFlavor;
  }
}




/*****************************************************************************************************
* UserTreeCellEditor.java
 *author: Ulrich Hilger
 *[url]http://articles.lightdev.com/tree/tree_article.pdf[/url]
*
 *Oft sind die Nodes von einem Tree nicht nur einfache Strings, sondern kompliziertere Objekte.
 *Damit beim Editieren das original Userobjekt nicht verloren geht und wir trotzdem 
 *den Namen eines Nodes ändern können, brauchen wir einen eigenen "TreeCellEditor" (UserTreeCellEditor).
 *In "UserTreeCellEditor" wird als Beispiel angenommen, daß die Objekte vom Tree 
 *die Schnittstelle "HierarchicalItem" implementieren. 
 *Die Methode "getTreeCellEditorComponent"  speichert die Referenz zum Userobjekt
 *in der privaten Variablen "item". 
 *Die Methode "getCellEditorValue" speichert erstmal den editierten Wert im Userobjekt 
 *(mit "item.setData(value)") und gibt dann das ganze Userobjekt zurück anstatt nur den editierten String. 
 *Dabei wird angenommen, daß die "toString"-Methode vom Userobjekt den editierten Wert zurückgibt.
****************************************************************************************************/
package treeDnD1;
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
public class UserTreeCellEditor extends DefaultTreeCellEditor {
    public UserTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) {
        super(tree, renderer);
    }
    public Object getCellEditorValue() {
        Object returnValue = null;
        Object value = super.getCellEditorValue();
        if(item == null) {
            returnValue = value;
        } else {
            item.setData(value);
            returnValue = item;
        }
        return returnValue;
    }
    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
        if(value instanceof DefaultMutableTreeNode) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
            Object userObject = node.getUserObject();
            if(userObject instanceof HierarchicalItem) {
                item = (HierarchicalItem) node.getUserObject();
            }
        }
        return super.getTreeCellEditorComponent(tree, value, isSelected, expanded, leaf, row);
    }
    private HierarchicalItem item;
}
interface HierarchicalItem{
    public abstract void setData(Object data);
    public abstract Object getData();
    public abstract void setId(Object id);
    public abstract Object getId();
    public abstract Object getParentId();
    public abstract void setParentId(Object parentId);
    public abstract boolean isRoot();
}
 

André Uhres

Top Contributor
> Hier ist ein funktionierendes Beispiel:

Ich habe noch Verbesserungen in obigem Beispiel vorgenommen.
Jetzt läuft's rund.
 

André Uhres

Top Contributor
Ich habe die Klassen NodeMoveTransferHandler und TreeDropTarget jetzt noch ein wenig angepasst:
für den Fall, wo man mehrere Nodes gleichzeitig verschieben will, sieht man während der
Drag-Operation jetzt alle zu verschiebenden Nodes, anstatt nur den ersten Node.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
Z Swing Drag&Drop zwischen JTable und JTree AWT, Swing, JavaFX & SWT 4
F Swing Drag and Drop in JTree aus verschiedenen Listen AWT, Swing, JavaFX & SWT 6
E JTree Autoscroll bei Drag and Drop AWT, Swing, JavaFX & SWT 4
C Drag an Drop vom JTree zur JTable AWT, Swing, JavaFX & SWT 4
G Drag and Drop JTree to Canvas AWT, Swing, JavaFX & SWT 7
E Drag & Drop von jTree in JList AWT, Swing, JavaFX & SWT 5
G JTree Node ggf. aufklappen bei Drag & Drop? AWT, Swing, JavaFX & SWT 7
F JTree - Drag and Drop AWT, Swing, JavaFX & SWT 2
D Drag and Drop von JTree auf JPanel AWT, Swing, JavaFX & SWT 9
G Drag&Drop (JTree) AWT, Swing, JavaFX & SWT 2
W JTree, bei Drag Over über den Knoten "markieren" AWT, Swing, JavaFX & SWT 3
FrittenFritze JTree, LazyLoading und "Rückwärtstraversion" AWT, Swing, JavaFX & SWT 3
J Falsches Rendern durch JCheckBox in eigenem JTree AWT, Swing, JavaFX & SWT 6
F jTree und das Model aus einer eigenen Klasse AWT, Swing, JavaFX & SWT 1
F Jtree aus Klasse mit Arraylisten AWT, Swing, JavaFX & SWT 1
A Swing JList zu JTree AWT, Swing, JavaFX & SWT 11
richis-fragen JTree +/- verschwidet wenn Knoten keine Kinder hat... AWT, Swing, JavaFX & SWT 6
RalleYTN Modaler Dialog und JTree Node mit sehr... seeeeehr vielen Elementen AWT, Swing, JavaFX & SWT 6
Z Swing JTree DefaultMultipleTreeNode Repräsentation ändern AWT, Swing, JavaFX & SWT 1
W Swing Anzeigefehler bei JTree AWT, Swing, JavaFX & SWT 1
S Zwei JTree, ein Model, bei Selection im ersten JTree soll der zweite die Inhlate anzeigen AWT, Swing, JavaFX & SWT 2
S JRadioButton und JCheckBox im JTree AWT, Swing, JavaFX & SWT 14
H Swing JTree: Zählt der rootNode mit? AWT, Swing, JavaFX & SWT 2
krgewb Swing JTree - Farbe von nodes ändern AWT, Swing, JavaFX & SWT 4
R JTree behandeln AWT, Swing, JavaFX & SWT 2
E Swing Copy und Paste eines einzelnen Knoten aus einem JTree AWT, Swing, JavaFX & SWT 1
U dynamisches JTree erstellen AWT, Swing, JavaFX & SWT 2
J JTree updaten AWT, Swing, JavaFX & SWT 2
N Swing JTree Problem beim erstellen der Knoten AWT, Swing, JavaFX & SWT 0
H JTree in JScrollPane passt sich nicht an Größe von JPanel an AWT, Swing, JavaFX & SWT 2
T Swing API Frage zu Verzeichnisbäumen und JTree AWT, Swing, JavaFX & SWT 1
T JTree mit Symbolen? AWT, Swing, JavaFX & SWT 8
R Anfängerfrage: Ansichten des JTree AWT, Swing, JavaFX & SWT 1
H Swing JTree Minimumgröße AWT, Swing, JavaFX & SWT 2
F Swing JTree + DiffUtils // Markierung Nodes aufheben AWT, Swing, JavaFX & SWT 2
I JTree wird nicht angezeigt AWT, Swing, JavaFX & SWT 3
M Swing JTree AWT, Swing, JavaFX & SWT 4
M Nodes in JTree nicht anzeigen AWT, Swing, JavaFX & SWT 0
T JTree mit Cloud verbinden AWT, Swing, JavaFX & SWT 0
H JTree Probleme AWT, Swing, JavaFX & SWT 9
M JButton wird von JTree überdeckt AWT, Swing, JavaFX & SWT 4
J Auf Dateien in JTree zugreifen AWT, Swing, JavaFX & SWT 15
F jTree.startEditingAtPath(path); funktioniert nicht bei eigenem CellEditor? AWT, Swing, JavaFX & SWT 8
D Swing JTree Steuerung AWT, Swing, JavaFX & SWT 11
S Swing JTree verwirrt mich AWT, Swing, JavaFX & SWT 2
T JTree - Elemente mit Doppelklick auswählen AWT, Swing, JavaFX & SWT 6
J JTree speichern AWT, Swing, JavaFX & SWT 4
N Swing JTree TreeCellRenderer mit html und automatischen Zeilenumbruch AWT, Swing, JavaFX & SWT 8
O Swing JTree um Label (oder Panel) erweitern AWT, Swing, JavaFX & SWT 9
T JTree, Knoten mehrmals verwenden AWT, Swing, JavaFX & SWT 5
B JTree mit Ordneransicht in JPanel einbinden AWT, Swing, JavaFX & SWT 4
D JTree node reagiert bei Klick nicht immer AWT, Swing, JavaFX & SWT 2
M Swing JTree: Wie kann ich die Hintergrundfarbe der selection ändern?!?! AWT, Swing, JavaFX & SWT 7
D Mehrmals auf Node im JTree klicken AWT, Swing, JavaFX & SWT 2
D JSplitPane, Jtree, CardLayout (constraint must be a string) AWT, Swing, JavaFX & SWT 9
N Swing FileFilter lässt JTree sich nicht öffnen AWT, Swing, JavaFX & SWT 2
X Swing 2 TreeModel und ein JTree synchronisieren AWT, Swing, JavaFX & SWT 3
N Swing JTree TreePath zu Windows Pfad? AWT, Swing, JavaFX & SWT 2
RELAXccc Swing JTree + JScrollPane, refresh Problem AWT, Swing, JavaFX & SWT 17
X Swing JTree aktualisieren AWT, Swing, JavaFX & SWT 2
V Swing JTree - Umbenennen selbst handlen. AWT, Swing, JavaFX & SWT 2
E Übergebenem JTree Blätter hinzufügen AWT, Swing, JavaFX & SWT 2
E Wert eines selektierten Knotens in einem JTree auslesen AWT, Swing, JavaFX & SWT 3
A Swing JTree - Nodes expanden AWT, Swing, JavaFX & SWT 2
D JTree nach Klick auf einen Hyperlink aktualisieren AWT, Swing, JavaFX & SWT 3
B JTree AWT, Swing, JavaFX & SWT 9
T Menüacceleratoren verschwinden bei JTree AWT, Swing, JavaFX & SWT 5
1 Swing JTree collapse child nodes AWT, Swing, JavaFX & SWT 4
B JTree - sehr individuell AWT, Swing, JavaFX & SWT 3
G Swing JTree - Verbindungslinien entfernen AWT, Swing, JavaFX & SWT 4
A Swing Herausfinden ob bei JTree Klick auf "+"/"-" anahnd x,y AWT, Swing, JavaFX & SWT 2
S Swing JTree und seine Listener... AWT, Swing, JavaFX & SWT 4
L Swing JTree wird nicht selektiert AWT, Swing, JavaFX & SWT 2
P [JTree] Markierhilfe der Drop-Location selber gestalten. AWT, Swing, JavaFX & SWT 4
A JTree aus Pfaden erzeugen AWT, Swing, JavaFX & SWT 3
K Swing Hilfe beim JTree! AWT, Swing, JavaFX & SWT 3
X Datensätze in JTree AWT, Swing, JavaFX & SWT 2
L Update JTree Verzeichnisse AWT, Swing, JavaFX & SWT 9
E JTree Auswahl AWT, Swing, JavaFX & SWT 2
K JTree width der Treenodes auf 100% AWT, Swing, JavaFX & SWT 6
C JTree LastSelectedPathComponent benutzen? AWT, Swing, JavaFX & SWT 3
S Swing JTree Node Text nicht richtig angezeigt AWT, Swing, JavaFX & SWT 2
Landei Swing JTree mit "Tabellenzeilen"? AWT, Swing, JavaFX & SWT 5
Rudolf Swing JTree Node anhand vom Namen finden AWT, Swing, JavaFX & SWT 4
S JTree Elemente nach BaumLevel abspeichern AWT, Swing, JavaFX & SWT 2
Z JTree rootChilds AWT, Swing, JavaFX & SWT 2
D JTree DefaultMutableTreeNode ActionPerformed AWT, Swing, JavaFX & SWT 3
T JTree Daten in DB schreiben am besten SQL AWT, Swing, JavaFX & SWT 21
O JTree/TreeModel/DefaultMutableTreeNodes thread safe machen AWT, Swing, JavaFX & SWT 3
J Lazy Loading eine JTree während Scrollen AWT, Swing, JavaFX & SWT 11
S JTree & JComboBox - Elemente übers Fenster hinaus anzeigen AWT, Swing, JavaFX & SWT 9
E Swing JTree AWT, Swing, JavaFX & SWT 2
J Swing Lazy Loading in JTree wenn gescrollt wird AWT, Swing, JavaFX & SWT 3
N Knotenanordnung in JTree AWT, Swing, JavaFX & SWT 4
S JTree mit Liste zur Speicherung AWT, Swing, JavaFX & SWT 3
S Jtree CheckNode mit JPanel AWT, Swing, JavaFX & SWT 32
G JTree entfernt Nodes nicht AWT, Swing, JavaFX & SWT 12
C Swing JTree und TreeModel AWT, Swing, JavaFX & SWT 15
S Swing JTree wird nicht angezeigt AWT, Swing, JavaFX & SWT 3
J JTree AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben