【问题标题】:Swing throws ArrayIndexOutOfBoundsException while relocating nodes in JTreeSwing 在 JTree 中重定位节点时抛出 ArrayIndexOutOfBoundsException
【发布时间】:2018-01-02 11:12:07
【问题描述】:

我想更改我的JTree 中某些节点的位置。代码如下:

public void changeNodePositionInTree() {
   DefaultTreeModel model = (DefaultTreeModel)tree.getModel();

   for(int i = 0; i < someList.size(); i++) {
      DefaultMutableTreeNode node = findNodeInTreeByName(someList.get(i));

      //if node is in a tree, then change its location and insert it in position i
      if(node != null) {
         model.removeNodeFromParent(node);
         model.insertNodeInto(node, tree.getRoot(), i);
      }
   }
}

SwingUtilities.invokeLater(new Runnable() {
   public void run() {
      changeNodePositionInTree();
   }
});

这段代码我面临两个问题:

  1. 有时少数节点无法完整显示其文本,并且在末尾用一些截断和点 (...) 表示。
  2. 有时我会收到此 JRE 异常,但我不明白为什么。我认为它被抛出是因为我删除了一个节点然后再次插入它,JRE 尝试在这两个操作之前或之间重新绘制这棵树。我怎样才能避免这种情况?

      Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 22 >= 22
        at java.util.Vector.elementAt(Vector.java:474)
        at javax.swing.tree.DefaultMutableTreeNode.getChildAt(DefaultMutableTreeNode.java:245)
        at javax.swing.tree.VariableHeightLayoutCache$VisibleTreeStateNodeEnumeration.nextElement(VariableHeightLayoutCache.java:1695)
        at javax.swing.tree.VariableHeightLayoutCache$VisibleTreeStateNodeEnumeration.nextElement(VariableHeightLayoutCache.java:1653)
        at javax.swing.plaf.basic.BasicTreeUI.paint(BasicTreeUI.java:1183)
        at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
        at javax.swing.JComponent.paintComponent(JComponent.java:780)
        at javax.swing.JComponent.paint(JComponent.java:1056)
        at javax.swing.JComponent.paintChildren(JComponent.java:889)
        at javax.swing.JComponent.paint(JComponent.java:1065)
        at javax.swing.JViewport.paint(JViewport.java:728)
        at javax.swing.JComponent.paintChildren(JComponent.java:889)
        at javax.swing.JComponent.paint(JComponent.java:1065)
        at javax.swing.JComponent.paintChildren(JComponent.java:889)
        at javax.swing.JComponent.paint(JComponent.java:1065)
        at javax.swing.JComponent.paintChildren(JComponent.java:889)
        at javax.swing.JComponent.paint(JComponent.java:1065)
        at javax.swing.JComponent.paintChildren(JComponent.java:889)
        at javax.swing.JSplitPane.paintChildren(JSplitPane.java:1047)
        at javax.swing.JComponent.paint(JComponent.java:1065)
        at javax.swing.JComponent.paintChildren(JComponent.java:889)
        at javax.swing.JComponent.paint(JComponent.java:1065)
        at javax.swing.JComponent.paintChildren(JComponent.java:889)
        at javax.swing.JComponent.paint(JComponent.java:1065)
        at javax.swing.JComponent.paintChildren(JComponent.java:889)
        at javax.swing.JComponent.paint(JComponent.java:1065)
        at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
        at javax.swing.JComponent.paintChildren(JComponent.java:889)
        at javax.swing.JComponent.paintToOffscreen(JComponent.java:5217)
        at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
        at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
        at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
        at javax.swing.JComponent.paint(JComponent.java:1042)
        at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
        at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
        at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
        at java.awt.Container.paint(Container.java:1975)
        at java.awt.Window.paint(Window.java:3912)
        at javax.swing.RepaintManager$4.run(RepaintManager.java:842)
        at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
        at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
        at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
        at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
        at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
        at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
        at java.awt.EventQueue.access$500(EventQueue.java:97)
        at java.awt.EventQueue$3.run(EventQueue.java:709)
        at java.awt.EventQueue$3.run(EventQueue.java:703)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    

【问题讨论】:

  • 1) “这段代码我面临两个问题:” SO 不是帮助台,而是问答网站。所以每个主题都应该是关于一个的问题,并且应该有一个清晰、简洁的问题。 2) 为了尽快获得更好的帮助,请发帖minimal reproducible example 或Short, Self Contained, Correct Example。
  • model.insertNodeInto(node, tree.getRoot(), i); - i 可能超出模型当前管理的可用职位范围
  • @MadProgrammer 这怎么可能?我认为i 的位置没有最大可能值。
  • Vector 只是一个数组的包装器。您正在尝试将值插入Vector 认为不可用或无效的位置,例如,当i &gt;= size()
  • 嗯,我认为这是一个很好的观点,但我能做些什么呢?我在循环中修改树,方法 model.insertNodeInto(node, tree.getRoot(), i); 通知适当的侦听器,但是在重绘开始时,其他方法 model.removeNodeFromParent(node); 被执行,ArrayOutOfBoundsException 在重绘期间发生。

标签: java swing indexoutofboundsexception jtree defaulttreemodel


【解决方案1】:

不要在模型上使用 insertNodeInto 方法,而是在根节点上调用 add ,最后在传递根节点的模型上调用 nodesChanged 方法。代码如下供您参考。

public void changeNodePositionInTree() {
   DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
   DefaultMutableTreeNode root = ( DefaultMutableTreeNode ) tree.getRoot();
   for(int i = 0; i < someList.size(); i++) {
      DefaultMutableTreeNode node = findNodeInTreeByName(someList.get(i));

      //if node is in a tree, then change its location and insert it in position i
      if(node != null) {
         model.removeNodeFromParent(node);
         root.add( node );
      }
   }

   // inform node that the root node got changed
   model.nodeChanged(root);

}

SwingUtilities.invokeLater(new Runnable() {
   public void run() {
      changeNodePositionInTree();
   }
});

【讨论】:

  • 其实,我昨天终于有了这个想法。它有效,但我仍然不明白为什么不使用 insertNodeInto,因为 API 声明它是修改树的首选方式。此外,这种方式有一个主要缺点:我无法将节点插入特定位置,因为root.add(node) 总是添加到结尾。
  • 假设我们在根节点下有 22 个节点,我们有 someList 有 25 个项目,前 22 个项目为 findNodeInTreeByName 方法调用返回 null,所以没有插入。然后是 23 个元素(索引为 22),我们为 findNodeInTreeByName 方法调用获取节点,在这种情况下,它不是根节点的直接子节点,因为我们在根节点中有 22 个元素并且您正在尝试插入,因此我们可能会得到数组索引超出范围在索引 22 处。
  • 如果我的root 没有孩子怎么办。你的意思是如果我尝试将第一个孩子插入为:model.insertNodeInto(node, root, root.getChildCount()),我会得到一个ArrayIndexOutOfBounds 异常吗?我不这么认为......
  • @polis 我明白了你的意思,异常是由于方法调用model.removeNodeFromParent(node); model.insertNodeInto(node, tree.getRoot(), i); InsertNodeInto 更新了树模型,但 VisibleTreeStateNodeEnumeration 对象 childCount 字段没有更新它假设节点中有 23 个元素,但实际上是一个元素使用之前的 removeNodeFromParent 方法调用删除。
猜你喜欢
  • 2020-02-07
  • 2012-03-26
  • 1970-01-01
  • 1970-01-01
  • 2011-01-19
  • 1970-01-01
  • 2021-02-06
  • 2016-11-09
  • 2023-03-16
相关资源
最近更新 更多