在将一些节点添加到底层模型后,如何刷新JTree? [英] How can I refresh a JTree after adding some nodes to the underlying model?

查看:127
本文介绍了在将一些节点添加到底层模型后,如何刷新JTree?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我要说我不使用DefaultTreeModel。我实现了自己的TreeModel,所以我不能使用DefaultXXX。问题是:通过我的模型定义的一些addStuff()方法,我将节点添加到底层数据结构。然后我通过在addStuff()函数中调用treeNodesChanged()来通知侦听器(我知道有treeNodesInserted方法,但它是相同的。它只是用不同的方法通知侦听器)。现在,其中一个监听器是我的主窗体中的静态类,这个监听器可以告诉JTree,它也包含在我的主窗体中,用于刷新自身。如何告诉JTree从模型中重新加载其部分或全部节点?

First of all, let me say that I dont use the DefaultTreeModel. I implement my own TreeModel, so i cant use the DefaultXXX stuff. The problem is this: Through some addStuff() methods which my model defines I add nodes to the underlying data structure. I then notify listeners by calling treeNodesChanged() inside the addStuff() function (I Know there are treeNodesInserted methods but it is the same thing. It just notifies listeners with a different method). Now, one of the listeners is a static class in my main form and this listener can tell the JTree, which is also contained in my main form, to refresh itself. How do I tell the JTree to "reload" some or all of its nodes from the model?

更新:
发现此问题尽管不完全相同,但它给出了我想要的答案。

UPDATE: Found this question that although not exactly the same, it gives the answer I want.

UPDATE 2:
我的问题不是如何通知查看者(JTree),而是在模型通知后应该以什么方式重新加载jtree。

UPDATE 2: My problem was not how to notify the viewer (the JTree), but rather in what way should the jtree be reloaded after the notification from the model.

首先让我说,我知道刷新树以反映底层更改的唯一方法是调用updateUI(),或重用setModel()方法。基本上,我的问题是:

First of all let me say that the only way i know to refresh a tree to reflect underlying changes, is to call the updateUI(), or reuse the setModel() method. Essentially, my problem is this:

假设TreeModelListener刚刚通知(通过TreeModelListener API)模型中发生了更改。好的,现在怎么办?

Suppose the TreeModelListener has just been notified (through the TreeModelListener API) that a change has occured in the model. Ok, what now?

我有这个问题,因为JTree没有实现TreeModelListener。因此,在我的情况下,监听器是JTree的容器,或实现监听器的内部类,与Jtree位于同一容器中。

I have this problem because the JTree does not implement TreeModelListener. So the listener, in my situation, is the JTree's container, or an internal class implementing the Listener, living under the same container as Jtree.

假设我是TreeModelListener实施,与我的兄弟JTree在JForm中幸福地生活。突然我的方法treeNodesInserted(TreeModelEvent evt)被调用。现在我该怎么做?如果我从我内部调用Jtree.updateUI(),那么模型的侦听器List会抛出ConcurrentModification异常。我可以调用updateUI以外的其他东西吗?

So suppose I am a TreeModelListener implementation, living happily in a JForm with my brother JTree. Suddenly my method treeNodesInserted(TreeModelEvent evt) is called. What do I do now? If i call Jtree.updateUI() from inside me, then the model's listeners List throws ConcurrentModification Exception. Can I call something else other than updateUI?

我尝试了很多东西,但只有updateUI刷新了JTree。所以我在听众之外做了。从JForm,我只是调用模型的方法来改变不正常的结构,然后我调用updateUI。没有使用TreeModelListener。

I tried a number of things, but only updateUI refreshed the JTree. So I did it outside of the listener. From the JForm, I just call the model's method that alters the undrlying structure, and then i call updateUI. No TreeModelListener gets used.

UPDATE3:
我发现注册了隐式TreeModelListeners。在我的模型的addTreeModelListener(TreeModelListener监听器)实现中,我放了一个debug system.out行:

UPDATE3: I found out that there are implicit TreeModelListeners registered. In my model's addTreeModelListener(TreeModelListener listener) implementation i put a debug system.out line:

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

我在执行jTree.setModel(模型)时看到了这个调试输出:

and I saw this debug output just when I executed jTree.setModel(model):


添加了监听器:javax.swing.JTree.TreeModelHandler

listener added: javax.swing.JTree.TreeModelHandler

监听器添加:javax.swing。 plaf.basic.BasicTreeUI.Handler

listener added: javax.swing.plaf.basic.BasicTreeUI.Handler

引起ConcurrentModificationException是因为对jtree.updateUI()的调用重新注册了监听器(仅限于plaf,而不是两者)所以当我在监听器通知循环中调用updateUI时抛出它。
现在刷新树的唯一方法是在TreeModelListener之外执行。有关更好解决方案的任何意见或想法吗?我错过了什么吗?

The ConcurrentModificationException is caused because a call to jtree.updateUI() re registers the listener (only the plaf, not both) so it is thrown when i call updateUI inside a listener notification loop. The only way now to refresh the tree is do it outside of TreeModelListener. Any comments or ideas for a better solution? Am I missing something?

推荐答案

我遇到了同样的问题:调用 treeNodesInserted()没有导致我的 JTree 更新其内容。

I faced the same "problem": calling treeNodesInserted() did not cause my JTree to update its contents.

