Finding an Item in a CTreeCtrl

If you want to find an item in a tree control (CTreeCtrl from MFC) by its name you need a recursive function. Below is a function that does that. How does it work: you pass the text of the item to search, the tree reference and an item in the tree. The function will search through the sub-tree of that item for a match. If it finds it, it returns the tree item, otherwise NULL. To search the entire tree, pass the root of the tree. If your tree has more than just one root and you want to search the entire tree, you’d have to call it once for each root item.

// name - the name of the item that is searched for
// tree - a reference to the tree control
// hRoot - the handle to the item where the search begins
HTREEITEM FindItem(const CString& name, CTreeCtrl& tree, HTREEITEM hRoot)
{
	// check whether the current item is the searched one
	CString text = tree.GetItemText(hRoot);
	if (text.Compare(name) == 0)
		return hRoot; 

	// get a handle to the first child item
	HTREEITEM hSub = tree.GetChildItem(hRoot);
	// iterate as long a new item is found
	while (hSub)
	{
		// check the children of the current item
		HTREEITEM hFound = FindItem(name, tree, hSub);
		if (hFound)
			return hFound; 

		// get the next sibling of the current item
		hSub = tree.GetNextSiblingItem(hSub);
	} 

	// return NULL if nothing was found
	return NULL;
}

[Update]
To search the entire tree you can use this helper function, which will work regardless how many roots the tree has.

HTREEITEM CTreeDemoDlg::FindItem(const CString& name, CTreeCtrl& tree)
{
   HTREEITEM root = m_tree.GetRootItem();
   while(root != NULL)
   {
      HTREEITEM hFound = FindItem(name, tree, root);
      if (hFound)
         return hFound; 

      root = tree.GetNextSiblingItem(root);
   }

   return NULL;
}

11 thoughts on “Finding an Item in a CTreeCtrl”

  1. Create a tree having just two nodes and when you pass in the hroot by using treePtr->GetRootItem()the code fails on the first string mismatch if the first node(root) does not have any child since the function returns NULL.

  2. Well, the function works very well, but as I design it, not was you expect it. It is suppose to take a tree item and search through its sub-tree to find a particular item. To search in the entire tree, just pass in the root item. However, if your tree has more than one root, then you’d have to call this function once for each of the root items to search the entire tree. Please see the updated post, I have added a helper function.

  3. This function cannot take a root of TVI_ROOT, unless the following code is included:

    if ( hRoot != TVI_ROOT && ! name.Compare( tree.GetItemText( hRoot ) ) )
    return hRoot;

    Or accessing the ItemText for root causes a (pretty hard to find) error.

    Otherwise, thanks for the example.

  4. I believe that is because TVI_ROOT only has meaning for the TVINSERTSTRUCT struct. You cannot pass it to functions expecting a tree item handle.

  5. I have rewrited both functions in one recursive function.

    HTREEITEM FindItem(const CString& name, CTreeCtrl& tree, HTREEITEM hRroot)
    {
    while (hRoot != NULL)
    {
    CString text = tree.GetItemText(hRoot);
    if (text.Compare(name) == 0)
    return hRoot;

    HTREEITEM hFound = FindItem(name, tree, tree.GetChildItem(hRoot));
    if (hFound)
    return hFound;

    hRoot = tree.GetNextSiblingItem(hRoot);
    }

    return NULL;
    }

    Call it with FindItem(name, tree, tree.GetRootItem())

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.