JTree model.nodechanged(Node) loses data

元气小坏坏 提交于 2019-12-12 05:38:54

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!