【问题标题】:Subclass of TreeNode DnD issueTreeNode DnD 问题的子类
【发布时间】:2011-06-03 12:26:38
【问题描述】:

我的类结构如下:

DefaultMutableTreeNode |_ BCS结构 |_ |模块 |_ |部分 |_ 页

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 有问题的原因。我还需要做/修改什么才能使其与子类一起使用吗?有什么想法或建议吗?

谢谢!

完整的示例代码:

导入 java.awt.*; 导入 java.awt.datatransfer.*; 导入 java.awt.dnd.*; 导入 java.util.*; 导入 java.util.List; 导入 javax.swing.*; 导入 javax.swing.tree.*; 公共类 TreeDragAndDrop { 私人 JScrollPane getContent() { JTree 树 = 新 JTree(); tree.setDragEnabled(true); tree.setDropMode(DropMode.ON_OR_INSERT); tree.setTransferHandler(new TreeTransferHandler()); tree.getSelectionModel().setSelectionMode( TreeSelectionModel.CONTIGUOUS_TREE_SELECTION); 展开树(树); 返回新的 JScrollPane(树); } 私人无效expandTree(JTree树){ DefaultMutableTreeNode 根 = (DefaultMutableTreeNode)tree.getModel().getRoot(); 枚举 e = root.breadthFirstEnumeration(); 而(e.hasMoreElements()){ DefaultMutableTreeNode 节点 = (DefaultMutableTreeNode)e.nextElement(); 如果(node.isLeaf())继续; int row = tree.getRowForPath(new TreePath(node.getPath())); 树.expandRow(行); } } 公共静态无效主要(字符串[]参数){ JFrame f = 新的 JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(new TreeDragAndDrop().getContent()); f.setSize(400,400); f.setLocation(200,200); f.setVisible(true); } } 类 TreeTransferHandler 扩展 TransferHandler { 数据风味节点风味; DataFlavor[] 口味 = 新 DataFlavor[1]; DefaultMutableTreeNode[] nodesToRemove; 公共 TreeTransferHandler() { 尝试 { 字符串 mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" + javax.swing.tree.DefaultMutableTreeNode[].class.getName() + "\""; 节点风味=新数据风味(mimeType); 风味[0] = 节点风味; } 捕捉(ClassNotFoundException e){ System.out.println("ClassNotFound:" + e.getMessage()); } } 公共布尔canImport(TransferHandler.TransferSupport支持){ if(!support.isDrop()) { 返回假; } support.setShowDropLocation(true); if(!support.isDataFlavorSupported(nodesFlavor)) { 返回假; } // 不允许拖放源选择。 JTree.DropLocation dl = (JTree.DropLocation)support.getDropLocation(); JTree 树 = (JTree)support.getComponent(); int dropRow = tree.getRowForPath(dl.getPath()); int[] selRows = tree.getSelectionRows(); for(int i = 0; i 0 && 目标.getLevel() 0 && selRows.length == 1) 返回假; // 首先可能有孩子。 for(int i = 1; i selRows.length-1) { // 并非 first 的所有子项都被选中。 返回假; } } } 返回真; } protected Transferable createTransferable(JComponent c) { JTree 树 = (JTree)c; TreePath[] 路径 = tree.getSelectionPaths(); 如果(路径!= null){ // 组成一个节点数组用于传输和 // 另一个 for/of 将被删除的节点 // 成功删除后的 exportDone。 列出副本 = 新的 ArrayList(); 删除列表 = 新的 ArrayList(); DefaultMutableTreeNode 节点 = (DefaultMutableTreeNode)paths[0].getLastPathComponent(); DefaultMutableTreeNode 复制 = 复制(节点); 副本。添加(复制); toRemove.add(节点); for(int i = 1; i node.getLevel()) { // 子节点 复制。添加(复制(下一个)); // 节点已经包含子节点 } else { // 兄弟 副本。添加(副本(下一个)); toRemove.add(下一个); } } DefaultMutableTreeNode[] 节点 = copy.toArray(new DefaultMutableTreeNode[copies.size()]); 节点删除 = toRemove.toArray(new DefaultMutableTreeNode[toRemove.size()]); 返回新的 NodesTransferable(nodes); } 返回空值; } /** createTransferable 中使用的防御性副本。 */ 私有 DefaultMutableTreeNode 副本(TreeNode 节点){ 返回新的 DefaultMutableTreeNode(node); } protected void exportDone(JComponent source, Transferable data, int action) { 如果((动作和移动)==移动){ JTree 树 = (JTree) 源代码; DefaultTreeModel 模型 = (DefaultTreeModel)tree.getModel(); // 删除createTransferable中nodesToRemove中保存的节点。 for(int i = 0; 我

【问题讨论】:

  • 是否有错误信息或某种异常?你能扩展一下“不起作用”吗?
  • 不,没有错误信息。它根本不允许进行拖放操作。如果您尝试拖放一个节点,它会正确调用函数,只是有一些设置不正确,无法让我的 JTree 接受我的子类是可拖放的。
  • 您能否尝试在代码中使用 MySubDefaultMutableTreeNode 代替 String mimeType = DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" + javax.swing.tree.MySubDefaultMutableTreeNode[].class.getName() + " \"";
  • 您提供给我们的代码不完整,请更新问题。
  • @tulskiy 完整的代码在那里,但它被我在 for 循环中的

标签: java swing jtree drag-and-drop


【解决方案1】:

如果您认为问题在于您将 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);
    }
}

【讨论】:

  • 有趣的建议。我现在试试这个
  • 我又想到了一个。我的 JTree 在 JScrollPane 中。我是否必须对 JScrollPane 进行任何更改才能使其包含的 JTree 可拖放?
  • @user489041:不,JScrollPane 不会干扰 dnd。
猜你喜欢
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 2019-07-25
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多