CTreeView Iterator






4.92/5 (22 votes)
Mar 28, 2002
4 min read

159865

5426
An iterator to parse subtree and execute function on each item/node
Introduction
Don't you find you have written the same segment of code many times to parse a subtree because the action you wanted to launch on the items was different. In order to avoid such code, I've written CTreeViewIterator
class. This class contains a method called ApplyFunction
to launch a function on each item/node of a subtree.
Implementation
The class I've written is dedicated to Explorer like applications (those with a CTreeView
class on the left side). In that section, we're going to see how to use CTreeViewIterator
in that general case. In the section Adaptation, we'll see how to modify it to use it in other cases.
When you generate your application using the wizard, Visual C++ doesn't give you the capability to choose the CTreeView
class implementation. Therefore, you have to have a CLeftView
in your application. In the LeftView.cpp file, add the following line in the include
section.
#include "TreeViewIterator.h"
You're now able to use the CTreeViewIterator
class in that module.
You must define the function that will receive the item/node as parameter. This function will be external to your CLeftView
class even if defined in the same module. If you don't define it in this module, do not forget to create a definition to set it visible from this module. If for any reason, you do want to set it as a method of your CLeftView
class, please read the Adaptation section. The signature of this function is predefined. It must be like this:
int ExternalFunction ( CLeftView *tvTreeView, /* Handle on the tree view*/
HTREEITEM tiItem ) /* Item in the tree */
- This function must return an integer set to
1
if ok,0
else. - The first parameter is to be a
CLeftView*
. It will receive a handle on theCLeftView
to let you use. - The second parameter is to be a
HTREEITEM
. It will receive a handle on the currently parsed item/node.
For example, let's consider this function:
//*******************************************************************
//
// FUNCTION: ExternalDisplayItem
//
// RETURNS: int
//
// COMMENTS: External function to display the subtree as a list
//
//*******************************************************************
int ExternalDisplayItem (
CLeftView *tvTree, /* Handle on the tree */
HTREEITEM tiItem ) /* Item in the tree */
{
CTreeCtrl &tTree= tvTree->GetTreeCtrl ();
// store the name
tvTree->sFullList += tTree.GetItemText(tiItem) + "\r\n";
return ( 1);
}
The goal here, is to store the subtree as a list in a string
. So, the only thing the external function has to do is getting the name and concatenating it to the full list. To do so, it will use an attribute created in the CLeftView
called sFullList
(type CString
). Since we got a handle on the CLeftView
as first parameter, there's no problem till the attribute is public
(if not, we should have used public
methods like get
& set
). Using this method, you may update the tree item/node or the CLeftView
the way you want.
Now you have the function to apply to each item/node, you have to call it. To do so, you'll have to implement first the iterator and then, to call the ApplyFunction
method with the right parameters.
The ApplyFunction
's signature is:
int CTreeViewIterator::ApplyFunction (
CLeftView *tvView, /* Handler on the tree view */
HTREEITEM tiStart, /* Item to start with */
FuncPtrView fptrFunction ) /* Function to launch */
- This function returns an integer set to
1
if ok,-1
if problem when parsing subtree,0
if problem when calling the external function. - The first parameter is a handle on the
CLeftView
derived fromCTreeView
. - The second parameter is a handle on the item/node to consider as the root when parsing the subtree.
fptrFunction
is a function pointer to the external function you previously created.
Using our precedent external function, we got this code:
//*******************************************************************
//
// FUNCTION: OnSelchanged
//
// RETURNS: void
//
// COMMENTS: Current selected item has changed
//
//
//*******************************************************************
void CLeftView::OnSelchanged (
NMHDR *pNMHDR, /* handle on event values */
LRESULT *pResult ) /* handle on event return value */
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
NM_TREEVIEW *pNMTreeView = (NM_TREEVIEW *) pNMHDR;
CTreeCtrl &tTree = this->GetTreeCtrl ();
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
// create the iterator
CTreeViewIterator *ptrTree = (CTreeViewIterator *) &tTree;
// call the function
sFullList= "";
ptrTree->ApplyFunction (this, pNMTreeView->itemNew.hItem,
&ExternalDisplayItem );
GetDocument()->UpdateAllViews ( this, 1L, (CObject *) &sFullList );
*pResult = 0;
}
The method OnSelChanged
is launched when the user has selected a new item/node in the treeview
. Here, we have caught it to add our function call. As you can see, we first add the iterator implementation with:
CTreeViewIterator *ptrTree = (CTreeViewIterator *) tTree;
In fact, we may consider the iterator on the CTreeCtrl
as a shell with a special method. Therefore, within ApplyFunction
method, we will see the content of the CTreeCtrl
to parse.
We now have to get the parameters:
- The first one, the handle on the
CLeftView
is easy to get, it's this variable. - The second is the handle on the item/node. Since we are in the method that catches the new selection, we are going to extract the item address within the parameter
pNMHDR
using two lines:NM_TREEVIEW *pNMTreeView = (NM_TREEVIEW *) pNMHDR; // to cast the event param pNMTreeView->itemNew.hItem // to refer to the new selected item
- The last parameter is the handle on the external function we created.
That way, we obtain the following call:
ptrTree->ApplyFunction (this, pNMTreeView->itemNew.hItem, &ExternalDisplayItem );
Since this event may be caught many times, we initialize the variable sFullList
before we parse the subtree.
When the ApplyFunction
is finished, we update the other views with the generated string
using the method UpdateAllViews.
Here we are, catching the UpdateAllViews
event isn't the subject here but you may have a look at the sample project to get an idea.
Adaptation
That section is to explain you how to upgrade the CTreeViewIterator
to adapt it to your own case. I wrote it as a FAQ. I'll update it with the cases you will propose. So, what's your problem?
Question: My CTreeView
class is not named CLeftView
.
Answer: Change the CTreeView
classname in:
- The function pointer's signature
- The
ApplyFunction
definition - The
ApplyFunction
implementation
Question: I want to set the called function a method of my class CLeftView
.
Answer: You just have to change the function pointer's signature to add your class. For example, try this:
- Change the External function to a
public
method calledDisplayItem
inCLeftView
class. - Change the signature to:
typedef int ( CLeftView::*FuncPtrView ) ( CLeftView * tTree, HTREEITEM tiItem );
- Change the call of
ApplyFunction
method to:ptrTree->ApplyFunction (this, pNMTreeView->itemNew.hItem, &CLeftView::DisplayItem );
- In
ApplyFunction
implementation, change the function call to:( tvView->*fptrFunction ) ( tvView, tiCurrItem )
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.