Search text in labels


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 );



Comments

  • What about incremental search of labels?

    Posted by Legacy on 06/15/1999 12:00am

    Originally posted by: Oren Lev

    Hi,

    Do you know how I can implement incremental search like it is done in the Explorer tree? (start to write a word when the tree is in focus, and the selection jumps to the closest match)

    I found a message called: "TVM_GETISEARCHSTRING" that is supposed to be sent to the tree control and return the current incremental text, but it doesn't seem to work...

    I thank you for any information on this subject.

    Oren

    Reply
  • Little problem ???

    Posted by Legacy on 11/05/1998 12:00am

    Originally posted by: Patrice Lacroix

    I believe I found a problem in this method.
    
    

    Please correct me if I'm wrong or if I am not using this method correctly.

    If I am searching for a string in the tree and this string is
    currently selected, the method will return NULL.

    Should I check before I call the method ?

    Here is what I did to correct it:

    // For the first pass, set the current item equal to the selection
    HTREEITEM htiSel = hItem ? hItem : GetSelectedItem();
    HTREEITEM htiCur = htiSel;

    ...
    ...
    // For the first pass only, we check to see if it
    // is the item we're looking for.
    BOOL bFirstPass = TRUE;

    while( htiCur && (htiCur != htiSel || bFirstPass) )
    {
    bFirstPass = FALSE;
    ...
    ...
    ...
    }

    ...
    ...
    ...

    Please, tell me if you have a better way to do it.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • CentreCorp is a fully integrated and diversified property management and real estate service company, specializing in the "shopping center" segment, and is one of the premier retail service providers in North America. Company executives travel a great deal, carrying a number of traveling laptops with critical current business data, and no easy way to back up to the network outside the office. Read this case study to learn how CentreCorp implemented a suite of business continuity services that included …

Most Popular Programming Stories

More for Developers

RSS Feeds