Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: GUI и Java FX приложения > TreeModel and TreeModelListener - изменение модели


Автор: User1302 5.9.2011, 16:53
Здравствуйте, форумчане!

Пожалуйста, помогите разобраться.
Не получается перерисовывать дерево. Дерево представляет собой группы связанных лиц. То есть: List<List<Person>>. Из главного узла могут удаляться группы List<Person>, а также из конкретной группы List<Person> могут быть удалены лица Person.

Дерево строится из модели.
Модель реализует TreeModel. Данные берутся из списка списков List<List<Person>>.

Проблема: при удалении лица дерево совсем пропадает из контейнера.
В модели дерева такие переменные: List<List<Person>> root - корневой узел, группа лиц List<Person> group, лицо Person p
Уведомление слушателей происходит так:
Код

final EventListener[] listeners = listenerList.getListeners(TreeModelListener.class);
        final TreeModelEvent event = new TreeModelEvent(this, new Object[]{root, group, p});
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < listeners.length; i++) {
//                    ((TreeModelListener) listeners[i]).treeStructureChanged(event);
                    ((TreeModelListener) listeners[i]).treeNodesRemoved(event);
                }
            }
        });

Если вызываю метод TreeModelListener.treeStructureChanged(new TreeModelEvent(this, new Object[]{root})); - дерево перерисовывается, только сворачивается. Хочется, чтоб оставалось несвернутым.

Вот полный рабочий код:
Код


import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.EventListener;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.EventListenerList;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public class TreeExample {

    public static void main(String[] args) throws InterruptedException {

        //Подготавливаем список для модели дерева
        List<List<Person>> groups = new ArrayList<List<Person>>();
        List<Person> group1 = new ArrayList<Person>();
        List<Person> group2 = new ArrayList<Person>();

        Person person1 = new Person();
        Person person2 = new Person();
        Person person3 = new Person();
        Person person4 = new Person();

        group1.add(person1);
        group2.add(person2);
        group2.add(person3);
        group2.add(person4);

        groups.add(group1);
        groups.add(group2);

        //Подготавливаем модель и дерево
        final JTree tree = new JTree();
        ExampleTreeModel model = new ExampleTreeModel();
        model.setRoot(groups);
        tree.setModel(model);

        //Подготавливаем фрейм и запускаем его
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setBounds(500, 500, 500, 500);

                JScrollPane scrollPane = new JScrollPane(tree);
                frame.add(scrollPane);

                frame.setVisible(true);
            }
        });

        //имитируем удаление Person-a из списка
        Thread.sleep(3000);
        group2.remove(person4);
        model.personRemoved(person4, group2);
    }
}

//Модель дерева. Источник данных - простой список списков List<List<Person>>
class ExampleTreeModel implements TreeModel {

    private List<List<Person>> root;
    private EventListenerList listenerList = new EventListenerList();

    public void setRoot(List<List<Person>> root) {
        this.root = root;
    }

    @Override
    public Object getRoot() {
        return root;
    }

    @Override
    public Object getChild(Object parent, int index) {
        if (((List) parent).size() <= index) {
            return null;
        }
        return ((List) parent).get(index);
    }

    @Override
    public int getChildCount(Object parent) {
        if (parent instanceof Person) {
            return 0;
        }
        return ((List) parent).size();
    }

    @Override
    public boolean isLeaf(Object node) {
        return (node instanceof Person);
    }

    @Override
    public void valueForPathChanged(TreePath path, Object newValue) {
    }

    @Override
    public int getIndexOfChild(Object parent, Object child) {
        if (parent instanceof Person) {
            return 0;
        }
        if (parent == root) {
            if (root.contains((List) child)) {
                return root.indexOf(child);
            } else {
                return 0;
            }
        } else {
            return ((List) parent).indexOf(child);
        }
    }

    @Override
    public void addTreeModelListener(TreeModelListener l) {
        listenerList.add(TreeModelListener.class, l);
    }

    @Override
    public void removeTreeModelListener(TreeModelListener l) {
        listenerList.remove(TreeModelListener.class, l);
    }

    //Метод для уведомления модели о том, что удален Person из списка.
    //В методе - уведомление слушателей модели. В нашем случае - tree
    public void personRemoved(Person p, List<Person> group) {
        final EventListener[] listeners = listenerList.getListeners(TreeModelListener.class);
        final TreeModelEvent event = new TreeModelEvent(this, new Object[]{root, group, p});
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < listeners.length; i++) {
//                    ((TreeModelListener) listeners[i]).treeStructureChanged(event);
                    ((TreeModelListener) listeners[i]).treeNodesRemoved(event);
                }
            }
        });
    }
}

//Сущность для построения иерархии в дереве
class Person {

    private long id;
    private String title;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}



Заранее спасибо!

Автор: jk1 6.9.2011, 03:29
Код

TreeModelListener.treeStructureChanged()

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

Автор: User1302 6.9.2011, 09:27
Цитата

jk1 Можно попробовать вызывать не от root, а от изменяемого узла

Пробовал вместо:
Код

final TreeModelEvent event = new TreeModelEvent(this, new Object[]{root, group, p});

создавать событие так:
Код

final TreeModelEvent event = new TreeModelEvent(this, new Object[]{group, p});

То есть нет от корневого узла root, а от узла, кот. изменяется - проблема та же.

Думаю, что неверно формирую обьект события TreeModelEvent. 
Или, неверно реализую методы TreeModel.

Буду искать..

Автор: User1302 7.9.2011, 12:10
В нете ничего не могу найти пока smile 

Может кто ответит на вопрос, если я сформулирую его несколько иначе:

Есть список внутри которого находятся обьекты. (В моем случае List<Person>).
Этот список наполняется пускай таким-себе "менеджером лиц" (что-то вроде PersonManager).

Я хочу построить из этого списка простенькое дерево такого вида: корневой узел - List, листы - Person.
Проще всего сделать дерево с помощью модели, так удобно и логично.

Теперь представим, что в логике программы менеджер лиц удаляет из списка лицо List<Person>.remove(person);

Вот теперь нужно сказать об этом дереву, чтоб оно отцепило от себя один лист Person.

Как это сделать правильно?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)