Solved

JTree expand problem

Posted on 2004-08-04
14
1,463 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
  • 6
  • 4
  • 4
14 Comments
 
LVL 14

Expert Comment

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

Author Comment

by:ctjoumas
Comment Utility
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
Comment Utility
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
 
LVL 14

Expert Comment

by:sudhakar_koundinya
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 

Author Comment

by:ctjoumas
Comment Utility
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
Comment Utility
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
Comment Utility
> 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
Comment Utility
> 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
Comment Utility
>  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
Comment Utility
Thanks!
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

Are you developing a Java application and want to create Excel Spreadsheets? You have come to the right place, this article will describe how you can create Excel Spreadsheets from a Java Application. For the purposes of this article, I will be u…
Java Flight Recorder and Java Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis. Java Flight Recorder is a profiling and event collectio…
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:

728 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now