Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Case-sensitive ComboBox

0.00/5 (No votes)
20 Apr 2007 1  
CComboBox (and CListBox) with case-sensitive searching

ComboBoxCS Demo

When searching for strings in Combo boxes, the search is always case-insensitive. I have a need for a case-sensitive combo box in an application, so I have put together this class to implement that.

I could have used CComboBoxEx to give me a case-sensitive ComboBox, but it wouldn't be a drop-in replacement for a CComboBox. The methods normally used in CComboBox (eg AddString), are not implemented in CComboBoxEx. This would mean a lot of re-coding in order to use it.

How to use it

Using the CComboBoxCS class is very straightforward. Follow the steps below to add one to an existing project.

  1. After putting the source files (ComboBoxCS.cpp and ComboBoxCS.h) into the directory you wish to use them from, add the files to your Visual Studio project.
  2. In the resource editor, add a combo where you wish.
  3. In Class Wizard add a member variable for your combo control, selecting "Control" from the "Category" list, and selecting "CComboBoxCS" from the "Variable Type" list. (If CComboBoxCS does not appear in the list, you may need to delete your class wizard file (.clw) and regenerate it). I will assume your control variable name is m_combo.
  4. In order to make the combo case-sensitive, add a handler for WM_INITDIALOG in your dialog class if you don't already have one, and add the following code to it:
  5. m_combo.SetCaseSensitiveSearch();

That's all you need to do.

If you use many Combo boxes which you wish to make them all case-sensitive, you can set the default for all instances by adding:

m_combo.SetCaseSensitiveSearchDefault();

or alternatively, if you always want this behaviour, you can change the default value in the source code:

/*static*/ BOOL CListBoxCS::ms_bCaseSensitiveSearchDefault = TRUE;

How it works

The list box part of CComboBoxCS is subclassed to a CListBoxCS, which provides the case-sensitivity. (Note that the CListBoxCS class can be used in place of a CListBox should you require a case-sensitive list box). In order to subclass the list box, there are one or two methods available. One method ('the messy method') is to handle the WM_CTLCOLOR message. This is a standard (and well-documented) method. The other method ('the clean method') is to use the API function GetComboBoxInfo to ask the combobox for its list control. The drawback with the clean method is that it is only available on Win98, or WinNT 4.0 SP6, or later. The code uses LoadLibrary/GetProcAddress to determine whether the function is available. If it is it uses it, else it falls back to the messy method.

One problem with the messy method, is that the list box doesn't get subclassed until the user drops the list portion of the combo down. This is not good enough here, as we need the list to have been subclassed at the time we do a FindString or FindStringExact. So, we have to cheat.

On receipt of a FindString, FindStringExact, or SelectString message, we look to see whether we need to subclass the list. We need to if we are case-sensitive, and the list has not yet been subclassed. If we don't need to, then we simply pass the message on to the standard combobox Windows procedure.

Assuming we do need to subclass, we then call the function to drop the list portion of the combo. This forces the list to be (re)painted, which causes the required WM_CTLCOLOR to be sent to the combobox.

A problem with this is that we get the list box flicking up, and then closing again. To stop the list flickering, we can't just turn off redraw for the combo, as that doesn't affect the list, nor can we turn if off for the list, as we don't have it yet. The code I have used shrinks the combo so its list box is zero pixels high, and then drops it down. It is then resized to where it came from. This can all be done while the combo has redrawing turned off.

Using the clean method we don't have any of these problems, and can simply ask the combobox for a handle to the list box, which we then subclass. This is done at the earliest time it can be, which will be either as the user types in the edit control, as the list is dropped, or when the combobox receives a FindString/FindStringExact/SelectString message.

History

Version 2.2.1 - 20 Apr 2007

  • Updated to build correctly in VC7 (VS2003) and VC8 (VS2005)

Version 2.2 - 23 Jun 2004

  • Renamed FindString() method to OnFindString(), as this was preventing the use of the standard CComboBox::FindString method
  • added trap for owner-draw messages in the subclassed list to make sure they are handled by the combo-box, to resolve problems with using the combo with owner-draw, which in turn made the subclassed list owner-drawn
  • made the loading of USER32.DLL to provide GetComboBoxInfo() function happen once only for the life of the app, to prevent it happening each time a combo-box is sub-classed
  • changed handlers for CBN_EDITCHANGE and CBN_DROPDOWN to use ON_CONTROL_REFLECT_EX, to allow the control's parent to handle them also
  • added handler for LB_SELECTSTRING to CListBoxCS

Version 2.1 - 09 Jul 2003

  • Updated to support Unicode

Version 2 - 12 Jun 2002

  • new (clean) method of subclassing - uses API function GetComboBoxInfo() if available, else falls back to 'messy' method
  • added handling of CB_SELECTSTRING message
  • minor changes to the searching code

Version 1 - 11 Sep 2001

  • First version.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here