В первую очередь, позвольте мне сказать, что я не использую 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. Какие-либо комментарии или идеи для лучшего решения? Я пропускаю что-то?
Я всегда находил TreeModel немного запутанным. Я согласен с приведенным выше утверждением, что модель должна уведомлять представление о внесении изменений, чтобы представление могло перерисовываться. Однако при использовании DefaultTreeModel этого не происходит. Я считаю, что вам необходимо вызвать метод reload () после обновления модели. Что-то вроде:
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
DefaultMutableTreeNode root = (DefaultMutableTreeNode)model.getRoot();
root.add(new DefaultMutableTreeNode("another_child"));
model.reload(root);
Предполагается, что ваша TreeModel запускает TreeModelEvents при ее изменении, а JTree наблюдает за вашей моделью через TreeModelListener для обновления при изменении модели.
Так что, если вы правильно реализуете поддержку TreeModelListener , вам не нужно наблюдать за моделью и информировать JTree, поскольку он уже сам это делает. С точки зрения MVC, JTree - это ваше представление / контроллер, а TreeModel - это ваша модель (или, скорее, адаптер модели), который можно наблюдать. Если вы не знаете, как сделать подробное уведомление для TreeModelListener, используйте TreeModelListener.treeStructureChanged (..), чтобы уведомить об обновлении «всей модели» (предупреждение: может привести к потере выбора и состояний раскрытия узла).
ОКОНЧАТЕЛЬНОЕ ОБНОВЛЕНИЕ:
Обнаружил проблему и решил ее : Следующие шаги решают проблему, (но см. Принятый ответ для лучшего решения и более глубокого объяснения проблемы) :
treeNodesInserted ()
он не работает (JTree не обновляется). Но он работает с вызовом treeStructureChanged ()
. Очевидно, неявные слушатели внутренне обновляют дерево так, как я хочу, но только в их реализации метода treeStructureChanged ()
. Было бы хорошо, если бы JTree предоставил этот «алгоритм» как функцию, чтобы ее можно было вызывать вручную.
«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 ()
всего, что вам нравится, а не того, что должно быть возвращено на основе параметризованного типа.
Я также обнаружил, что реализация 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));
}
}