Solved

Iterating CTreeCtrl items

Posted on 1998-07-27
8
2,655 Views
Last Modified: 2013-11-20
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!

0
Comment
Question by:chrisbill
  • 3
  • 2
  • 2
  • +1
8 Comments
 
LVL 4

Expert Comment

by:erajoj
ID: 1319801
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
 
LVL 8

Expert Comment

by:MikeP090797
ID: 1319802
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
 
LVL 8

Expert Comment

by:MikeP090797
ID: 1319803
Sorry, didn't saw the answer when posting the comment
0
Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

 

Author Comment

by:chrisbill
ID: 1319804
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
 
LVL 6

Expert Comment

by:snoegler
ID: 1319805
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
 
LVL 6

Expert Comment

by:snoegler
ID: 1319806
I forgot:
You have to start the recursion with

CArray<HTREEITEM,HTREEITEM> myArr;
myfunc(myControl,TVI_ROOT,myArr);
0
 

Author Comment

by:chrisbill
ID: 1319807
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
 
LVL 6

Accepted Solution

by:
snoegler earned 50 total points
ID: 1319808
- 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

Featured Post

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
repeatSeparator  java  challenge 13 57
method notes when mouse over in eclipse 5 86
move a line in eclipse 3 101
java ^ examples 8 65
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…

776 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