Iterating CTreeCtrl items

How can I walk a list of CTreeCtrl items?  I've written a class (say, CCustomerInfo) that is SetItemData()'d to a tree control item, and I need to save the list of items to disk.  The items show up, and I can access them with GetSelectedItem(), but the other GetXXXXX methods aren't working for me.  

Any suggestions?  Some example code would be appreciated!

chrisbillAsked:
Who is Participating?
 
snoeglerConnect With a Mentor Commented:
- one possibility:
   To use your own CTreeView, you can simply use the code provided with the MFC:
   MFC contains the sources, so you can copy the MFC source, and replace its CTreeCtrl with
   your own CTreeCtrl.
- the other:
   If you override the GetTreeCtrl() function it should work. CTreeView does nothing other as
   casting itself to CTreeCtrl() - look in the sources. To avoid these vTable problems, why
   don't you use a non-virtual function as 'Serialize'? It will be called directly, so this problem is
   avoided.

To this storing issue:
That is now the complete code i used myself for the same purpose(the only difference is
that it was placed in a CTreeCtrl instead of CTreeView, but first take a look at it please)

void recurseThroughTree(CTreeCtrl *control,
                         HTREEITEM starthere,
                         CArchive& ar)
{
  if(ar.IsStoring()) {
    HTREEITEM firstchild,currentchild;
    firstchild=control->GetNextItem(starthere,TVGN_CHILD);
    if(firstchild==NULL) return;
    currentchild=firstchild;
    for(;;) {
      if(control->ItemHasChildren(currentchild))
            ar.Write("N",1); // This item is a 'node'
      else
            ar.Write("B",1); // This item is a 'branch'

      CString text=GetItemText(currentchild);
      int            length=text.GetLength()+1; // +1 for terminating '\0'

      ar.Write( length,sizeof(int));
      ar.Write( (LPCTSTR)text, length);

      if(control->ItemHasChildren(currentchild))
            // recurse if it has children
            recurseThroughTree(control,currentchild,ar);

      currentchild=control->GetNextItem(currentchild,TVGN_NEXT);
      if(currentchild==NULL) break;
    }
    if(starthere==TVI_ROOT) ar.Write("E",1); // End mark
  }      else
  {
    HTREEITEM      currentchild;
    for(;;) {
      char      nodeOrNot;  // 'N' as node, 'B' as branch
      int            length;
      CString      text;
      ar.Read(&nodeOrNot,1);

      if(nodeOrNot=='E') { // Is it the end?
        ASSERT(starthere==TVI_ROOT);
        return;
      }

      ar.Read(&length,sizeof(int));
      ar.Read(text.GetBuffer(length+1),length);
      text.ReleaseBuffer();

      currentchild=control->InsertItem(text,starthere);

      if(nodeOrNot=='B')
        recurseThroughTree(control,currentchild,ar);
    }
  }
}

void CTreeViewX::Serialize(CArchive& ar)
{
  // recurseThroughTree determinates itself if storing or not
  recurseThroughTree(&GetTreeCtrl(),TVI_ROOT,ar);
  // now you can proceed writing/reading other data
}
0
 
erajojCommented:
This code is from www.CodeGuru.com (Zafir Anjum):

void CTreeCtrlX::Serialize(CArchive& ar)
{
        if (ar.IsStoring())
        {      
                // storing code
                HTREEITEM hti = GetRootItem();
                while( hti )
                {
                        int indent = GetIndentLevel( hti );
                        while( indent-- )
                                ar.WriteString( "\t" );
                        ar.WriteString( GetItemText( hti ) + "\r\n");
                        hti = GetNextItem( hti );
                }
               
        }
        else
        {      
                // loading code
                CString sLine;
                if( !ar.ReadString( sLine ) )
                        return;

                HTREEITEM hti = NULL;
                int indent, baseindent = 0;
                while( sLine[baseindent] == '\t' )
                        baseindent++;
                do
                {
                        if( sLine.GetLength() == 0 )
                                continue;
                        for( indent = 0; sLine[indent] == '\t'; indent++ )
                                ;               // We don't need a body
                        sLine = sLine.Right( sLine.GetLength() - indent );
                        indent -= baseindent;

                        HTREEITEM parent;
                        int previndent = GetIndentLevel( hti );
                        if( indent ==  previndent)
                                parent = GetParentItem( hti );
                        else if( indent > previndent )
                                parent = hti;
                        else
                        {
                                int nLevelsUp = previndent - indent;
                                parent = GetParentItem( hti );
                                while( nLevelsUp-- )
                                        parent = GetParentItem( parent );
                        }
                        hti = InsertItem( sLine, parent ? parent : TVI_ROOT, TVI_LAST );
                }while( ar.ReadString( sLine ) );

        }
}



int CTreeCtrlX::GetIndentLevel( HTREEITEM hItem )
{
        int iIndent = 0;

        while( (hItem = GetParentItem( hItem )) != NULL )
                iIndent++;
        return iIndent;
}


// GetNextItem  - Get next item as if outline was completely expanded
// Returns              - The item immediately below the reference item
// hItem                - The reference item
HTREEITEM CTreeCtrlX::GetNextItem( HTREEITEM hItem )
{
        HTREEITEM       hti;

        if( ItemHasChildren( hItem ) )
                return GetChildItem( hItem );           // return first child
        else{
                // return next sibling item
                // Go up the tree to find a parent's sibling if needed.
                while( (hti = GetNextSiblingItem( hItem )) == NULL ){
                        if( (hItem = GetParentItem( hItem ) ) == NULL )
                                return NULL;
                }
        }
        return hti;
}

/// John
0
 
MikeP090797Commented:
Why can't you use GetItem, with the iItem of the LV_ITEM set to the index of the item you want to get?
0
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

 
MikeP090797Commented:
Sorry, didn't saw the answer when posting the comment
0
 
chrisbillAuthor Commented:
I should have mentioned that I tried to use the extended tree control from codeguru.com, but I simply could not get it to work!  I derived a class from CTreeCtrl, but I had no way to make the CCustomerView use it. I tried rewriting GetTreeCtrl() to use my control in the view class, but I guess some vtbl methods (like Serialize) pointed into space :(



0
 
snoeglerCommented:
You could write a recursive function storing the items in an
array.

Take a look at this pseudo-code:

void myfunc(CTreeCtrl *control,
       HTREEITEM starthere,
       CArray<HTREEITEM,HTREEITEM>& myArr)
{
  HTREEITEM firstchild,currentchild;
  firstchild=control->GetNextItem(starthere,TVGN_CHILD);
  if(firstchild==NULL) return;
  currentchild=firstchild;
  for(;;) {
    myArr->Add(currentchild);
    if(control->ItemHasChildren(currentchild))
      // recurse if it has children
      myfunc(control,currentchild,myArr);

    currentchild=control->GetNextItem(currentchild,TVGN_NEXT);
    if(currentchild==NULL) break;
  }
}

After this, the CArray has received all HTREEITEMs of the
CTreeCtrl. Now you can fetch your information with the member
functions, like GetItemText(myArr[index]);
0
 
snoeglerCommented:
I forgot:
You have to start the recursion with

CArray<HTREEITEM,HTREEITEM> myArr;
myfunc(myControl,TVI_ROOT,myArr);
0
 
chrisbillAuthor Commented:
snoegler, I'm still interested in using my own CTreeCtrl inside a CTreeView.  I suppose I could always replace that first parameter of your function with my CTreeCtrl, but how can I stick it inside CTreeView?  I'd like to have the CTreeView serialize itself, and then serialize my CTreeCtrl.  
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.