Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JTree: speed up drawing of 1000+ children nodes from objects retrieved from database?

Tags:

java

swing

jtree

When I retrieve 1000+ java objects from the database, it is done very quickly. I end up with List<Object> matching my query.

The problem is drawing these objects onto the Jtree.

For example, I have a parentID of a given node. When this node (DefaultMutableTreeNode) is double clicked (TreeMouseListener.class), it will display direct children of this node, not all descendants (although this might be required later if possible but not right now).

The problem is that this jtree drawing operation takes very long time to complete adding 1000+ children DefaultMutableTreeNodes for the selected parent node.

ex) 1000 of new DefaultMutableTreeNode(Person person);

How can this drawing process be sped up?

I am not using any custom cell renderer nor am I displaying anything other than small bits of text for each node.

like image 788
KJW Avatar asked Oct 10 '22 14:10

KJW


2 Answers

You'll need to time where the slowdown is but I doubt it is just creating DefaultMutableTreeNodes which should be faster than loading the Person objects from the database. It's unlikely to be the painting (unless your Person#toString() is very slow) since there won't be a thousand nodes on the screen.

My guess is that you are adding the nodes one-by-one, causing a thousand change events instead of adding all the children at once. You should add the thousand child nodes to the parent node directly and then call DefaultTreeModel#nodeStructureChanged(node) on the parent node.

If that is still slow, it's time for a SSCCE. For example, pressing the button on my system shows no delay at all:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

public class TestJTree {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                final DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
                final DefaultTreeModel model = new DefaultTreeModel(root);
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.getContentPane().add(new JScrollPane(new JTree(model)));
                frame.getContentPane().add(new JButton(
                        new AbstractAction("Add thousand children") {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        int offset = root.getChildCount() + 1;
                        for (int i = 0; i < 1000; i++) {
                            DefaultMutableTreeNode child = new DefaultMutableTreeNode(
                                    "Person " + (i + offset));
// adding child with event (but isn't much slower really)
//                                model.insertNodeInto(child, root, root.getChildCount());
                            root.add(child);
                        }
                        model.nodeStructureChanged(root);
                    }
                }), BorderLayout.PAGE_END);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}
like image 96
Walter Laan Avatar answered Oct 13 '22 10:10

Walter Laan


You're probably creating 1000+ DefaultMutableTreeNodes to put your List in. The problem is creating that many objects quickly, and translating your objects to DefaultMutableTreeNode. If you don't create all of those objects you can improve your performance. I'd suggest just writing your own implementation of TreeModel that works directly with your object model so you don't have to recreate that many objects over again. That should improve your speed dramatically. I've put 10,000 objects in JTree before (I did it but it probably wasn't that great an idea), but I had to write my own TreeModel so I didn't have to recreate those objects.

However, as with all performance problems you should profile it first to figure out where you are spending time and address that issue. If it turns out it's this problem then you can do that. You don't need to try and create your own graphics drawing routines because that's significantly more work than writing your own TreeModel.

Another option is to fetch the tree on demand as it's needed. So fetch the root then as the user expands each node fetch its children from the server. The user can't look at all 1000+ nodes at once anyway so this will dramatically reduce the amount you are transferring over the network and less time spent on the server.

like image 28
chubbsondubs Avatar answered Oct 13 '22 09:10

chubbsondubs