|
Replies:
4
-
Last Post:
Jul 24, 2007 9:43 AM
by: kschaefe
|
|
|
|
|
|
|
DefaultTreeModel - what a mess!
Posted:
Jul 23, 2007 5:47 AM
|
|
|
As an aside to my earlier post on a JTree not updating after deleting a node during DnD, I am really struggling to come to grips with the DefaultTreeModel class and some of its methods.
Obviously, when you make changes to the underlying tree model, you need to notify the tree that these changes have been made. However, there seems to be a plethora of similar methods to achieve this and it's not at all clear from the JavaDoc which one(s) to call.
Consider for example simply deleting a node in a JTree. Firstly, there's the delete itself to be concerned about but am I supposed to call fireTreeNodesRemoved() or nodesWereRemoved() or both? In which order? Then you could argue that the tree's structure has changed so that brings in fireTreeStructureChanged() and nodeStructureChanged(). Do I need one or both of these as well? And then, because I am displaying the number of child nodes in each node's text I am going to need to call fireTreeNodesChanged() and nodeChanged() as well so that this display is correctly updated. Finally add to this the reload() method which the JavaDoc indicates needs to be called if you change the nodes in the model. That's a total of 7 methods just to let the tree know I deleted 1 node. Does anybody else think that's a bit too much effort required?
So what is the purpose of having so many similar methods, how many should be called and in what order should they be called?
-- And loving it,
-Q _________________________________________________ Qu0llSixFour@gmail.com (Replace the "SixFour" with numbers to email me)
|
|
|
|
|
|
|
Re: DefaultTreeModel - what a mess!
Posted:
Jul 23, 2007 11:36 AM
in response to: qu0ll
|
|
|
Yeah I agree.. it's a very busy class as you said.
The difference between these options as I conceive of it is one of scope and time. The more stuff you are declaring to need updating, the more time it could take to recalculate and redraw.
When you delete a single node, notify listeners via NodesRemoved. It's cheap and fast and doesn't waste time looking at nodes that nothing has changed on. I don't think it collapses the tree.
When you delete nodes here, there everywhere, you start to qualify for a structural change.. so call StructureChanged passing in a Path and it will refigure-out the tree from that path into its children ; I think it collapses the node.
Reload is the grandaddy of them all and reloads everything from the root and collapses everything also, as I remember.
There are lots of overlapping methods and scant advice on how to compare them.
|
|
|
|
|
|
|
|
Re: DefaultTreeModel - what a mess!
Posted:
Jul 23, 2007 1:15 PM
in response to: swv
|
|
|
I agree with what you say re nodesWereRemoved() versus nodeStructureChanged() but what about nodesWereRemoved() versus fireTreeNodesRemoved()? They seem to do essentially the same thing and neither is deprecated. This goes for all of those seemingly similar pairs of methods of the form nodesXXXX() and fireTreeNodesXXXX(). I just don't get it.
-- And loving it,
-Q _________________________________________________ Qu0llSixFour@gmail.com (Replace the "SixFour" with numbers to email me)
|
|
|
|
|
|
|
|
Re: DefaultTreeModel - what a mess!
Posted:
Jul 24, 2007 2:42 AM
in response to: qu0ll
|
|
|
HiQ,
happily jumping to the "mess" with nth coffee And agree that the *documentation* is a mess (by not existing), that's part of why the api is so hard to understand. Another part is that trees are harder than other datastructures ... and the DefaultTreeModel tries to take as much of the burden for certain contexts as possible.
Basically, it adapts a hierarchy of TreeNodes to a TreeModel and takes over the event notification where it can. It can completely take care, if the hierarchy is build of MutableTreeNodes. Then client code for single node mutations calls:
model.insertNodeTo(MutableTreeNode ...)
model.removeNodeFromParent(MutableTreeNode ..)
The model is designed around TreeNode (the above are the only methods which take the Mutable variant - which is not exactly true, see below *). But even a TreeNode which is not "officially" a member of the Mutable family might be removable/insertable into the tree hierarchy by code unrelated to Swing. In this case the client code must inform the model that its underlying hierarchy has changed. Code snippets (a bit pseudo, the nodesWere take arrays for position /and children)
// insert a node into a parent contained in the hierarchy
someClientInsert(parent, newChild);
model.nodesWereInserted(parent, positionOfNewChild)
// remove a node from a parent contained in the hierarchy
someClientRemove(parent, child);
model.nodesWereRemoved(parent, oldPositionOfChild, child)
All fireXX methods are protected - nothing to call from client code. And who ever wants to subclass a DefaultXXModel . But even then, the subclass would use as many of the cover methods as possible - there's no reason to burden new code with the nastiness of tree event details.
The model is a bit incomplete in that it doesn't cover the modification of a node. The missing api for symmetry;
void changeNode(MutableTreeNode, Object]
[*] The model is mis-behaving in that valueForPathChanged(..) does an unconditional type cast to MutableTreeNode, so will blow if the tree is build of simple TreeNodes. Which I consider a bug, especially so as it it undocumented (back to start <g>) Both the missing api and the bug might be reason enough to subclass.
To answer some of your questions: - exactly one of the removeNode/nodesWereRemoved/fireNodesRemoved is called each removal. Go with the highest level possible. - if the removed parent's representation is changed, call nodeChanged(parent). That's all. - be careful with reload/structureChanged: typically delete more visual state than you would like to.
HTH Jeanette
|
|
|
|
|
|
|
|
Re: DefaultTreeModel - what a mess!
Posted:
Jul 24, 2007 9:43 AM
in response to: kleopatra
|
|
|
I have to agree with Jeanette. But to add some points.
I like JTree, but I do not like DefaultTreeModel. JTree's counterpart JTable has a nice collection of interface, abstraction, and default implementation, which is lacking here. The JTree has only the interface and default implementation. Where's the abstraction?
Part of the problem of using DefaultTreeModel is that it just doesn't cut the mustard when it comes to working with data outside of DefaultMutableTreeNodes. It is not easy, for instance, to create a hierarchy of files (as a file system) because you need to place the file into a TreeNode to be effective. How do you notify the model that children have changed? Do you keep copies of the child files as TreeNodes? Do you have a custom TreeNode that lazily wraps the children as TreeNodes when requested? Problems, problems.
So, what's missing to make the life of everyone easier is the AbstractTreeModel. There are a couple of implementations available on the Web, and an RFE filed at Sun.
The reason that this tangent is important to you is that in a lot of places where people discuss AbstractTreeModel, there tends to be example models built on them. Delving into the code for such examples will help you to better design your model and provide useful examples for how (other) developers use the fireXXX methods.
Karl
|
|
|
|
|