Hope you are doing fine.
I have a JTree which I load lazily using database query (each node). I have a button on the screen and when user clicks the button I perform some insert/update/delete
in database and then add the model back in Jtree
with only root and its immediate children using an SQL (this collapses the tree and selection and all expanded nodes collapse which is expected since it is a lazily loaded tree)
What I want to accomplish is before user clicks button to insert/update/delete
, I read all the expanded state and save it in memory then when I re-initialize the JTree
I loop through those expanded children and call jtree.expandPath
but it does not expand the nodes :(.
I even added a TreeWillExpandListener
and in treeWillExpand
event I added code to get the children of the node from database and I see that query does get executed to get the childreen but JTree
still shows up as collapsed.
I really need your help. Please advise. Here is the code snippet.
package marketdatagui;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.EventListenerList;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.io.File;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
public class StressGroupModel
implements TreeModel,Serializable, Cloneable
{
protected EventListenerList listeners;
private static final Object LEAF = new Serializable() { };
private Map map;
private NodeData root;
private class NodeData{
String id;
String name;
public String toString(){
return name;
}
}
public StressGroupModel()
{
this.root = new NodeData();
root.id = "Root";
root.name = "Root";
this.listeners = new EventListenerList();
this.map = new HashMap();
开发者_C百科 List rootChildren = new ArrayList();
NodeData d1 = new NodeData();
d1.id = "5000007";
d1.name = "Name5000007";
rootChildren.add(d1);
NodeData d2 = new NodeData();
d2.id = "10000054";
d2.name = "Name10000054";
rootChildren.add(d2);
map.put(root.id, rootChildren);
}
public Object getRoot()
{
return root;
}
public boolean isLeaf(Object node)
{
return map.get(node) == LEAF;
}
public int getChildCount(Object node)
{
List children = children(node);
if (children == null)
return 0;
return children.size();
}
public Object getChild(Object parent, int index)
{
return children(parent).get(index);
}
public int getIndexOfChild(Object parent, Object child)
{
return children(parent).indexOf(child);
}
protected List children(Object node)
{
NodeData s = (NodeData)node;
Object value = map.get(s.id);
if (value == LEAF)
return null;
List children = (List)value;
if (!"Root".equals(s.id))
{
String[][] dbData = getChildren(s.id);
if (dbData != null)
{
children = new ArrayList(dbData.length);
for (int i = 0; i < dbData.length; i++)
{
NodeData d = new NodeData();
d.id = dbData[i][1];
d.name = dbData[i][1] + "Name";
children.add(d);
if ("R".equals(dbData[i][2]))
map.put(d, LEAF);
}
}
else
children = new ArrayList(0);
map.put(s.id, children);
}
return children;
}
private String[][] getChildren(String parent_uid){
String sql = "select parent_uid,child_uid,child_type from stress_groups_mapping "
+ " where parent_uid="+ parent_uid
+" order by parent_uid, child_uid";
return Util.getTableData(sql);
}
public void valueForPathChanged(TreePath path, Object value)
{
}
public void addTreeModelListener(TreeModelListener l)
{
listeners.add(TreeModelListener.class, l);
}
public void removeTreeModelListener(TreeModelListener l)
{
listeners.remove(TreeModelListener.class, l);
}
public Object clone()
{
try
{
StressGroupModel clone = (StressGroupModel)super.clone();
clone.listeners = new EventListenerList();
clone.map = new HashMap(map);
return clone;
}
catch (CloneNotSupportedException e)
{
throw new InternalError();
}
}
}
- Here is how I create the tree
public createTree{
JFrame f = new JFrame("Tree Dragging Tester"); DefaultMutableTreeNode root = new DefaultMutableTreeNode(new Object()); jtree = new JTree(new StressGroupModel()); TreeWillExpandListener treeWillExpandListener = new TreeWillExpandListener() { public void treeWillCollapse(TreeExpansionEvent treeExpansionEvent) throws ExpandVetoException { } public void treeWillExpand(TreeExpansionEvent treeExpansionEvent) throws ExpandVetoException { TreePath path = treeExpansionEvent.getPath(); Object node = path.getLastPathComponent(); ((StressGroupModel)jtree.getModel()).getChildCount(node); } }; jtree.addTreeWillExpandListener(treeWillExpandListener); f.getContentPane().add(jtree, BorderLayout.CENTER); f.setSize(300, 200); f.setVisible(true); }
- Here is how I save the expanded state
Enumeration paths = jtree.getExpandedDescendants(new TreePath(jtree.getModel().getRoot()));
- Do insert/update/delete DB stuffs
- Now re-initialize the model and add back to JTree (so it picks latest values from DB)
- Now I loop and call expand to expand the nodes that user expanded before he clicked the button but alas it stays collapsed :(
jtree.setModel(new StressGroupModel()); while (paths.hasMoreElements()) {
TreePath treePath = (TreePath) paths.nextElement(); try { jtree.expandPath(treePath); jtree.setSelectionPath(treePath); } catch(Exception ex){ } }
I found the solution.
Need an equals method and hashCode in my NodeData class, problem was internally after setting the new Model when I was trying to expand the path the equals returned false as default implementation of equals does a "shallow compare" i.e. only compares references, I had to override the hashCode and equals method and did a "Deep compare" in equals method.
Thanks
精彩评论