I have a problem with JTree nodes visibility I use for my JDialog. When I want to add new node to the model the Jtree is not refreshed.
Strange is the nodes are updating just as they should if I set setRootVisible(true).
Here is the code. Thanks in advance
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
public class TestClass {
JTree tree;
DefaultTreeModel dm;
JDialog dialog;
public TestClass(){
JFrame frame = new JFrame("title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
JPanel showPane = new JPanel();
showPane.setLayout(new BorderLayout());
dm = new DefaultTreeModel(new DefaultMutableTreeNode("root"));
tree = new JTree(dm);
tree.setRootVisible(false);
JButton button = new JButton("add node");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
dm.insertNodeInto(new DefaultMutableTreeNode("Node " + (root.getChildCount() + 1)), root, root.getChildCount());
int c = root.getChildCount();
System.out.println("child count: " + c);
for(int i=0; i<c; i++){
DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i);
System.out.println("has node:" + node.getUserObject().toString());
}
}
});
showPane.add(tree, BorderLayout.CENTER);
showPane.add(button, BorderLayout.PAGE_END);
JComponent[] inputComponents = new JComponent[] {showPane};
Object[] opButtons = {"OK"};
JOptionPane optPane = new JOptionPane(inputComponents
, JOptionPane.PLAIN_MESSAGE
, JOptionPane.CLOSED_OPTION
, null
, opButtons
, opButtons[0]);
optPane.setPreferredSize(new Dimension(400 ,250));
dialog = optPane.createDialog(null, "Create new Application Node");
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
if(optPane.getValue() != null){
System.exit(0);
}
}
public static void main(String arg[]){
TestClass myClass = new TestClass();
}
}
Make sure to expand the path from the parent of the new node to the root each time you add a new child node:
DefaultMutableTreeNode newChild = new DefaultMutableTreeNode("Node " + (root.getChildCount() + 1));
dm.insertNodeInto(newChild, root, root.getChildCount());
tree.expandPath(new TreePath(dm.getPathToRoot(newChild.getParent())));
Please also check another solution:
DefaultTreeModel model = (DefaultTreeModel) (tree.getModel());
model.reload();
API says:
invoke reload method if you've modified the TreeNodes upon which this model depends. The model will notify all of its listeners that the model has changed.
For a quick verification try the following:
public void actionPerformed(ActionEvent arg0) {
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
dm.insertNodeInto(new DefaultMutableTreeNode("Node " + (root.getChildCount() + 1)), root, root.getChildCount());
int c = root.getChildCount();
System.out.println("child count: " + c);
DefaultTreeModel model = (DefaultTreeModel) (tree.getModel()); // !!!
model.reload(); // !!!
for (int i = 0; i < c; i++) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i);
System.out.println("has node:" + node.getUserObject().toString());
}
}
Please see the following answer for more details:
The answer by @JBNizet is correct, to summarize:
To throw in a bit of alternative api to make the child visible:
dm.makeVisible(new TreePath(newChild.getPath());
Regarding a comment by @Geoff Reedy (bolding by me):
Normally the root node of a JTree is expanded, but when the tree is created, the root node does not have any children so it cannot be expanded
the cannot is not so strict: whether or not it can be expanded (even with zero children) depends actually on the implementation of the model's isLeaf. Arguably, the root never is a leaf (even without children) because its essence is to not be :-) Can be achieved with
final DefaultTreeModel model = new DefaultTreeModel(root) {
@Override
public boolean isLeaf(Object node) {
if (isRoot(node)) {
return false;
}
return super.isLeaf(node);
}
private boolean isRoot(Object node) {
return node != null && node == getRoot();
}
};
with such an implementation, the root is always expanded (root visible or not) and newly inserted direct children will show up without making them explicitly visible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With