Adding and removing nodes from a JTree

60,923

I don't know why you are deleting and recreating all the nodes.

Update should always be done through the model. You have a couple of choices:

Update the model directly:

DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
model.insertNodeInto(new DefaultMutableTreeNode("another_child"), root, root.getChildCount());

Update the tree nodes and then notify the model:

DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();
root.add(new DefaultMutableTreeNode("another_child"));
model.reload(root);

The same applies for removing nodes.

The DefaultTreeModel has a removeNodeFromParent(...) which will update the model directly.

Or you can use the remove(...) method of the DefaultMutableTreeNode class. In which case you would need to do the reload().

Share:
60,923
Roman Rdgz
Author by

Roman Rdgz

Telecom Engineer

Updated on July 09, 2022

Comments

  • Roman Rdgz
    Roman Rdgz almost 2 years

    I have a very basic JTree. As I am on a rush, I'd prefer not to use TreeModel if it is not needed. I wrote a SSCCE to expose the problem:

    Sometimes I add a node. Other times I remove them. When I push Add, a node is correctly added. When I push Remove, it is supposed to remove the node, but it doesn't. Also, if I try adding more than one node, the tree stays with just the first node I added.

    I wrote an update method for the JTree, where I first erase all the nodes hanging from the root node, and then I look at which nodes and sub-nodes I have to create.

    What I am doing wrong here, apart from not using a TreeModel to operate into the tree?

    import java.awt.Dimension;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTree;
    import javax.swing.tree.DefaultMutableTreeNode;
    
    
    public class TreeTest {
        private JFrame myFrame;
        private JTree myTree;
        private JButton addButton, removeButton;
    
        private int numberOfNodes;
        private DefaultMutableTreeNode rootNode;
    
        private ArrayList<String> graphicIDS;
        private ArrayList<String> graphicInfo;
    
        public static void main (String [ ] args){
            new TreeTest();
        }
    
        public TreeTest() {
            graphicIDS = new ArrayList<String>();
            numberOfNodes = 0;
            graphicInfo = new ArrayList<String>();
            graphicInfo.add("Info A");
            graphicInfo.add("Info B");
            graphicInfo.add("Info C");
            graphicInfo.add("Info D");
    
            JPanel panel = new JPanel(new GridBagLayout());
            GridBagConstraints c = new GridBagConstraints();
            myFrame = new JFrame("JTree test");
            myFrame.setResizable(false);
            myFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    
            c.fill = GridBagConstraints.BOTH;
            c.anchor = GridBagConstraints.NORTH;
            c.gridx = 0;
            c.gridy = 0;
            c.gridwidth = 2;
            c.insets = new Insets(5,5,5,5);
    
            rootNode = new DefaultMutableTreeNode("Root node");
            myTree = new JTree(rootNode);
            myTree.setPreferredSize(new Dimension(200, 500));
            panel.add(myTree, c);
    
            c.gridwidth = 1;
            c.gridy++;
            removeButton = new JButton("Remove");
            removeButton.setEnabled(false);
            removeButton.addActionListener(new ActionListener (){
                @Override
                public void actionPerformed(ActionEvent e) {    
                    System.out.println("Removed curve "+(graphicIDS.size()));
                    graphicIDS.remove(graphicIDS.size()-1);
                    numberOfNodes--;
                    updateMeasurementsTree();
                }
            });
            panel.add(removeButton, c);
    
            c.gridx++;
            addButton = new JButton("Add");
            addButton.addActionListener(new ActionListener (){
                @Override
                public void actionPerformed(ActionEvent e) {
                    graphicIDS.add("Curve "+(numberOfNodes+1));
                    System.out.println("Added curve "+(numberOfNodes+1));
                    numberOfNodes++;
                    updateMeasurementsTree();
                }
            });
            panel.add(addButton, c);
    
            myFrame.getContentPane().add(panel);
            myFrame.pack();
            myFrame.setVisible(true);
        }
    
        public void updateMeasurementsTree(){
            rootNode.removeAllChildren();
    
            for(int i=0; i<numberOfNodes;i++){  
                String idString = graphicIDS.get(i);
                DefaultMutableTreeNode idNode = new DefaultMutableTreeNode("Graphic "+idString);
                rootNode.add(idNode);
                int randomValue = (int) Math.floor(Math.random()*graphicInfo.size());
                String infoString = graphicInfo.get(randomValue);
                DefaultMutableTreeNode infoNode = new DefaultMutableTreeNode("Info "+infoString);
                idNode.add(infoNode);
            }
            if(numberOfNodes==0) removeButton.setEnabled(false);
            else{
                removeButton.setEnabled(true);
                expandAll();
            }
        }
    
        public void expandAll() {
            int row = 0;
            while (row < myTree.getRowCount()) {
              myTree.expandRow(row);
              row++;
            }
        }
    }
    
  • kleopatra
    kleopatra over 12 years
    +1 - ecept for the reload ;-) The model has nodesWhereInsertedRremoved/Changed - dont nail me on the eact names, though) to notify its listeners after-the-fact. Reload is the last measure, f.i. after doing complex modifications in several depths of the tree
  • Roman Rdgz
    Roman Rdgz over 12 years
    Thanks a lot, I was making it way more complex than it really was
  • Nitesh Verma
    Nitesh Verma almost 11 years
    How about deleting a child value?
  • glend
    glend over 8 years
    for clarification; when removing nodes the nodeChanged() method causes buggy behaviour, reload() works fine though. this is because nodeChanged() doesn't collapse trees, reload() does.