0

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:

enter image description here

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?

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
Kareem Elsayed
  • 295
  • 6
  • 22
  • 1
    Use a logical and consistent form of indenting code lines and blocks. The indentation is intended to make the flow of the code easier to follow! IDEs usually have a [shortcut for formatting code](https://www.google.com.au/?ion=1&espv=2#q=eclipse%20format%20code).. – Andrew Thompson Jun 23 '16 at 06:13
  • i did the auto format but didnt help – Kareem Elsayed Jun 23 '16 at 06:23
  • 1
    Well, good luck with it. Life's too short to deal with unfromatted code. – Andrew Thompson Jun 23 '16 at 06:29
  • ! i don`t understand your point ! – Kareem Elsayed Jun 23 '16 at 06:39
  • Your unformatted code is hard to read, but it is clearly wrong: _don't_ sleep on the [*Initial Thread*](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html); _do_ see [*Concurrency in Swing*](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) and [*How to Use Swing Timers*](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html). – trashgod Jun 23 '16 at 08:42
  • oh ok thanks for the note. any idea why this problem facing me with the JTree?? – Kareem Elsayed Jun 23 '16 at 09:06

1 Answers1

2

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.

image

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);
        }
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045