JTree избежать коллапса после перезагрузки

Я пытаюсь найти решение проблемы с коллапсом в JTree после перезагрузки. Ситуация:

JTree

[-] Office A
 |---[-] Office A.1
 |    |---[-] Office A.1.1
 |    |---[-] Office A.1.2
[-] Office B
 |---[-] Office B.1
 |    |---[-] Office B.1.1
 |    |    |---[-] Office B.1.1.1

Теперь мне нужно добавить Office A.1.3. Для этого я получаю Office A.1 и методом add(DefaultMutableTreeNode aNode) добавляю Office A.1.3.

OfficeA1.add(OfficeA13);

После этого я вызываю метод reload для DefaultTreeModel дерева.

Проблема в том, что после этого вызова дерево рушится все:

[+] Office A
[+] Office B

И я должен вручную расширить узел Office A, чтобы убедиться, что узел добавлен...

[-] Office A
 |---[-] Office A.1
 |    |---[-] Office A.1.1
 |    |---[-] Office A.1.2
 |    |---[-] Office A.1.3
[+] Office B

Мой код...

   DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root not visibile");
   DefaultMutableTreeNode usersRoot = new DefaultMutableTreeNode("Utenti");
   DefaultMutableTreeNode groupsRoot = new DefaultMutableTreeNode("Gruppi");
   DefaultMutableTreeNode officesRoot = new DefaultMutableTreeNode("Uffici")
   root.add(usersRoot);
   root.add(groupsRoot);
   root.add(officesRoot);

   JTree ccTree = new JTree(root);

и когда я добавляю узел...

Office anOffice = //get the correct office object
DefaultTreeModel model = (DefaultTreeModel)competenzaTree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();

DefaultMutableTreeNode n = (DefaultMutableTreeNode)root.getChildAt(0);

n.add(new DefaultMutableTreeNode(anOffice));
model.reload(n);

Проблема в узле officesRoot. Узел usersRoot и groupsRoot не является иерархическим.

Есть ли способ избежать такого поведения? Спасибо.

Вероятно, можно задать и другой способ: какой способ добавить/удалить узел из дерева, не вызывая коллапса всего дерева?

p.s. Я также прочитал этот пост, но он мне не помог.


person Fry    schedule 27.03.2014    source источник
comment
Рассмотрите возможность использования DefaltTreeModel#nodesWereInserted или DefaultTreeModel#insertNodeInto, что может быть проще.   -  person MadProgrammer    schedule 27.03.2014
comment
добавлен код ... и, как вы можете прочитать для обновления, я имею в виду добавление узла и перезагрузку дерева ... недостаточно ясно?   -  person Fry    schedule 27.03.2014
comment
@MadProgrammer, можете ли вы лучше объяснить в ответе, чтобы я мог попробовать ваше предложение?   -  person Fry    schedule 27.03.2014
comment
Я еще не тестировал это, но вместо вызова перезагрузки, который говорит JTree сбросить свои настройки и начать заново, использование вставкиNodeInto в модели должно (теоретически) только уведомлять дерево о том, что новый узел доступен, а не обновлять дерево. Я сделаю тест вместе.   -  person MadProgrammer    schedule 27.03.2014
comment
возможно, что-то не так в коде, который вы не показываете (скорее всего, ошибка заключается в отсутствии уведомления об изменении в модели)... использование перезагрузки является предупреждающим сигналом: пока вы не выполняете массовые изменения в нескольких поддеревьях, это не нужно . Не связанные: а) пожалуйста, изучите соглашения об именах Java и придерживайтесь их б) никогда не выполняйте ручное определение размера/расположение компонентов   -  person kleopatra    schedule 27.03.2014
comment
круто, спасибо за быструю очистку :-) Теперь не хватает только SSCCE для демонстрации проблемы в вашем коде.   -  person kleopatra    schedule 27.03.2014
comment
отредактировано... код для добавления узла   -  person Fry    schedule 27.03.2014
comment
Где я делаю неправильно?   -  person Fry    schedule 27.03.2014


Ответы (1)


Рассмотрите возможность использования DefaultTreeModel#insertNodeInto(DefaultMutableNode, DefaultMutableNode, int), который должен информировать таблицу JTree о том, что новый узел стал доступен, вызывать обновление JTree, но не должен влиять на текущее расширенное состояние дерева

Этот пример основан на примере из раздела Как использовать деревья.

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;

import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeSelectionModel;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;

public class TestTree extends JPanel {

    private JTree tree;
    private DefaultTreeModel model;
    private JButton btnAdd;
    private int childCount;

    public TestTree() {
        super(new BorderLayout());

        //Create the nodes.
        DefaultMutableTreeNode top = new DefaultMutableTreeNode("The Java Series");
        createNodes(top);

        model = new DefaultTreeModel(top);

        //Create a tree that allows one selection at a time.
        tree = new JTree(model);
        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        //Create the scroll pane and add the tree to it. 
        JScrollPane treeView = new JScrollPane(tree);

        //Add the split pane to this panel.
        add(treeView);

        btnAdd = new JButton("Add");
        btnAdd.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                TreePath treePath = tree.getSelectionPath();
                if (treePath != null) {
                    DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath.getLastPathComponent();
                    DefaultMutableTreeNode child = new DefaultMutableTreeNode("Child " + (++childCount));
                    model.insertNodeInto(child, node, node.getChildCount());
                }
            }
        });

        add(btnAdd, BorderLayout.SOUTH);
    }

    private class BookInfo {

        public String bookName;

        public BookInfo(String book) {
            bookName = book;
        }

        public String toString() {
            return bookName;
        }
    }

    private void createNodes(DefaultMutableTreeNode top) {
        DefaultMutableTreeNode category = null;
        DefaultMutableTreeNode book = null;

        category = new DefaultMutableTreeNode("Books for Java Programmers");
        top.add(category);

        //original Tutorial
        book = new DefaultMutableTreeNode(new BookInfo("The Java Tutorial: A Short Course on the Basics"));
        category.add(book);

        //Tutorial Continued
        book = new DefaultMutableTreeNode(new BookInfo("The Java Tutorial Continued: The Rest of the JDK"));
        category.add(book);

        //JFC Swing Tutorial
        book = new DefaultMutableTreeNode(new BookInfo("The JFC Swing Tutorial: A Guide to Constructing GUIs"));
        category.add(book);

        //Bloch
        book = new DefaultMutableTreeNode(new BookInfo("Effective Java Programming Language Guide"));
        category.add(book);

        //Arnold/Gosling
        book = new DefaultMutableTreeNode(new BookInfo("The Java Programming Language"));
        category.add(book);

        //Chan
        book = new DefaultMutableTreeNode(new BookInfo("The Java Developers Almanac"));
        category.add(book);

        category = new DefaultMutableTreeNode("Books for Java Implementers");
        top.add(category);

        //VM
        book = new DefaultMutableTreeNode(new BookInfo("The Java Virtual Machine Specification"));
        category.add(book);

        //Language Spec
        book = new DefaultMutableTreeNode(new BookInfo("The Java Language Specification"));
        category.add(book);
    }

    /**
     * Create the GUI and show it. For thread safety, this method should be
     * invoked from the event dispatch thread.
     */
    private static void createAndShowGUI() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            ex.printStackTrace();
        }

        //Create and set up the window.
        JFrame frame = new JFrame("TreeDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Add content to the window.
        frame.add(new TestTree());

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event dispatch thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

}
person MadProgrammer    schedule 27.03.2014