I have a JTree which is not supposed to be editable by the user in any way. It's purpose is to display some data only. Now, as the time passes, certain events in the program will cause the data in the tree to change. I.e. values in branches or leaves are updated or there is deletion of branches or leaves.
Besides the approach of recursively traversing the JTree to find the branch/node to update/delete (which I find very tedious) is there a standard way or pattern to handle this? I am using the default tree model. Was I supposed to implement my own tree model or something else? I only know the swing basics, so may be my question has a simple answer, I am just not sure.
Sorry for the newbie question. If I override getChild for example of treeModel, the display will not be refreshed right away, correct? An action from the user has to occur first to have the getChild called. So is an explicit traversal the approach to follow to have the tree updated automatically?
What I have done in the past is to make the user objects (the ones contained in the nodes) have a reference to the node they are contained in. Then if you change the object, it can cause the tree to be refreshed by telling the tree that its node was updated. No searching required.
Or more generally, you can keep references to specific nodes if you have code which will update those nodes, or delete them, or whatever.
Thank you Paul!!!
How is the tree updated? I looked into several apis e.g reload() of tree model or updateUI of JTree but it is not clear to me how I should update the tree. I understand your approach, but I am not familiar enough with the apis to understand how I should do the update i.e. how to tell the tree that the node was updated. Could you please give me an example?
@Rob: Hi, I checked the links but I can not understand much. The docs say that when the TreeModel changes we can detect it through the treeModelListener and there is an example. I can not see how the treeModelListener is related to JTree. If I use the defaultModeltree and I change the tree model, an event will be fired and if I have the listener I can get it, but how will the tree be updated, I can not see. I am not interested in knowing if the tree is changed by the user. I want to understand how to implement Paul's method. Change the tree model and tell the tree to refresh WITHOUT losing state. I.e. if a folder is expanded remains expanded etc. Thank you.
If you're using a DefaultTreeModel (by far the easiest choice) then notice it has methods with names like "nodeChanged" and "nodesWereInserted". You call these to tell the tree that you did the things that you did. (Yes, what happens under the covers is that a DefaultTreeModel registers the JTree as one of its TreeModelListeners and that's how the JTree finds out that changes happened in the model.)
As for having nodes stay expanded when you change their contents, that's a different question entirely. Expanded-ness apparently isn't part of the state you can control easily. (Notice that it's an attribute of the view, not an attribute of the model.) So put that part of the problem aside until you have the basic model-view connection implemented.
Thanks Paul. I will start the first part. I could not understand this because it does not say (http://download.oracle.com/javase/7/docs/api/javax/swing/JTree.html) that a JTree implements a TreeModelListener interface so I could not connect these in my mind. I will try the first part as you say, and hopefully the second part (leaving the view as is) will be not affected by the first part. Thanks!
@Paul Clapham: Hi, I followed your suggestion, and the tree is updated ok, but I am not sure if my implementation is exactly how you would expect it or if it is messy. I will describe what I did and I hope that you or at least someone can point out where my design should change (if it is indeed bad) so that I can understand how to work with Swing better.
The suggestion was to have pointers to the tree nodes inside the objects, so that when an object's value is changed, I can use the reference to update the tree.
Since the object containing the data of interest, should not be modified (not created by me and not allowed to change them), I created a hashmap, that corelates an object to a particular DefaultMutableTreeNode. Whenever an object was created, a new entry in the hasmap was added and a node in the tree also. I updated the tree using treeModel's nodeStructure changed. If an object was changed, I used the hashmap to get the treenode and update it. I am not sure if this is the way to go or I should implement a custom treemodel since these concepts are not clear in my mind yet. Another problem I am concerned with, is that the code is a little messy. I have a class named model, and I endup updating the treenodes inside the model.
I.e. The user presses a button. The view class does some processing in the actionPerformed and the processing function of my model is called. I have ended up doing the update of the tree inside my model. Is this bad design? I should return the result back to view class, to update the tree?
Any review comment is appreciated, since swing is confusing to me. Thank you.