Speed up expand/collapse all nodes of a JTree
Asked Answered
D

6

8

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.

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?

Disband answered 15/12, 2009 at 12:35 Comment(2)
Why do you want to fully expand a JTree with 100,000 nodes? Only a fraction of the nodes will fit on the screen anyway so what is the benefit in doing this?Cecil
The use case is showing the usage of a part in all bill of materials in our datastructur. This could lead theoretically to such big amount of data. Right now I'm trying to find out what is possible with a JTree technically (especially in comparisson to the Delphi/C++ Component VirtualTreeView)Disband
R
4

Quick way:

JTree jTree;
for (int i = 0; i < jTree.getRowCount(); i++) {
         jTree.expandRow(i);
}
Royster answered 28/3, 2014 at 10:25 Comment(0)
H
3

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 :

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.

Hagiocracy answered 25/10, 2013 at 9:16 Comment(0)
S
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.

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.

Saga answered 15/12, 2009 at 12:50 Comment(0)
A
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)

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;
        }
    }
Arrogate answered 15/10, 2010 at 21:20 Comment(0)
B
1

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

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.

Beavers answered 9/9, 2016 at 21:29 Comment(0)
H
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..

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.

Hierolatry answered 15/12, 2009 at 13:20 Comment(1)
In principal I totally agree, but right now I'm only trying to find out what is possible with a JTree. And so far I've found out that the tree works ok with such big data structures when it comes to scrolling and panning. But expanding many nodes is extermly time consumingDisband

© 2022 - 2024 — McMap. All rights reserved.