JavaSwingJTree and TreeModel: TreeModelListener


TreeModelListener

I think all of the following has already been said in the TreeModel discussion, but some remarks from a TreeModelListener's perspective.:

treeNodesAdded(path, indices, children)

You must handle the case that the parent node was previously a leaf.

treeNodesRemoved(path, indices, children)

If all children have been removed, it is possible that the parent node turned into a leaf.

treeNodesChanged (path, indices, children)

This event does not reflect a structural change of the TreeModel. It may usually be ignored unless you want to react to such (in general, unknown) property changes (for example repaint the nodes, if you're JTree).

There are two cases to consider:

treeStructureChanged (path)

(children and indices aren't used)

This event is used to reflect multiple things:

Example

A TreeModelListener which handles many of the special cases and delegates to specialized methods. As it caches the root, it can only be used to listen to a single TreeModel (though for most purposes, it is not necessary to cache the root.)

import javax.swing.tree.TreePath;
import javax.swing.tree.TreeModel;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;

public abstract class AbstractTreeModelListener
   implements TreeModelListener
{
    private Object root;

    protected AbstractTreeModelListener(TreeModel data)
    {
        root = data.getRoot();
    }

    public final void treeNodesChanged(TreeModelEvent e)
    {
        if (e.getChildren() == null)
            rootChanged(e);
        else
            childrenChanged(e);
    }

    public final void treeNodesInserted(TreeModelEvent e)
    {
        childrenAdded(e);
    }

    public final void treeNodesRemoved(TreeModelEvent e)
    {
        childrenRemoved(e);
    }

    public final void treeStructureChanged(TreeModelEvent e)
    {
        TreePath path = e.getTreePath();

        if (path == null)
            newRoot(null);
        else if (path.getPathCount() == 1)
        {
            Object newRoot = path.getLastPathComponent();
        
            /* newRoot cannot be null (is part of TreePath) */

            if (!newRoot.equals(root))
            {
                root = newRoot;
                newRoot(newRoot);
            }
            else
                structureChanged(path);
        }
        else
            structureChanged(path);
    }

    /** Invoked when the root has changed (i.e. properties of the root node). */
    protected abstract void rootChanged(TreeModelEvent e);

    /** Invoked when children of the event's tree path have changed. */
    protected abstract void childrenChanged(TreeModelEvent e);

    /** Invoked when children were added to the event's tree path. */
    protected abstract void childrenAdded(TreeModelEvent e);

    /** Invoked when children were removed from the event's tree path. */
    protected abstract void childrenRemoved(TreeModelEvent e);

    /** Invoked when there is a new root (i.e. a new object). */
    protected abstract void newRoot(Object newRoot);
    
    /** Invoked when the structure below the event's tree path changed. */
    protected abstract void structureChanged(TreePath parentPath);
}

(C) 2001-2009 Christian Kaufhold (swing@chka.de)