3

I have filtered successfully a JTree using the View filtered approach (in the tree render, setting preferred component size to 0 for the items filtered out). Please see [Filtering on a JTree

I have a scaling environment with more than 1 million tree items.

The problem is that when some tree items are filtered out, the performance decreases considerably (expanding tree, scrolling is very slow).

My code is the following:

public static class TreeRenderer extends DefaultTreeCellRenderer
{
    @Override
    public Component getTreeCellRendererComponent( final JTree tree, final Object value, final boolean selected,
                                                    final boolean expanded, final boolean leaf, final int row, final boolean hasFocus )
    {
        // Invoke default Implementation, setting all values of this
        super.getTreeCellRendererComponent( tree, value, selected, expanded, leaf, row, hasFocus );

        if( !isNodeVisible( (DefaultMutableTreeNode)value ) )
        {
            setPreferredSize( new Dimension( 0, 0 ) );
        }
        else
        {
            setPreferredSize( new Dimension( 200, 15 ) );
        }

        return this;
    }
}

public static boolean isNodeVisible( final DefaultMutableTreeNode value )
{
    // In this example all Nodes without a UserObject are invisible
    return value.getUserObject() != null;
}

If I change the values (width, height) of setPreferredSize(new Dimension(0,0)) by other than 0, the performance increases to normal.

What is the deal about setting a zero-sized component in a Jtree? What am I missing? Is there I way I can sort this out using still the View approach?

Thanks

patxeco
  • 41
  • 4

1 Answers1

1

That's an interesting one. Unfortunately, I can not offer a solution, but at least think to have found the reason for the performance drop.

I started investigating this, led by a gut feeling caused by method comments like that of JTree#setRowHeight(int). Particularly, I looked for places where a height of 0 might have a similar, special meaning, and cause undesired computations.

And I found what I think is the actual reason for the performance issue. This led through some (non-public) classes that one usually is not concerned with, but in the end, the performance issue seems to be caused by the javax.swing.tree.VariableHeightLayoutCache.TreeStateNode#hasValidSize() method:

/*
 * Returns true if this node has a valid size.
 */
public boolean hasValidSize() {
    return (preferredHeight != 0);
}

This method is used to decide whether some component state has to be updated. When the preferred size is 0, then this method "validates" the node state - leading again to a preferred height of 0, which is considered as being "invalid". This causes many repeated updates, each involving a call to the getTreeCellRendererComponent method of the cell renderer, which consequently is called several million times for a tree with 1 Million nodes (in contrast to a few thousand calls in total when the preferred height is not 0).


Sorry, I know, this does not really help you much. The respective class is not public, and creating an own implementation would imply building some considerable infrastructure (possibly with own layout caches and own Tree UIs...).

I'm not sure whether model-based filtering could be a viable option for you - particularly because I know that this is not trivial either, unless one creates a completely new tree model, which in turn may not be the best idea when dealing with millions of nodes...


However, maybe this insight helps others to find a solution. And anyone who finds a good solution for this (or view-based filtering on JTrees in general) would receive a +1 (and maybe some bounty) from me. A "good" solution here means that it should not involve any hacks. Particularly, the current solutions in the above mentioned question are "hacks", as they cause undesired behavior (for example, that the hidden nodes will still be traversed when navigating through the tree with the keyboard).

Marco13
  • 53,703
  • 9
  • 80
  • 159