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

时间:2022-12-22 12:33:33

I have a JTree with about 100000 nodes or more. Now I want to expand the whole tree. To do so I use the solution I found here.

我有一个大约100000个节点的JTree。现在我要展开整个树。为了做到这一点,我使用了我在这里找到的解决方案。

My problem is that expanding such a large tree takes like 60 seconds or more, which is not very convenient. Does anyone have any suggestions how I could speed up expansion?

我的问题是,扩展这样一棵大树需要60秒甚至更长时间,这不是很方便。有谁有什么建议我可以加速扩张吗?

6 个解决方案

#1


3  

Quick way:

快捷方式:

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

#2


2  

I had the same problem with a tree containing 150 000 nodes (with more than 19 000 openable nodes). And I divided by 5 the duration of the expand all just by overriding the method getExpandedDescendants :

我遇到了同样的问题,一个包含150000个节点的树(有超过19000个可打开的节点)。我除以5的持续时间通过重写方法getexpanded后代:

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

The expand all action take now 5 seconds instead of 25 and I'm still working on improve performance.

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

#3


1  

I think you need to think of a display strategy, either breadth-first (look at all direct children) or depth-first (look at all the descendants of just one child). 100,000 is far too many nodes to view on the screen and you will need to think about panning and zooming. You should think of filters that could select the subsets of descendants that you want.

我认为你需要考虑一个显示策略,要么是宽度优先(看看所有直接的孩子),要么是深度优先(看看一个孩子的所有后代)。10万是屏幕上太多的节点,你需要考虑平移和缩放。您应该考虑可以选择您想要的子集的筛选器。

One strategy could be to display the top children and when your mouse enters a child, display all its descendants and when you leave collapse them. In that way you could navigate over the tree displaying the current subtree of interest.

一种策略可能是显示最优秀的孩子,当你的鼠标进入一个孩子,显示所有的后代,当你离开的时候,他们。通过这种方式,您可以在树中导航,显示当前感兴趣的子树。

#4


1  

i tried the solution, you use, too.

我也试过了,你也用。

After my opinion the code presented there isn't optimal: - it calls tree.expandPath for all the nodes, instead of calling it only for the deepest non-leaf nodes (calling expandPath on leaf nodes has no effect, see the JDK)

在我的意见之后,给出的代码并不是最优的:它叫树。所有节点的扩展路径,而不是只调用最深层的非叶节点(在叶子节点上调用expandPath没有效果,参见JDK)

Here's a corrected version which should be faster:

这里有一个更正的版本,应该更快:

// 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;
        }
    }

#5


0  

Yeah, rethink your UI element. A JTree is not what you are looking for to show 100,000 nodes. Use something where you can see a table and click items to drill-down into a table element. Then have a breadcrumb like history so the user can navigate up the hierarchy..

是的,重新考虑你的UI元素。JTree不是您想要显示的100,000个节点。在您可以看到一个表的地方使用一些东西,然后单击项目将其钻到一个表元素中。然后有一个类似于历史的面包屑,这样用户就可以在层次结构中导航。

If you are insistent on having a JTree, there is a way to take over they way it repaints, but I don't know if that will help you with the expand problem.

如果你坚持要有一棵JTree,有一种方法可以取代它们,它可以重新绘制,但是我不知道这会不会帮助你解决扩展问题。

#6


0  

I've had some success with the following pattern:

我在以下模式中取得了一些成功:

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

This already brought some large expansions (150,000 tree nodes) down from 12s -> 3.5s

这已经带来了一些大的扩展(15万棵树节点)从12s -> 3.5。

Then to expand in bulk more rapidly:

然后迅速扩大体积:

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

This brought it down to about 1.0s.

这使它下降到大约1。0。

#1


3  

Quick way:

快捷方式:

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

#2


2  

I had the same problem with a tree containing 150 000 nodes (with more than 19 000 openable nodes). And I divided by 5 the duration of the expand all just by overriding the method getExpandedDescendants :

我遇到了同样的问题,一个包含150000个节点的树(有超过19000个可打开的节点)。我除以5的持续时间通过重写方法getexpanded后代:

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

The expand all action take now 5 seconds instead of 25 and I'm still working on improve performance.

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

#3


1  

I think you need to think of a display strategy, either breadth-first (look at all direct children) or depth-first (look at all the descendants of just one child). 100,000 is far too many nodes to view on the screen and you will need to think about panning and zooming. You should think of filters that could select the subsets of descendants that you want.

我认为你需要考虑一个显示策略,要么是宽度优先(看看所有直接的孩子),要么是深度优先(看看一个孩子的所有后代)。10万是屏幕上太多的节点,你需要考虑平移和缩放。您应该考虑可以选择您想要的子集的筛选器。

One strategy could be to display the top children and when your mouse enters a child, display all its descendants and when you leave collapse them. In that way you could navigate over the tree displaying the current subtree of interest.

一种策略可能是显示最优秀的孩子,当你的鼠标进入一个孩子,显示所有的后代,当你离开的时候,他们。通过这种方式,您可以在树中导航,显示当前感兴趣的子树。

#4


1  

i tried the solution, you use, too.

我也试过了,你也用。

After my opinion the code presented there isn't optimal: - it calls tree.expandPath for all the nodes, instead of calling it only for the deepest non-leaf nodes (calling expandPath on leaf nodes has no effect, see the JDK)

在我的意见之后,给出的代码并不是最优的:它叫树。所有节点的扩展路径,而不是只调用最深层的非叶节点(在叶子节点上调用expandPath没有效果,参见JDK)

Here's a corrected version which should be faster:

这里有一个更正的版本,应该更快:

// 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;
        }
    }

#5


0  

Yeah, rethink your UI element. A JTree is not what you are looking for to show 100,000 nodes. Use something where you can see a table and click items to drill-down into a table element. Then have a breadcrumb like history so the user can navigate up the hierarchy..

是的,重新考虑你的UI元素。JTree不是您想要显示的100,000个节点。在您可以看到一个表的地方使用一些东西,然后单击项目将其钻到一个表元素中。然后有一个类似于历史的面包屑,这样用户就可以在层次结构中导航。

If you are insistent on having a JTree, there is a way to take over they way it repaints, but I don't know if that will help you with the expand problem.

如果你坚持要有一棵JTree,有一种方法可以取代它们,它可以重新绘制,但是我不知道这会不会帮助你解决扩展问题。

#6


0  

I've had some success with the following pattern:

我在以下模式中取得了一些成功:

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

This already brought some large expansions (150,000 tree nodes) down from 12s -> 3.5s

这已经带来了一些大的扩展(15万棵树节点)从12s -> 3.5。

Then to expand in bulk more rapidly:

然后迅速扩大体积:

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

This brought it down to about 1.0s.

这使它下降到大约1。0。