但问题出在其他地方:我为 TreeModelEvent 使用了错误的构造函数。我以为我可以为 treeNodesInserted()创建 TreeModelEvent ,就像那样:

But the problem was in other place: I used wrong constructor for TreeModelEvent. I thought that I can create TreeModelEvent for treeNodesInserted() like that:

//-- Wrong!!
TreePath path_to_inserted_item = /*....*/ ;
TreeModelEvent tme = new TreeModelEvent(my_source, path_to_inserted_item);

这不起作用。

TreeModelEvent docs 中所述,此构造函数仅用于 treeStructureChanged()。但对于 treeNodesInserted() treeNodesRemoved() treeNodesChanged()我们应该使用另一个构造函数:

As stated in TreeModelEvent docs, this constructor is only needed for treeStructureChanged(). But for treeNodesInserted(), treeNodesRemoved(), treeNodesChanged() we should use another constructor:

TreePath path_to_parent_of_inserted_items = /*....*/ ;
int[] indices_of_inserted_items = /*....*/ ;
Object[] inserted_items = /*....*/ ;
TreeModelEvent tme = new TreeModelEvent(
      my_source,
      path_to_parent_of_inserted_items,
      indices_of_inserted_items,
      inserted_items
   );

此代码有效, JTree 更新内容正确。

This code works, and JTree updates its contents properly.

UPD:实际上,文档不清楚使用这些 TreeModelEvent s,尤其是 JTree ,所以,我想告诉我在试图弄清楚如何解决时遇到的一些问题处理所有这些事情。

UPD: Actually, docs are unclear about using these TreeModelEvents, and especially with JTree, so, I want to tell about some questions that came to me when I tried to figure out how to deal with all this stuff.

首先,Paralife注意到他的评论,插入/更改/删除节点或更改树结构时的情况正交。那么,

Firstly, as Paralife noted it his comment, cases when nodes are inserted/changed/removed, or when tree structure is changed, aren't orthogonal. So,

问题#1:我们何时应该使用 treeNodesInserted() / Changed() / Removed(),以及 treeStructureChanged()

Question #1: when should we use treeNodesInserted()/Changed()/Removed(), and when treeStructureChanged()?

答案: treeNodesInserted() / 已更改() / 如果只有所有受影响的节点具有相同的父节点,则可以使用Removed()。否则,您可以多次调用这些方法,或者只调用 treeStructureChanged()一次(并将受影响节点的根节点传递给它)。所以, treeStructureChanged()是一种通用方式,而 treeNodesInserted() / 已更改() / Removed()更具体。

Answer: treeNodesInserted()/Changed()/Removed() can be used if only all the affected nodes have the same parent. Otherwise you may make several calls to these methods, or just call treeStructureChanged() once (and pass the root node of affected nodes to it). So, treeStructureChanged() is a kind of universal way, while treeNodesInserted()/Changed()/Removed() are more specific.

问题# 2:至于 treeStructureChanged()是一种通用的方法,为什么我需要处理这些 treeNodesInserted() / 改变() / 删除()?只需拨打 treeStructureChanged()似乎更容易。

Question #2: As far as treeStructureChanged() is a universal way, why do I need to deal with these treeNodesInserted()/Changed()/Removed()? Just call to treeStructureChanged() seems to be easier.

答案:如果你使用 JTree 来显示树的内容,然后以下内容对你来说可能是一个惊喜(就像我一样):当你调用 treeStructureChanged时(),然后 JTree 不保持子节点的扩展状态!考虑一下这个例子,这里是 JTree 的内容:

Answer: If you use JTree to display contents of your tree, then the following thing might be a surprize for you (as it was for me) : when you call treeStructureChanged(), then JTree doesn't keep expand state of sub-nodes! Consider the example, here's contents of our JTree now:

[A]
 |-[B]
 |-[C]
 |  |-[E]
 |  |  |-[G]
 |  |  |-[H]
 |  |-[F]
 |     |-[I]
 |     |-[J]
 |     |-[K]
 |-[D]

然后你做了一些修改 C (比如,将其重命名为 C2 ),然后调用 treeStructureChanged()为此:

Then you make some changes to C (say, rename it to C2), and you call treeStructureChanged() for that:

  myTreeModel.treeStructureChanged(
        new TreeModelEvent(
           this,
           new Object[] { myNodeA, myNodeC } // Path to changed node
           )
        );

然后,节点 E F 将被折叠!你的 JTree 将如下所示:

Then, nodes E and F will be collapsed! And your JTree will look like that:

[A]
 |-[B]
 |-[C2]
 |  +-[E]
 |  +-[F]
 |-[D]

为避免这种情况,你应该使用 treeNodesChanged(),就像那样:

To avoid that, you should use treeNodesChanged(), like that:

  myTreeModel.treeNodesChanged(
        new TreeModelEvent(
           this,
           new Object[] { myNodeA }, // Path to the _parent_ of changed item
           new int[] { 1 },          // Indexes of changed nodes
           new Object[] { myNodeC }, // Objects represents changed nodes
                                     //    (Note: old ones!!! 
                                     //     I.e. not "C2", but "C",
                                     //     in this example)
           )
        );

然后,将保留扩展状态。

Then, expanding state will be kept.

我希望这篇文章对某些人有用。

I hope this post will be useful for somebody.

这篇关于在将一些节点添加到底层模型后,如何刷新JTree?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