当前位置: 首页 > 面试题库 >

将一些节点添加到基础模型后,如何刷新JTree?

冷善
2023-03-14
问题内容

首先,让我说我不使用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。我以为我可以创建TreeModelEventtreeNodesInserted()这样的:

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

这行不通。

TreeModelEventdocs中所述,此构造函数仅用于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: 实际上,文档尚不清楚使用这些TreeModelEvents的情况,尤其是使用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
           )
        );

然后,节点EF将崩溃!您的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处理程序也可以。 注意:处理程序将为任何回调触发,但是您可以在需要调用函数时使用过滤器。