Question

I'm having some bother understanding why I cannot get a TreeModelChanged listener to respond to changes in the model which it subscribes to.

I have managed to reproduce the problem in a small example.

The SysOut message does not print to the console whenever a new node is added to the tree.

I intend to replace the SysOut message with some commands to redraw the tree. At the moment I am using a SysOut message just to prove that the listener is not being fired.

Am I missing something fundamental?

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;


public class TreeTest {

    private JTree t;
    private DefaultTreeModel m ;

    public static void main(String[] args) {
         new TreeTest();

    }

    public TreeTest() {

        //Draw Frame & Panel  - set dimensions
        JFrame f = new JFrame();
        f.setSize(new Dimension(800,600));
        JPanel p = new JPanel();
        p.setSize(new Dimension(800,600));



        //Create a Tree Model. Give it a String at the root.
        m = new DefaultTreeModel(new DefaultMutableTreeNode("Root"));

        //Create a tree and add the Model to it
        t = new JTree();
        t.setModel(m);


        //Try a Tree Model Listener
        m.addTreeModelListener(new TreeModelListener() {

            private void doSomething() {
                //Should fire whenever a node is added to the model
                System.out.println("Responding to TreeModelListener");
            }
            @Override
            public void treeStructureChanged(TreeModelEvent e) {
                doSomething();

            }

            @Override
            public void treeNodesRemoved(TreeModelEvent e) {
                doSomething();

            }

            @Override
            public void treeNodesInserted(TreeModelEvent e) {
                doSomething();

            }

            @Override
            public void treeNodesChanged(TreeModelEvent e) {
                doSomething();

            }
        });     

        //Add listener to a button which adds nodes to the tree when clicked
        JButton addNode = new JButton("Add node");
        addNode.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("New Node");
                DefaultMutableTreeNode root = (DefaultMutableTreeNode) m.getRoot();
                root.add(newNode);
            }
        });

        JScrollPane s = new JScrollPane(t);


        p.add(s);
        p.add(addNode);

        p.setVisible(true);
        f.add(p);
        f.setVisible(true);
    }

}
Was it helpful?

Solution

that's because the model doesn't know about the addition, it happens under its feet. Use the methods on DefaultTreeModel to do the insertion:

model.insertNodeInto(newNode, root, root.getChildCount())

Edit

a TreeNode is just a (more or less) dumb data structure. As you can see in the api, it's not an Observable, so there is no way for the model which uses that data structure to detect if anything changed on the node. To make it aware of the change, you have to do one of two things

  • use the node manipulation methods of the model
  • update the node and notify the model manually (calling nodesWereInserted)

The first is the preferable way (keeps control where it belongs), the second might be needed in more complex contexts (though I would strongly recommend to never do it, that's why SwingX DefaultTreeTableModel doesn't have them exposed :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top