首先,让我说我不使用DefaultTreeModel。我实现了自己的TreeModel,所以无法使用DefaultXXX。问题是这样的:通过我的模型定义的一些addStuff()方法,我将节点添加到基础数据结构中。然后,我通过在addStuff()函数内调用treeNodesChanged()来通知侦听器(我知道有treeNodesInserted方法,但这是同一回事。它只是用不同的方法通知侦听器)。现在,侦听器之一是我的主窗体中的静态类,并且此侦听器可以告诉JTree(也包含在我的主窗体中)刷新自身。如何告诉JTree从模型中“重新加载”其部分或全部节点?
更新:我的问题不是如何通知查看器(JTree),而是从模型发出通知后应以哪种方式重新加载jtree。
首先,我要说的是,我知道刷新树以反映基础更改的唯一方法是调用updateUI()或重用setModel()方法。本质上,我的问题是这样的:
假设刚刚通过TreeModelListener API通知TreeModelListener模型发生了更改。好吧,现在怎么办?
我有这个问题,因为JTree没有实现TreeModelListener。因此,在我的情况下,侦听器是JTree的容器,或者是实现侦听器的内部类,它与Jtree处于同一容器内。
因此,假设我是一个TreeModelListener实现,与我的兄弟JTree一起幸福地生活在JForm中。突然我的方法treeNodesInserted(TreeModelEvent
evt)被调用。现在我该怎么做?如果我从内部调用Jtree.updateUI(),则模型的侦听器列表将引发ConcurrentModification异常。除updateUI之外,我还能打电话吗?
我尝试了很多事情,但是只有updateUI刷新了JTree。所以我是在听众之外做的。在JForm中,我只调用了模型的方法,该方法会改变不复杂的结构,然后调用updateUI。没有使用TreeModelListener。
UPDATE3:我发现有隐式的TreeModelListeners注册。在模型的addTreeModelListener(TreeModelListener
listener)实现中,我放置了一条debug system.out行:
System.out.println("listener added: " + listener.getClass().getCanonicalName());
当我执行jTree.setModel(model)时,我看到了这个调试输出:
侦听器已添加:javax.swing.JTree.TreeModelHandler
侦听器已添加:javax.swing.plaf.basic.BasicTreeUI.Handler
之所以引起ConcurrentModificationException,是因为对jtree.updateUI()的调用重新注册了侦听器(仅对plaf进行了注册,而不是对两者都进行注册),因此当我在侦听器通知循环内调用updateUI时会引发该异常。现在刷新树的唯一方法是在TreeModelListener之外进行。任何意见或想法,以寻求更好的解决方案?我想念什么吗?
我遇到了同样的“问题”:调用treeNodesInserted()
并没有导致我JTree
更新其内容。
但问题出在其他地方:我为使用了错误的构造函数TreeModelEvent
。我以为我可以创建TreeModelEvent
为treeNodesInserted()
这样的:
//-- Wrong!!
TreePath path_to_inserted_item = /*....*/ ;
TreeModelEvent tme = new TreeModelEvent(my_source, path_to_inserted_item);
这行不通。
如TreeModelEvent
docs中所述,此构造函数仅用于treeStructureChanged()
。但是treeNodesInserted()
,treeNodesRemoved()
,treeNodesChanged()
我们应该使用另一个构造函数:
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
正确更新其内容。
UPD: 实际上,文档尚不清楚使用这些TreeModelEvent
s的情况,尤其是使用s
还不清楚JTree
,因此,我想讲述一些在我试图弄清楚如何处理所有这些内容时遇到的问题。
首先,正如Paralife指出的那样,插入/更改/删除节点或更改树结构的情况不是正交的。所以,
问题1: 我们什么时候应该使用treeNodesInserted()
/ Changed()
/
Removed()
,以及何时treeStructureChanged()
?
答: treeNodesInserted()
/ Changed()
/
Removed()
可如果只是所有受影响的节点具有相同的父使用。否则,您可能会多次调用这些方法,或者仅调用treeStructureChanged()
一次(并将受影响节点的根节点传递给它)。因此,treeStructureChanged()
是一种普遍的方式,而treeNodesInserted()
/
Changed()
/ Removed()
是更具体。
问题2: 至于treeStructureChanged()
是一个普遍的方式,为什么我需要处理这些treeNodesInserted()
/
Changed()
/ Removed()
?只需致电treeStructureChanged()
似乎更容易。
答:
如果您JTree
用来显示树的内容,那么以下内容可能对您来说是一个惊喜(对我而言):当您调用时treeStructureChanged()
,则JTree
不会保持子节点的扩展状态!考虑这个例子,这是我们JTree
现在的内容:
[A]
|-[B]
|-[C]
| |-[E]
| | |-[G]
| | |-[H]
| |-[F]
| |-[I]
| |-[J]
| |-[K]
|-[D]
然后,您对进行了一些更改C
(例如,将其重命名为C2
),并要求treeStructureChanged()
这样做:
myTreeModel.treeStructureChanged(
new TreeModelEvent(
this,
new Object[] { myNodeA, myNodeC } // Path to changed node
)
);
然后,节点E
和F
将崩溃!您的JTree
外观将如下所示:
[A]
|-[B]
|-[C2]
| +-[E]
| +-[F]
|-[D]
为了避免这种情况,您应该使用treeNodesChanged()
,例如:
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)
)
);
然后,将保持扩展状态。
我希望这篇文章对某人有用。
我需要一个非常简单的例子,说明如何使用Neo4JClient将节点添加到索引中 在下面的C代码中,我创建了一个索引和一个员工节点。 问题: 在下面的代码中,如何将创建的节点添加到索引中?解决方案应允许搜索员工ID或姓名。
问题内容: 我想在我的Ember-CLI应用程序中使用此Node.js模块https://www.npmjs.com/package/remarkable- regexp 。 如何使它可用于Ember应用程序? 我通过将其添加到 但是它失败了: 路径或模式“ node_modules / remarkable-regexp / index.js”与任何文件都不匹配 问题答案: 既然是npm模块,我
我是RxJava新手,但我喜欢它。而现在我有小问题了。我使用的是+。 如果我有有效的用户令牌,我会得到API的响应,但如果令牌无效,我必须刷新令牌并尝试再次发出请求。 null null 如何使用RXJava实现它?
问题内容: 我想在运行时按下按钮时向JFrame中添加一些新组件。到目前为止,该方法仍然有效,但是我必须手动调整窗口大小才能看到新组件。 有什么我可以触发的动作或可以调用的方法来刷新窗口吗?任何帮助表示赞赏。提前致谢。 问题答案: 你必须去框架。如果这样不起作用,您还必须致电
谁能帮我在Android Studio中添加build.gradle库。 我知道它已被弃用,但我想使用它,如果有人能帮助我,我将不胜感激 写什么 如上所述,我想使用已弃用的库,而不是新的Actionbar Pullto刷新。
问题内容: 我有一个pageLoad函数,该函数在无法更改的.ascx控件上设置一些CSS。在页面加载时,一切都很好,但是当更新面板更新控件时,不再应用我的CSS。页面更新后如何重新运行功能? 显然,这仅在初始页面加载时运行。更新后如何运行? 问题答案: 添加add_pageLoaded处理程序也可以。 注意:处理程序将为任何回调触发,但是您可以在需要调用函数时使用过滤器。