Solved

JTree expand problem

Posted on 2004-08-04
14
1,474 Views
Last Modified: 2009-07-29
I am trying to expand a tree path after a node is added, only if this is the only child node. However, I am running into the following sporadic problem:


java.lang.ArrayIndexOutOfBoundsException: 1 >= 1
      at java.util.Vector.elementAt(Vector.java:427)
      at javax.swing.tree.DefaultMutableTreeNode.getChildAt(DefaultMutableTreeNode.java:230)
      at javax.swing.tree.VariableHeightLayoutCache$VisibleTreeStateNodeEnumeration.updateNextIndex(VariableHeightLayoutCache.java:1739)
      at javax.swing.tree.VariableHeightLayoutCache$VisibleTreeStateNodeEnumeration.updateNextObject(VariableHeightLayoutCache.java:1690)
      at javax.swing.tree.VariableHeightLayoutCache$VisibleTreeStateNodeEnumeration.nextElement(VariableHeightLayoutCache.java:1681)
      at javax.swing.plaf.basic.BasicTreeUI.paint(BasicTreeUI.java:1121)      
                at javax.swing.plaf.metal.MetalTreeUI.paint(MetalTreeUI.java:143)
      at javax.swing.plaf.ComponentUI.update(ComponentUI.java:142)
      at javax.swing.JComponent.paintComponent(JComponent.java:541)
      at javax.swing.JComponent.paint(JComponent.java:808)
      at javax.swing.JComponent.paintWithOffscreenBuffer(JComponent.java:4771)
      at javax.swing.JComponent.paintDoubleBuffered(JComponent.java:4724)
      at javax.swing.JComponent._paintImmediately(JComponent.java:4668)
      at javax.swing.JComponent.paintImmediately(JComponent.java:4477)
      at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:410)
      at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:117)
      at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:178)
      at java.awt.EventQueue.dispatchEvent(EventQueue.java:448)
      at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:197)
      at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:144)
      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:136)
      at java.awt.EventDispatchThread.run(EventDispatchThread.java:99)


The code I am using to insert a node is:

      DefaultMutableTreeNode client = new DefaultMutableTreeNode( clientName );

      treeModel.insertNodeInto( client, onlineRoot, onlineRoot.getChildCount() );

      // if this is the first client added, initially expand this node
      if ( onlineRoot.getChildCount() == 1 ) {
          tree.expandRow( tree.getRowForPath( new TreePath( onlineRoot.getPath() ) ) );
          //tree.fireTreeExpanded( new TreePath( onlineRoot.getPath() ) );
      } // end if

      // notify the tree that this client has been added so it is rendered
      // properly
      notifyNodeChanged( clientName );


The call to notifyNodeChanged( clientName ) is used to fix a weird problem that occured sporadically as well - which was basically making a single node very large, requiring scrollbars to be displayed. It goes through the tree to find the corresponding node and calls a nodeChanged( node ) on it. I guess all I really need to do there (if in fact it helps) is just call treeModel.nodeChanged( client ).

Thanks!
0
Comment
Question by:ctjoumas
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
  • 4
14 Comments
 
LVL 14

Expert Comment

by:sudhakar_koundinya
ID: 11719315
if(vector.size()>0)
{
   //do your works
}
0
 

Author Comment

by:ctjoumas
ID: 11719366
I don't have a vector that stores anything.  I have a dynamic multilevel tree and want to expand a given level only if it's first child was just inserted.
0
 
LVL 14

Expert Comment

by:sudhakar_koundinya
ID: 11719447
if (onlineRoot.getChildCount()>0)
{
if ( onlineRoot.getChildCount() == 1 ) {
          tree.expandRow( tree.getRowForPath( new TreePath( onlineRoot.getPath() ) ) );
          //tree.fireTreeExpanded( new TreePath( onlineRoot.getPath() ) );
      } // end if
}
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 14

Expert Comment

by:sudhakar_koundinya
ID: 11719471
if (onlineRoot.getChildCount()>0)
{
if ( onlineRoot.getChildCount() == 1 ) {
if (onlineRoot.getPath()!= null && onlineRoot.getPath().length>0)
{
          tree.expandRow( tree.getRowForPath( new TreePath( onlineRoot.getPath() ) ) );
          //tree.fireTreeExpanded( new TreePath( onlineRoot.getPath() ) );
      } // end if
}
}
0
 
LVL 14

Expert Comment

by:sudhakar_koundinya
ID: 11719697
This might be useful to expand ur tree node

