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: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

  • Savvy enterprises are discovering that the cloud holds the power to transform IT processes and support business objectives. IT departments can use the cloud to redefine the continuum of development and operations—a process that is becoming known as DevOps. Download the Executive Brief DevOps: Why IT Operations Managers Should Care About the Cloud—prepared by Frost & Sullivan and sponsored by IBM—to learn how IBM SmartCloud Application services provide a robust platform that streamlines …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds