when to reimplement hashcode()? JTree with custom nodes, expandPath() fails
Hello,
I found thatJTree.expandPath(path) failed with my JTree consisting of custom nodes.
Here,class MyTreeNodeextends DefaultMutableTreeNode.
TreePath displayNode(MyTreeNode node){
TreePath newPath =new TreePath(node.getPath());
// for some reason this is necessary
// otherwise node does not display
tree.scrollPathToVisible (newPath);
// expand
// TODO fix bug. does not work
tree.expandPath(newPath);
// also does not work
//tree.expandPath(tree.getPathForRow(0));
// also does not work
//tree.makeVisible(newPath);
// System.out.println("tree.isExpanded(" + newPath + ") " + tree.isExpanded(newPath));
return newPath;
}
After some googling, I found this thread reporting the same problem:
http://groups.google.com/group/comp.lang.java.gui/browse_frm/thread/cf52cacb3d9b686f/49602f5d70869687#49602f5d70869687
the OP advised
"I learned not too long ago the error of my ways. I had implemented my own tree nodes (interface TreeNode) without implementing the hashCode method in the nodes. As a result, each instance of a node was interpreted as unique by tree-processing classes. The problem was solved when I implemented hashCode in every class that implemented TreeNode."
However, I reimplemented hashcode but itdid not work:
publicint hashCode(){
return myId;// myId is unique for a tree node.
}
publicboolean equals(Object arg0){
return id == ((MyTreeNode) arg0).id;
}
Anyone knows what the solution is?
thanks,
Anil
[2465 byte] By [
anilp1a] at [2007-10-3 2:44:12]

expandPath and expandRow will not do anything if the last node in the path is a leaf.How about tryingTreePath newPath = new TreePath(node.getParent().getPath());
> expandPath and expandRow will not do anything if the
> last node in the path is a leaf.How about trying
>
> TreePath newPath = new
> TreePath(node.getParent().getPath());
Thanks for replying.
Yes, I was aware that expandPath() does nothing on a leaf and did try that. However, displayNode() is called on the internal nodes too so it should still work. But it does not work.
Context: I am visiting each node in the tree. If it is inside a sub-tree, expand path so it is visible.
How are you creating the tree structure.? The tree model needs to be made aware of changes to nodes via
DefaultTreeModel.nodeChanged(TreeNode),
DefaultTreeModel.nodeStructureChanged(TreeNode), or
DefaultTreeModel.reload()
each time you add/remove children from a TreeNode.
Without code to look at it's just guesswork.
Here is code that works, how is yours different?
public static void main(String[] args) {
DefaultMutableTreeNode a = new DefaultMutableTreeNode("A");
DefaultMutableTreeNode b = new DefaultMutableTreeNode("B");
DefaultMutableTreeNode c = new DefaultMutableTreeNode("C");
DefaultMutableTreeNode d = new DefaultMutableTreeNode("D");
DefaultMutableTreeNode e = new DefaultMutableTreeNode("E");
DefaultTreeModel model = new DefaultTreeModel(a);
JTree tree = new JTree(model);
a.add(b);
b.add(c);
c.add(d);
d.add(e);
tree.expandPath(new TreePath(d.getPath()));
JFrame f = new JFrame("Tree Test");
f.add(tree);
f.setBounds(100,100,300,300);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
Thanks for replying.
1) Inserting and deleting are done thus:
treeModel.removeNodeFromParent(node);
treeModel.insertNodeInto(nodeToInsert, (MutableTreeNode) parent, parent.getIndex(node));
treeModel.insertNodeInto(nodeToInsert, (MutableTreeNode) node, node.getChildCount());
2) my tree nodes extend DefaultMutableTreeNode with their own renderer.
3) I am able to get a simple toy program that also extends DefaultMutableTreeNode, to expandPath().
I am trying to isolate the reason it is not expanding in my application.
thanks,
Anil
The strange thing I am finding is - when I override hashcode() and equals() in MyTreeNode, it expands partially ie. only the first level expands. 2nd and greater levels of nesting do not expand.
Another thing I find is - I have a user object for MyTreeNode viz. VisualNode.
When I register a tree expansion listener:
tree.addTreeExpansionListener(new TreeExpansionListener() {
public void treeExpanded(TreeExpansionEvent evt) {
TreePath tp = evt.getPath();
System.out.println("Expansion event, path " + tp);
}
public void treeCollapsed(TreeExpansionEvent evt) {
TreePath tp = evt.getPath();
System.out.println("Collapse event, path " + tp );
}
});
It prints out the user object?
Expansion event, path [VisualNode@a, VisualNode@a] VisualNode@a
I wonder why it partially expands the tree, and only at the first level.
-
Anil
Interestingly,
System.out.println("has tree been expanded? " + tree.hasBeenExpanded(newPath));
shows up "true" even though the internal node is still collapsed.
However, the TreeWillCollapse event listener trace does not print that it has immediately collapsed after the claimed "expanding" - ruling that out.
Question: Why does it claim to have been expanded even though it is still collapsed?
> Interestingly,
> System.out.println("has tree been expanded? " +
> tree.hasBeenExpanded(newPath));
> shows up "true" even though the internal node is
> still collapsed.
> However, the TreeWillCollapse event listener trace
> does not print that it has immediately
> collapsed after the claimed "expanding" - ruling that
> out.
update: As a workaround, I used the expandAll() method listed in Java Almanac to expand the entire tree - not just the subtree under that node. I was surprised to find it says that expanding must be done bottom up!-Anil
Your my hero, the hashcode-equals-thing was the solution for my problem (searched about 6h)