Подкласс выпуска TreeNode DnD - PullRequest
0 голосов
/ 04 января 2011

У меня есть структура классов следующим образом:

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

Модуль, Раздел и Страница - это то, что я фактически использую в своем JTree. Если вы запустите пример кода ниже, перетаскивание работает. Обратите внимание, что он использует DefaultMutableTreeNodes. Однако, если я помещаю код в свое реальное приложение, которое использует подклассы DefualtMutableTreeNode, он не работает.

Проходя по коду, я заметил две интересные области. Первое это:


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

Здесь он устанавливает DataFlavor. Он устанавливает его в массив DefualtMutableTreeNode, который я считаю правильным, поскольку DefaultMutableTreeNode является суперклассом моих узлов. Но это была та область, где я думал, что проблема может заключаться.

Другой момент заключается в том, что при отладке этого кода я получаю следующее:


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

до перетаскивания. Я предполагаю, что он возвращает DataFlavor, который не нравится хорошо. Вот почему я думаю, что с DataFlavor что-то не так. Есть ли что-то еще, что мне нужно сделать / изменить, чтобы это работало с подклассами? Есть идеи или предложения?

Спасибо!

Полный пример кода:


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 

1 Ответ

0 голосов
/ 05 января 2011

Если вы считаете, что проблема заключается в том, что вы создаете подкласс DefaultMutableTreeNode, попробуйте сделать свой DataFlavor массивом Object или, еще лучше, ArrayList:

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

Таким образом, вы можете вернуть свой список copies вместе со своим переводом. Может быть, это позволит избежать проблемы.

Вот пример того, как это сделать со списками:

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