The tree view control does not have any built-in method for searching the
entire tree for a label that contains a given sub-string. The GetItem()
function listed below takes a sub-string to search for and searches the
item labels for this sub-string. It also has arguments to specify whether
to do a case sensitive search, whether to search in the down direction,
whether to look for whole words only and which item to start looking from.
It uses the GetNextItem(), GetPrevItem()
and GetLastItem() described earlier. Note that
when a matching item is found, the IsFindValid() function is called to
determine if this item is acceptable. IsFindValid()
is a virtual function and can be overridden to implement a custom filter.
The default implementation returns TRUE.
// FindItem - Finds an item that contains the search string // Returns - Handle to the item or NULL // str - String to search for // bCaseSensitive - Should the search be case sensitive // bDownDir - Search direction - TRUE for down // bWholeWord - True if search should match whole words // hItem - Item to start searching from. NULL for // - currently selected item HTREEITEM CTreeCtrlX::FindItem(CString &str, BOOL bCaseSensitive /*= FALSE*/, BOOL bDownDir /*= TRUE*/, BOOL bWholeWord /*= FALSE*/, HTREEITEM hItem /*= NULL*/) { int lenSearchStr = str.GetLength(); if( lenSearchStr == 0 ) return NULL; HTREEITEM htiSel = hItem ? hItem : GetSelectedItem(); HTREEITEM htiCur = bDownDir ? GetNextItem( htiSel ) : GetPrevItem( htiSel ); CString sSearch = str; if( htiCur == NULL ) { if( bDownDir ) htiCur = GetRootItem(); else htiCur = GetLastItem( NULL ); } if( !bCaseSensitive ) sSearch.MakeLower(); while( htiCur && htiCur != htiSel ) { CString sItemText = GetItemText( htiCur ); if( !bCaseSensitive ) sItemText.MakeLower(); int n; while( (n = sItemText.Find( sSearch )) != -1 ) { // Search string found if( bWholeWord ) { // Check preceding char if( n != 0 ) { if( isalpha(sItemText[n-1]) || sItemText[n-1] == '_' ){ // Not whole word sItemText = sItemText.Right( sItemText.GetLength() - n - lenSearchStr ); continue; } } // Check succeeding char if( sItemText.GetLength() > n + lenSearchStr && ( isalpha(sItemText[n+lenSearchStr]) || sItemText[n+lenSearchStr] == '_' ) ) { // Not whole word sItemText = sItemText.Right( sItemText.GetLength() - n - sSearch.GetLength() ); continue; } } if( IsFindValid( htiCur ) ) return htiCur; else break; } htiCur = bDownDir ? GetNextItem( htiCur ) : GetPrevItem( htiCur ); if( htiCur == NULL ) { if( bDownDir ) htiCur = GetRootItem(); else htiCur = GetLastItem( NULL ); } } return NULL; } // IsFindValid - Virtual function used by FindItem to allow this // function to filter the result of FindItem // Returns - True if item matches the criteria // Arg - Handle of the item BOOL CTreeCtrlX::IsFindValid( HTREEITEM ) { return TRUE; }
In the class declaration add the following.
public:
virtual HTREEITEM FindItem(CString &sSearch,
BOOL bCaseSensitive = FALSE,
BOOL bDownDir = TRUE,
BOOL bWholeWord = FALSE,
HTREEITEM hItem = NULL);
protected:
virtual BOOL IsFindValid( HTREEITEM );