Как я могу обновить JTree после добавления некоторых узлов к базовой модели?

В первую очередь, позвольте мне сказать, что я не использую DefaultTreeModel. Я реализую свой собственный TreeModel, таким образом, я не могу использовать материал DefaultXXX. Проблема - это: Через некоторый addStuff () методы, которые определяет моя модель, я добавляю узлы к базовой структуре данных. Я затем уведомляю слушателей путем вызова treeNodesChanged () в addStuff () функция (я Знаю, что существуют treeNodesInserted методы, но это - то же самое. Это просто уведомляет слушателей с другим методом). Теперь, один из слушателей является статическим классом в моей основной форме, и этот слушатель может сказать JTree, который также содержится в моей основной форме, для обновления себя. Как я говорю JTree "перезагружать" некоторых или все его узлы из модели?

ОБНОВЛЕНИЕ: Найденный этим вопросом, что, хотя не точно то же, это дает ответ, я хочу.

ОБНОВЛЕНИЕ 2: Моя проблема не состояла в том, как уведомить средство просмотра (JTree), а скорее каким образом должен jtree быть перезагруженным после уведомления из модели.

В первую очередь, позвольте мне сказать, что единственный способ, которым я знаю для обновления дерева для отражения базовых изменений, состоит в том, чтобы назвать updateUI () или снова использовать setModel () метод. По существу моя проблема - это:

Предположим, что TreeModelListener был просто уведомлен (через TreeModelListener API), что изменение произошло в модели. Хорошо, что теперь?

У меня есть эта проблема, потому что JTree не реализует TreeModelListener. Таким образом, слушатель, в моей ситуации, является контейнером JTREE или внутренним классом, реализовывая Слушателя, живя под тем же контейнером как Jtree.

Поэтому предположите, что я - реализация TreeModelListener, живя счастливо в JForm с моим братом JTree. Внезапно мой метод treeNodesInserted (TreeModelEvent evt) называют. Что я делаю теперь? Если я называю Jtree.updateUI () из меня, то Список слушателей модели выдает Исключение ConcurrentModification. Я могу назвать что-то еще кроме updateUI?

Я попробовал много вещей, но только updateUI обновил JTree. Таким образом, я сделал это за пределами слушателя. От JForm я просто называю метод модели, который изменяет undrlying структуру, и затем я называю updateUI. Никакой TreeModelListener не привыкает.

UPDATE3: Я узнал, что существуют неявные зарегистрированные TreeModelListeners. В addTreeModelListener моей модели (слушатель TreeModelListener) реализация я поместил отладку system.out строка:

System.out.println("listener added: " + listener.getClass().getCanonicalName());

и я видел этот вывод отладки как раз в то самое время, когда я выполнил jTree.setModel (модель):

слушатель добавил: javax.swing. JTree. TreeModelHandler

слушатель добавил: javax.swing.plaf.basic. BasicTreeUI.Handler

ConcurrentModificationException вызывается, потому что вызов к jtree.updateUI () ре регистрирует слушателя (только plaf, не оба), таким образом, он брошен, когда я называю updateUI в цикле уведомления слушателя. Единственный путь теперь для обновления дерева, делают это за пределами TreeModelListener. Какие-либо комментарии или идеи для лучшего решения? Я пропускаю что-то?

16
задан Community 23 May 2017 в 12:16
поделиться

4 ответа

Я всегда находил TreeModel немного запутанным. Я согласен с приведенным выше утверждением, что модель должна уведомлять представление о внесении изменений, чтобы представление могло перерисовываться. Однако при использовании DefaultTreeModel этого не происходит. Я считаю, что вам необходимо вызвать метод reload () после обновления модели. Что-то вроде:

DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();
root.add(new DefaultMutableTreeNode("another_child"));
model.reload(root);
15
ответ дан 30 November 2019 в 15:51
поделиться

Предполагается, что ваша TreeModel запускает TreeModelEvents при ее изменении, а JTree наблюдает за вашей моделью через TreeModelListener для обновления при изменении модели.

