加速扩展/折叠JTree的所有节点

时间:2009-12-15 12:35:45

标签: java performance jtree expand

我有一个大约有100000个或更多节点的JTree。现在我想扩展整棵树。为此,我使用了我找到的解决方案here

我的问题是扩展这么大的树需要60秒或更长时间,这不是很方便。有没有人有任何建议我如何加快扩张?

6 个答案:

答案 0 :(得分:3)

快捷方式:

JTree jTree;
for (int i = 0; i < jTree.getRowCount(); i++) {
         jTree.expandRow(i);
}

答案 1 :(得分:2)

我遇到了一个包含150 000个节点(超过19 000个可打开节点)的树的问题。我只是通过覆盖方法getExpandedDescendants

,将扩展的持续时间除以5
JTree tree = new javax.swing.JTree()
{
    @Override
    public Enumeration<TreePath> getExpandedDescendants(TreePath parent)
    {
        if (!isExpanded(parent))
        {
            return null;
        }
        return java.util.Collections.enumeration(getOpenedChild(parent, new javolution.util.FastList<TreePath>()));
    }

    /**
     * Search oppened childs recursively
     */
    private List<TreePath> getOpenedChild(TreePath paramTreeNode, List<TreePath> list)
    {
        final Object parent = paramTreeNode.getLastPathComponent();
        final javax.swing.tree.TreeModel model = getModel();
        int nbChild = model.getChildCount(parent);
        for (int i = 0; i < nbChild; i++)
        {
            Object child = model.getChild(parent, i);
            final TreePath childPath = paramTreeNode.pathByAddingChild(child);
            if (!model.isLeaf(child) && isExpanded(childPath))
            {
                //Add child if oppened
                list.add(childPath);
                getOpenedChild(childPath, list);
            }
        }
        return list;
    }
};

展开所有动作现在需要5秒而不是25秒,我仍在努力提高性能。

答案 2 :(得分:1)

我认为你需要考虑一种展示策略,无论是广度优先(看看所有直接的孩子)还是深度优先(看看一个孩子的所有后代)。 100,000是要在屏幕上查看的节点太多,您需要考虑平移和缩放。您应该考虑可以选择所需后代子集的过滤器。

一种策略可能是显示顶级儿童,当您的鼠标进入儿童时,显示其所有后代以及何时离开它们。通过这种方式,您可以在显示当前感兴趣的子树的树上导航。

答案 3 :(得分:1)

我尝试了解决方案,你也使用了。

在我看来,那里提供的代码不是最优的:   - 它为所有节点调用tree.expandPath,而不是仅为最深的非叶节点调用它(在叶子节点上调用expandPath没有效果,请参阅JDK)

这是一个应该更快的更正版本:

// If expand is true, expands all nodes in the tree.
    // Otherwise, collapses all nodes in the tree.
    public void expandAll(JTree tree, boolean expand) {
        TreeNode root = (TreeNode)tree.getModel().getRoot();
        if (root!=null) {   
            // Traverse tree from root
            expandAll(tree, new TreePath(root), expand);
        }
    }

    /**
     * @return Whether an expandPath was called for the last node in the parent path
     */
    private boolean expandAll(JTree tree, TreePath parent, boolean expand) {
        // Traverse children
        TreeNode node = (TreeNode)parent.getLastPathComponent();
        if (node.getChildCount() > 0) {
            boolean childExpandCalled = false;
            for (Enumeration e=node.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode)e.nextElement();
                TreePath path = parent.pathByAddingChild(n);
                childExpandCalled = expandAll(tree, path, expand) || childExpandCalled; // the OR order is important here, don't let childExpand first. func calls will be optimized out !
            }

            if (!childExpandCalled) { // only if one of the children hasn't called already expand
                // Expansion or collapse must be done bottom-up, BUT only for non-leaf nodes
                if (expand) {
                    tree.expandPath(parent);
                } else {
                    tree.collapsePath(parent);
                }
            }
            return true;
        } else {
            return false;
        }
    }

答案 4 :(得分:0)

是的,重新考虑你的UI元素。 JTree不是您要显示的100,000个节点。使用可以查看表格的内容,然后单击项目以深入查看表格元素。然后有一个像历史一样的面包屑,以便用户可以向上导航层次结构..

如果你坚持使用JTree,有一种方法可以接管它重绘的方式,但我不知道这是否会帮助你解决扩展问题。

答案 5 :(得分:0)

我使用以下模式取得了一些成功:

tree = new JTree(...)
tree.setLargeModel(true);

这已经从12s带来了一些大的扩展(150,000个树节点) - &gt; 3.5s的

然后更快地扩大批量:

TreeUI treeUI = tree.getUI();
tree.setUI(null);
try {
  // perform bulk expansion logic, like in other answers
} finally {
  tree.setUI(treeUI);
}

这使其降至约1.0秒。