// If expand is true, expands all nodes in the tree.
    // Otherwise, collapses all nodes in the tree.
    public void expandAll(JTree tree, boolean expand) {
        TreeNode root = (TreeNode)tree.getModel().getRoot();
   
        // Traverse tree from root
        expandAll(tree, new TreePath(root), expand);
    }
    private void expandAll(JTree tree, TreePath parent, boolean expand) {
        // Traverse children
        TreeNode node = (TreeNode)parent.getLastPathComponent();
        if (node.getChildCount() >= 0) {
            for (Enumeration e=node.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode)e.nextElement();
                TreePath path = parent.pathByAddingChild(n);
                expandAll(tree, path, expand);
            }
        }
   
        // Expansion or collapse must be done bottom-up
        if (expand) {
            tree.expandPath(parent);
        } else {
            tree.collapsePath(parent);
        }

Regards
Sudhakar
0
 
LVL 92

Accepted Solution

by:
objects earned 125 total points
ID: 11721955
Is the above code being called from the event dispatch thread?
If not then it should be.

>  notifyNodeChanged( clientName );

that shouldn't be necessary
0
 

Author Comment

by:ctjoumas
ID: 11724833
sudhakar_koundinya: Except for your last post, that seems pretty much what I already have.

objects:

> Is the above code being called from the event dispatch thread?

I assume you are asking about my code?  If so, how do I call it from the event dispatch thread?  The code to add the node is called when a node is requested to be added, and the expansion of the row is called in the same method only if the node just added is the only child for the row.

So, I guess that means it is not in the event dispatch thread.  How do I do that?  I think I had tried using an invokeLater method, but that didn't work and I'm assuming that isn't quite the same thing.

as for the notifyNodeChanged( clientName ); line, all that does is basically:
treeModel.nodeChanged( node ); where node is the node of the clientName.  It seemed to fix my problem, but hte problem that I was seeing (where if there was only one node added it would take up the entire height of the tree and require scrollbars) occured once every 20 times or so.
0
 

Author Comment

by:ctjoumas
ID: 11724859
objects: btw, I just changed it to this - let me know what you think.  I still need to test it to see if I can run into the problem again:

        Runnable expandTree = new Runnable() {
            public void run() {
                tree.expandRow( tree.getRowForPath( new TreePath( offlineRoot.getPath() ) ) );
            }
        };

        // if this is the first client added, initially expand this node
        if ( offlineRoot.getChildCount() == 1 ) {
            SwingUtilities.invokeLater( expandTree );
        } // end if
0
 

Author Comment

by:ctjoumas
ID: 11728474
Hmm...objects, are you saying to put all of ny code in an event dispatch thread?  It seems to work, but it is always hard to prove.  I am sending notifications to other windows when adding or removing a node, so I guess all of that can be put into the event dispatch thread too?

My other question is - should only the expandRow be in an event dispatch thread, or should treeModel.removeNodeFromParent( node ) (and other calls) also be in one?

Thanks!
0
 
LVL 92

Expert Comment

by:objects
ID: 11731420
> are you saying to put all of ny code in an event dispatch thread?

all code that updates the gui

> should only the expandRow be in an event dispatch thread, or should treeModel.removeNodeFromParent( node ) (and other calls) also be in one?

yes
0
 

Author Comment

by:ctjoumas
ID: 11734400
> all code that updates the gui

So, in the case of
    DefaultMutableTreeNode client = new DefaultMutableTreeNode( clientName );

    treeModel.insertNodeInto( client, offlineRoot, offlineRoot.getChildCount() );

    if ( offlineRoot.getChildCount() == 1 )
        tree.expandRow( tree.getRowForPath( new TreePath( offlineRoot.getPath() ) ) );

should, only the expandRow be in there?  Or does insertNodeInto also update the gui?


> > should only the expandRow be in an event dispatch thread, or should treeModel.removeNodeFromParent( node ) (and other calls) also be in one?

> yes

Are you saying yes to the first or second part of that question? :)
0
 
LVL 92

Expert Comment

by:objects
ID: 11740602
>  Or does insertNodeInto also update the gui?

If the model is being displayed then yes it does.

> Are you saying yes to the first or second part of that question? :)

both :)
0
 

Author Comment

by:ctjoumas
ID: 11754178
Thanks!
0
 
LVL 92

Expert Comment

by:objects
ID: 11758554
0

Featured Post

Secure Your Active Directory - April 20, 2017

Active Directory plays a critical role in your company’s IT infrastructure and keeping it secure in today’s hacker-infested world is a must.
Microsoft published 300+ pages of guidance, but who has the time, money, and resources to implement? Register now to find an easier way.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

In this post we will learn different types of Android Layout and some basics of an Android App.
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…

730 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question