JDialog — обновить динамически добавленные узлы в JTree

У меня проблема с видимостью узлов JTree, которые я использую для своего JDialog. Когда я хочу добавить новый узел в модель, Jtree не обновляется.

Странно, ноды обновляются так, как должны, если я устанавливаю setRootVisible(true).

Вот код. заранее спасибо

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

public class TestClass {

JTree tree;
DefaultTreeModel dm;
JDialog dialog;

public TestClass(){
    JFrame frame = new JFrame("title");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

    JPanel showPane = new JPanel();
    showPane.setLayout(new BorderLayout()); 

    dm = new DefaultTreeModel(new DefaultMutableTreeNode("root"));
    tree = new JTree(dm);
    tree.setRootVisible(false);

    JButton button = new JButton("add node");
    button.addActionListener(new ActionListener(){

        public void actionPerformed(ActionEvent arg0) {
            DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();           
            dm.insertNodeInto(new DefaultMutableTreeNode("Node " + (root.getChildCount() + 1)), root, root.getChildCount());

            int c = root.getChildCount();
            System.out.println("child count: " + c);

            for(int i=0; i<c; i++){
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i);
                System.out.println("has node:" + node.getUserObject().toString());
            }
        }

    });

    showPane.add(tree, BorderLayout.CENTER);
    showPane.add(button, BorderLayout.PAGE_END);

    JComponent[] inputComponents = new JComponent[] {showPane};

    Object[] opButtons = {"OK"};

    JOptionPane optPane = new JOptionPane(inputComponents       
            , JOptionPane.PLAIN_MESSAGE             
            , JOptionPane.CLOSED_OPTION             
            , null                                      
            , opButtons                             
            , opButtons[0]);                            

    optPane.setPreferredSize(new Dimension(400 ,250));

    dialog = optPane.createDialog(null, "Create new Application Node");
    dialog.setLocationRelativeTo(frame);
    dialog.setVisible(true);

    if(optPane.getValue() != null){
        System.exit(0);
    }

}

public static void main(String arg[]){
    TestClass myClass = new TestClass();
}

}


person bioMind    schedule 13.10.2012    source источник
comment
Есть два фактора, которые объединяются, чтобы скрыть добавленные узлы. 1) Корень не виден. 2) Узлы не расширяются после обновления модели.   -  person Andrew Thompson    schedule 14.10.2012


Ответы (3)


Обязательно расширяйте путь от родителя нового узла к корню каждый раз, когда вы добавляете новый дочерний узел:

DefaultMutableTreeNode newChild = new DefaultMutableTreeNode("Node " + (root.getChildCount() + 1));
dm.insertNodeInto(newChild, root, root.getChildCount());
tree.expandPath(new TreePath(dm.getPathToRoot(newChild.getParent())));
person JB Nizet    schedule 13.10.2012
comment
Да, это работает как шарм, хотя это все еще смущает меня. Мне не нужно делать это для JFrame. Спасибо. - person bioMind; 14.10.2012
comment
@user1503578 user1503578 Обычно корневой узел JTree расширяется, но когда дерево создается, корневой узел не имеет дочерних элементов, поэтому его нельзя расширить. Обратите внимание, что даже когда корневой узел не виден, его расширенное состояние по-прежнему управляет видимостью его дочерних элементов. Позже, когда вы добавите новые узлы, они не будут отображаться, потому что корень свернут. - person Geoff Reedy; 14.10.2012
comment
@GeoffReedy в основном верно, но, придираясь ко мне, я бы сказал, что не может - это деталь реализации модели :-) - person kleopatra; 17.10.2012

Также проверьте другое решение:

   DefaultTreeModel model = (DefaultTreeModel) (tree.getModel()); 
   model.reload(); 

API говорит:

вызовите метод перезагрузки, если вы изменили TreeNodes, от которых зависит эта модель. Модель уведомит всех своих слушателей об изменении модели.

Для быстрой проверки попробуйте следующее:

public void actionPerformed(ActionEvent arg0) {
   DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
   dm.insertNodeInto(new DefaultMutableTreeNode("Node " + (root.getChildCount() + 1)), root, root.getChildCount());

   int c = root.getChildCount();
   System.out.println("child count: " + c);

   DefaultTreeModel model = (DefaultTreeModel) (tree.getModel()); // !!!
   model.reload();   // !!!

   for (int i = 0; i < c; i++) {
       DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i);
       System.out.println("has node:" + node.getUserObject().toString());
   }
}

Пожалуйста, смотрите следующий ответ для более подробной информации:

person Renat Gilmanov    schedule 13.10.2012
comment
не используйте перезагрузку для простых изменений, вместо этого убедитесь, что модель уведомляет соответствующим образом (defaultTreeModel будет при вставкеNodeInto) - person kleopatra; 17.10.2012

Ответ @JBNizet правильный, резюмируя:

  • вставка узла не оказывает автоматического влияния на состояние раскрытия родителя
  • поэтому, чтобы убедиться, что только что вставленный дочерний элемент виден, его родитель должен быть развернут

Чтобы добавить немного альтернативного API, чтобы сделать дочерний элемент видимым:

dm.makeVisible(new TreePath(newChild.getPath());

Что касается комментария @Geoff Reedy (выделено мной жирным шрифтом):

Обычно корневой узел JTree расширяется, но когда дерево создается, корневой узел не имеет дочерних элементов, поэтому его нельзя расширить.

cannot не является таким строгим: может ли он быть расширен (даже с нулевыми дочерними элементами), на самом деле зависит от реализации isLeaf модели. Возможно, корень никогда не является листом (даже без дочерних элементов), потому что его суть в том, чтобы не быть :-) Может быть достигнуто с помощью

final DefaultTreeModel model = new DefaultTreeModel(root) {

    @Override
    public boolean isLeaf(Object node) {
        if (isRoot(node)) {
            return false;
        }
        return super.isLeaf(node);
    }

    private boolean isRoot(Object node) {
        return node != null && node == getRoot();
    }

};

с такой реализацией корень всегда расширяется (видимый корень или нет), и новые вставленные прямые дочерние элементы будут отображаться, не делая их явно видимыми.

person kleopatra    schedule 17.10.2012