问题
I am testing some code with JTree
, and I noticed that model.reload()
gives different output than model.nodeChanged(currentNode)
. The correct output is obtained from model.reload()
. Here are my two outputs for the same code:
My code is as follows:
public class test {
private JFrame frame;
JTree tree;
DefaultMutableTreeNode root;
DefaultTreeModel model;
private Map<String, DefaultMutableTreeNode> treeMap;
public static void main(String[] args) {
test t = new test();
try {
Thread.sleep(1000 * 5);
} catch (Exception e) {
}
t.add_new_folder("Data", "trial 0");
t.add_new_folder("Data/trial 0", "trial 1");
t.add_new_folder("Data/trial 0/trial 1", "trial 2");
t.add_new_folder("Data", "trial 1");
try {
Thread.sleep(1000 * 5);
} catch (Exception e) {
}
t.add_new_folder("Data/trial 1", "trial 2");
t.add_new_folder("Data", "trial 2");
}
public test() {
frame = new JFrame("using reload");
tree = new JTree();
root = new DefaultMutableTreeNode("Data");
model = new DefaultTreeModel(root);
tree.setModel(model);
frame.getContentPane().add(tree, BorderLayout.WEST);
frame.setVisible(true);
frame.setSize(500, 500);
treeMap = new HashMap<>();
treeMap.put("Data", root);
}
public void add_new_folder(String path, String name) {
DefaultMutableTreeNode currentNode = treeMap.get(path);
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(name);
currentNode.add(childNode);
treeMap.put(path + "/" + name, childNode);
model.reload();
//model.nodeChanged(currentNode);
}
}
I need also to use model.nodeChanged()
as it keeps expanded paths the same unlike model.reload
. Any explanation and how to fix?
回答1:
Any idea why this problem facing me with the
Tree
?
As shown below, when correctly synchronized, the results are the same. As shown here, you can control visibility using expandRow()
and scrollPathToVisible()
. Using Thread.sleep()
will simply block the thread on which it is called. Because Swing is single-threaded, the results are unpredictable. Instead use java.swing.Timer or SwingWorker as needed.
Try to put some sleep between adding nodes and expand any path and in the continue code the problem will appear as stated in my question.
For the reasons mentioned, results using Thread.sleep()
are not reliable. Using java.swing.Timer
reveals the problem: nodeChanged()
reflects changes to the node itself. Because you've changed the children of the node, invoke nodeStructureChanged()
instead.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.Timer;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
public class Test {
private final JFrame frame;
private final JTree tree;
private final DefaultMutableTreeNode root;
private final DefaultTreeModel model;
private final Map<String, DefaultMutableTreeNode> treeMap;
private final boolean reload;
private int index;
private final String[] folders = {
"Data", "trial 0",
"Data/trial 0", "trial 1",
"Data/trial 0/trial 1", "trial 2",
"Data", "trial 1",
"Data/trial 1", "trial 2",
"Data", "trial 2"
};
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
new Test(true);
new Test(false);
});
}
public Test(boolean reload) {
this.reload = reload;
frame = new JFrame(String.valueOf(reload));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
treeMap = new HashMap<>();
root = new DefaultMutableTreeNode("Data");
model = new DefaultTreeModel(root);
tree = new JTree(model);
treeMap.put("Data", root);
frame.add(tree, BorderLayout.WEST);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer t = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (index < folders.length) {
addNewFolder(folders[index++], folders[index++]);
for (int i = 0; i < tree.getRowCount(); i++) {
tree.expandRow(i);
}
frame.pack();
}
}
});
t.start();
}
private void addNewFolder(String path, String name) {
DefaultMutableTreeNode currentNode = treeMap.get(path);
DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(name);
currentNode.add(childNode);
treeMap.put(path + "/" + name, childNode);
if (reload) {
model.reload();
} else {
model.nodeStructureChanged(currentNode);
}
}
}
来源:https://stackoverflow.com/questions/37981851/jtree-model-nodechangednode-loses-data