Java: Swing: JTree and TreeModel: 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:
The root has changed. Then indices and children are null, path has length 1 and has as component the root of the tree.
Non-root node(s) have changed. Then path is the path to the parent location of the changed nodes, indices as usual contains the indices that actually have changed.
treeStructureChanged (path)(children and indices aren't used)
This event is used to reflect multiple things:
The TreeModel has got a new root.
If the model has lost its root (i.e. getRoot() now returns null), path must be null, otherwise path has length 1 and contain the new root as component. Unless you have cached the old root, you cannot see from the event alone whether the event means "new root" or "structural change" of the structure below the root (case 2.). Only in special cases does this matter, though.
The tree structure below a certain node has completely changed.
All information about all descendants must be considered invalid, as well as the leaf state of the node.
(special case of the previous) A node has only changed leaf status.
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)