Добавление и удаление узлов из JTree

У меня очень простой JTree. Поскольку я тороплюсь, я бы предпочел не использовать TreeModel, если он не нужен. Я написал SSCCE, чтобы выявить проблему:

Иногда я добавляю узел. В другой раз я их удаляю. Когда я нажимаю Add, узел добавляется правильно. Когда я нажимаю Remove, предполагается удалить узел, но это не так. Кроме того, если я попытаюсь добавить более одного узла, дерево останется только с первым добавленным узлом.

Я написал метод обновления для JTree, где я сначала стираю все узлы, висящие на корневом узле, а потом смотрю, какие узлы и подузлы мне нужно создать.

Что я здесь делаю неправильно, кроме того, что не использую TreeModel для работы с деревом?

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++;
        }
    }
}

person Roman Rdgz    schedule 28.10.2011    source источник
comment
Спешка может замедлить вас; использование модели, как предлагает @camickr, является правильным подходом. +1, кстати, для полного примера.   -  person trashgod    schedule 29.10.2011
comment
быстро или нет, вы должны уведомлять модель, если вы меняете узлы под ее ногами. Нет пути вокруг. @camickr показывает, как сделать, украшенный моим комментарием :-)   -  person kleopatra    schedule 29.10.2011


Ответы (1)


Я не знаю, почему вы удаляете и воссоздаете все узлы.

Обновление всегда должно выполняться через модель. У вас есть несколько вариантов:

Обновите модель напрямую:

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

Обновите узлы дерева, а затем уведомите модель:

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

То же самое относится и к удалению узлов.

DefaultTreeModel имеет removeNodeFromParent(...), который будет напрямую обновлять модель.

Или вы можете использовать метод remove(...) класса DefaultMutableTreeNode. В этом случае вам нужно будет выполнить reload().

person camickr    schedule 28.10.2011
comment
+1 - за исключением перезагрузки ;-) В модели есть nodesWhereInsertedRremoved/Changed - не прибивайте меня к именам актов, хотя), чтобы уведомить своих слушателей постфактум. Перезагрузка - последняя мера, т.е. после выполнения сложных модификаций в нескольких глубинах дерева - person kleopatra; 29.10.2011
comment
Большое спасибо, я сделал это намного сложнее, чем это было на самом деле - person Roman Rdgz; 31.10.2011
comment
Как насчет удаления дочернего значения? - person Nitesh Verma; 16.07.2013
comment
в целях разъяснения; при удалении узлов метод nodeChanged() вызывает ошибки, хотя reload() работает нормально. это потому, что nodeChanged() не разрушает деревья, а reload() делает. - person glend; 14.01.2016