0

I want to change location of some nodes in my JTree. Here is the code:

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();
   }
});

I face two problems with this code:

  1. Sometimes few nodes not display full its text and it is represented with some truncation and dots (...) at the end.
  2. Sometimes I get this JRE exception and I don't understand why. I think it is thrown because I delete a node and then insert it again and JRE tries to repaint this tree before or inbetween these two operations. How can I avoid that?

      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)
    
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
polis
  • 795
  • 7
  • 23
  • 1) *"I face two problems with this code:"* SO is not a help desk, but a Q&A site. So each thread should be about **one** problem and should have one clear, concise **question**. 2) For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). – Andrew Thompson Jan 02 '18 at 11:47
  • `model.insertNodeInto(node, tree.getRoot(), i);` - `i` is likely out side of the range of available positions currently managed by the model – MadProgrammer Jan 02 '18 at 12:00
  • @MadProgrammer how is it possible? I thought that position `i`, does not have a max possible value. – polis Jan 02 '18 at 12:03
  • The `Vector` is just a wrapper around an array. You are trying to insert a value into a position that the `Vector` considers unavailable or invalid, for example, when `i >= size()` – MadProgrammer Jan 02 '18 at 12:05
  • Well, I think it is a good point, but what can I do? I modify tree in a loop and method `model.insertNodeInto(node, tree.getRoot(), i);` notifies appropriate listeners, but by the time the repaint starts, other method `model.removeNodeFromParent(node);` is executed and `ArrayOutOfBoundsException` occurrs during repaint. – polis Jan 02 '18 at 12:15

1 Answers1

0

Don't use insertNodeInto method on model instead call add on root node and finally call nodesChanged method on model passing root node. Code is below for your reference.

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();
   }
});
  • Actualy, I ended up with this idea yesterday. It worked, but I still don't understand why didn't work with `insertNodeInto`, because API states that it is a preffered way of modifying the tree. Also, this way has one major drawback: I cannot insert node into specific location, because `root.add(node)` always adds to an end. – polis Jan 03 '18 at 06:49
  • Let us say we have 22 nodes under root node we have someList with 25 items and first 22 items returns null for findNodeInTreeByName method call, so there is no insert. Then comes 23 element ( index is 22 ) for which we get node for findNodeInTreeByName method call which is not immediate child of root node in this scenario we may get array index out of bound since we 22 elements in root node and you are trying to insert at index 22. – Gnanasekaran Palanisamy Jan 03 '18 at 07:07
  • What if I have `root` with no childs. Do you mean I will get an `ArrayIndexOutOfBounds` exception if i try to insert first child as: `model.insertNodeInto(node, root, root.getChildCount())`? I don't think so... – polis Jan 03 '18 at 07:14
  • @polis I got your point the Exception is due to method call `model.removeNodeFromParent(node); model.insertNodeInto(node, tree.getRoot(), i);` InsertNodeInto updates the tree model but VisibleTreeStateNodeEnumeration object childCount field is not updated it assumes there is 23 element in a node but actually one element is removed with previous removeNodeFromParent method call. – Gnanasekaran Palanisamy Jan 03 '18 at 07:25