Так что, если вы правильно реализуете поддержку TreeModelListener , вам не нужно наблюдать за моделью и информировать JTree, поскольку он уже сам это делает. С точки зрения MVC, JTree - это ваше представление / контроллер, а TreeModel - это ваша модель (или, скорее, адаптер модели), который можно наблюдать. Если вы не знаете, как сделать подробное уведомление для TreeModelListener, используйте TreeModelListener.treeStructureChanged (..), чтобы уведомить об обновлении «всей модели» (предупреждение: может привести к потере выбора и состояний раскрытия узла).

3
ответ дан 30 November 2019 в 15:51
поделиться

ОКОНЧАТЕЛЬНОЕ ОБНОВЛЕНИЕ: Обнаружил проблему и решил ее : Следующие шаги решают проблему, (но см. Принятый ответ для лучшего решения и более глубокого объяснения проблемы) :

  1. Зарегистрированные неявные слушатели достаточно, чтобы сделать работу. Нет необходимости реализовывать собственный слушатель.
  2. При добавлении узлов и вызове treeNodesInserted () он не работает (JTree не обновляется). Но он работает с вызовом treeStructureChanged () .

Очевидно, неявные слушатели внутренне обновляют дерево так, как я хочу, но только в их реализации метода treeStructureChanged () . Было бы хорошо, если бы JTree предоставил этот «алгоритм» как функцию, чтобы ее можно было вызывать вручную.

2
ответ дан 30 November 2019 в 15:51
поделиться

«fiemap»

http://www.mjmwired.net/kernel/Documentation/filesystems/fiemap.txt

-121--3435751-

Generics use type erasure. Это в основном означает, что дженерики не более чем неявные слепки, так что когда вы делаете:

List<Integer> ...

это не отличается от обычного List и может содержать Integer s или что-либо на самом деле. Вы просто говорите Java привести get () к целочисленному (и другие вещи). Тип просто не сохраняется во время выполнения (в основном).

Массивы различаются. Массивы называются ковариантными . Это означает, что их тип сохраняется во время выполнения. Так что вы можете сделать:

List<Integer> list1 = new ArrayList<Integer>();
list2 = (List<String>)list1;
list2.add("hello");

что совершенно законно и будет компилировать и работать. Но

Integer[] arr1 = new Integer[10];
String[] arr2 = (String[])arr1; // compiler error

Но это становится более тонким, чем это тоже.

Integer[] arr1 = new Integer[10];
Object[] arr2 = (Object[])arr1;
arr2[5] = "hello"; // runtime error!

Что касается вашей функции. Когда вы пишете:

public static <T> T f(T x) {
  Integer[] arr = new Integer[4];
  T ret = (T) arr[2];
  return ret;
}

вы говорите компилятору вывести T , будучи типом аргумента и возвращаемым типом, из аргумента. Таким образом, при передаче Integer возвращаемым типом является Integer . При вызове

Integer i = f(new Integer(4));

компилятор просто выполняет ваши инструкции. Функция действительно принимает и возвращает Object в скомпилированном виде, но делает это

Integer i = (Integer)f(new Integer(4));

неявно.

Как и в приведенном выше примере List , ничто не останавливает возврат f () всего, что вам нравится, а не того, что должно быть возвращено на основе параметризованного типа.

-121--3133421-

Я также обнаружил, что реализация TreeModel немного сбивает с толку, когда дерево состоит не только из папок (root) и файлов (child), поэтому я использовал модель DefureTreeModel. Это работает на меня. Метод создает или обновляет JTree. Надеюсь, это поможет.

    public void constructTree() {       

        DefaultMutableTreeNode root =
                new DefaultMutableTreeNode(UbaEnv.DB_CONFIG);
        DefaultMutableTreeNode child = null;

        HashMap<String, DbConfig> dbConfigs = env.getDbConfigs();
        Iterator it = dbConfigs.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry pair = (Map.Entry) it.next();
            child = new DefaultMutableTreeNode(pair.getKey());

            child.add(new DefaultMutableTreeNode(UbaEnv.PROP));
            child.add(new DefaultMutableTreeNode(UbaEnv.SQL));
            root.add(child);
        }

        if (tree == null) {
            tree = new JTree(new DefaultTreeModel(root));
            tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
            tree.addTreeSelectionListener(new TreeListener());
        } else {
            tree.setModel(new DefaultTreeModel(root));
        }
}
5
ответ дан 30 November 2019 в 15:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: