Re: How to get the next immediately adjacent item in CTreeCtrl?
JD wrote:
Hi,
I want to loop through all the items in a CTreeCtrl, one by one from top to
bottom. CTreeCtrl has the following function, but it seems that nCode
doesn't provide an option for getting the next immediately adjacent item.
GetNextItem( HTREEITEM hItem, UINT nCode );
Do I have to write a recursive function to traverse the treeview for this
purpose (because there are multiple levels of ancestors and offspring)? If
so, I will be very surprised that such a simple and useful option can be
missing from MFC.
Actually, there is stuff in MFC, but not in a library. Get the DAOVIEW
sample project set up and you will find a CTreeCtrlEx class. I never use
HTREEITEM at an application level anymore.
A nice thing now is that you can derive from CTreeCursor and specialize
it with members/overloads for a particular need. Almost there here is a
helper class that I've added to the CTreeCtrlEx suite.
class CTreeCtrlTraverse
{
CTreeCtrlEx& tree_ctrl;
HTREEITEM root;
HTREEITEM tree_pos;
long depth;
public:
//constructor sets traverse start to root
CTreeCtrlTraverse::CTreeCtrlTraverse( CTreeCtrlEx& inTC )
:tree_ctrl( inTC )
,depth( 1 )
{
ASSERT( (HTREEITEM)inTC.GetRootItem( ) );
root= tree_pos= inTC.GetRootItem( );
}
//constructor sets traverse start to tree cursor
CTreeCtrlTraverse::CTreeCtrlTraverse( CTreeCursor& inPos )
:tree_ctrl( inPos.GetTreeCtrl( ) )
,depth( 1 )
{
ASSERT( (HTREEITEM)inPos );
root= tree_pos= inPos;
}
CTreeCursor GetCurrentNode( ) const { return CTreeCursor( tree_pos,
&tree_ctrl ); }
//Return next node and increment
CTreeCursor GetNextNode( );
//Returns root set by instantiation
CTreeCursor GetRootNode( ) const { return CTreeCursor( tree_pos,
&tree_ctrl ); }
//Get depth in tree
long GetDepth( ) const { return depth; }
void Reset( ) { depth= 1; tree_pos= root; }
};
If you do derive from CTreeCursor, this could be templated so you don't
have to cast the cursor at the app level.
Here is the cpp member:
CTreeCursor CTreeCtrlTraverse::GetNextNode( )
{
CTreeCursor tc;
if( !depth )
return CTreeCursor( NULL, &tree_ctrl );
if( CTreeCursor( tree_pos, &tree_ctrl ).HasChildren( ) )
{
++depth;
tree_pos= CTreeCursor( tree_pos, &tree_ctrl ).GetChild( );
return CTreeCursor( tree_pos, &tree_ctrl );
}
else if( CTreeCursor( tree_pos, &tree_ctrl ).GetNextSibling( ).IsValid( ) )
{
tree_pos= CTreeCursor( tree_pos, &tree_ctrl ).GetNextSibling( );
return CTreeCursor( tree_pos, &tree_ctrl );
}
else
{
do
{
tree_pos= CTreeCursor( tree_pos, &tree_ctrl ).GetParent(
).GetNextSibling( );
}
while( --depth && ! tree_pos );
return CTreeCursor( tree_pos, &tree_ctrl );
}
}
I've used this stuff in an exercise I did to gain an understanding of
the shell functions and first use of this:
http://www.codeproject.com/library/tree_container.asp
It is just another folder selector dialog. I'd be happy to zip the
project and send it to anyone that is curious.
Mail to dan_b at lakeweb (put a dotcom) You'll get an extended
CTreeCtrlEx suite.
Best, Dan.