dcsimg

Auto-completion ComboBox (2)

WEBINAR:
On-Demand

Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


Some were of the drop-down style where a list of predefined entries is displayed but the user may also add a new entry if the one he wants is not there.

MFC provides good functionality for both of these styles. The drop-list style also has basic type ahead functionality. If the user presses a key and an item beginning with that letter is in the list, it will be automatically highlighted. However the drop-down style does not have this functionality at all. What I wanted for my drop-down combo box is the kind of type ahead functionality found in Microsoft Excell.

When the user presses a key in the combo box the first item beginning with that letter is highlighted. However as the user continues to type, a string is formed, upon each key press, this string is checked against existing entires in the combo box and if one begings with the string then it is highlighted. What will happen is that if the user starts to type an entry that already exists, only a few key presses will be required to select it. If he types to the point where the string typed no longer matching an existing entry, a new one is automatically created.

How I did It

I'm sure there are several ways to do this kind of thing with MFC but I opted for the window subclassing method (probably because I'd just learnt about subclassing!). Subclassing allows the programmer to modify one of the Windows controls to provide the required functionality. A bit like inheritance really.

Subclassing An Ordinary Control

Lets say you wanted to subclass an ordinary control such as an edit box. I did this to create an edit box that would only allows numbers, the '.', delete and backspace keys. I used this for the input of monetary values. To subclass an edit control you create a new class derived from CEdit and create a control of this new class in your application. Assuming it is on a dialog box, you would add the following line to your dialog class' declaration:
	CNumericEdit	m_xAmount;
And in the OnInitDialog() function:
	m_xAmount.SubclassDlgItem(IDC_AMOUNT, this);
Where IDC_AMOUNT is the ID of the control you placed on the dialog form in the resource editor.

Subclassing a Combo Box

Subclassing a simple control is fairly straightforward. Unfortunately a combo box is made up of a list box and an edit box. To change the way the edit portion works, we need to actually subclass the edit portion of the combo box.

I've created a class called CTypeAheadCombo derived from CComboBox and a class called CComboEdit derived from CEdit. It's the edit class that does all the work. The only reason we need to subclass the combo box itself is to allow us to use the subclassed edit control in place of the ordinary one.

In the subclassed combo, we made a member variable of our subclassed edit control:

	CComboEdit	m_xEdit;
And then we override PreSubclassWindow() as follows:
	void CTypeAheadCombo::PreSubclassWindow() 
	{
		m_xEdit.SubclassDlgItem(1001, this);	
		CComboBox::PreSubclassWindow();
	}
Notice the 1001 used in place of a resource ID. Luckily for us, the edit portion of a combo box is always allocated the resource ID of 1001 which is quite handy.

Now onto the edit control itself...

The most obvious function to override is OnChar(). By trapping the characters types I can build up a search string to use when searching through the list of entries. I've used a CString for my search string and I've made it a member variable. In this way as long as the control is in existence (which will be for the life of the dialog) I can muck about with the search string to my hearts content but it gets reset when the combo box is recreated.

The basics of what I wanted to do it to trap the key that the user pressed, add it to the search string and then do a FindString() on the combo box to see if an entry exists. To get to the combo control I've just used a pointer to the parent of the edit control.

Difficulties

The basic building up of a search string and finding it within the list of entries was quite easy. What was not so easy was handling other keys. For example, if the user used the cursor keys to step back through his selection and type something, OnChar would only trap the new character typed but of course this character has now been placed into a different part of the string.

When the user presses backspace, parts of the string are deleted. the problem here is that I need to allow the user to delete his selection if required. The way I've done this is to say that if the user presses backspace or delete while a selection is currently highlighted, to unhighlight the selection and blank out the edit box.

OnKeyDown was needed to trap the cursor keys and the delete keys.

Other problems I encountered were with the caret. If I trapped the delete and cursor keys I had to ensure that the base class was called to actually process the key. My problem was with positioning the caret in the correct place. I had to set up a few bool variables to keep track of the original caret position, whether the delete or backspace keys were pressed and if a selection was highlighted.

The code itself is well-commented I think and should be enough to step you through how it's done.

If you have any comments, criticisms, suggestions etc then please e-mail me!
Caroline Price
caroline@kornflake.demon.co.uk

Download file



Comments

  • There are no comments yet. Be the first to comment!

  • You must have javascript enabled in order to post comments.

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

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date