Click here to Skip to main content
Click here to Skip to main content

CheckComboBox Control

By , 24 Nov 1999
 

Sample Image

Introduction

What does a CheckComboBox control do? A combo box has always been a way of selecting one item from a list of several. If you need to select one or more items, you have to either use a multiple selection listbox or use the MFC's CCheckListBox. The only problem is that it takes up space in your dialog or form. What you need is a CCheckComboBox!

When I started to develop the control, I was planning to design a composite control consisting of a static control along with a small button. When clicking the button, a popup window would be displayed where the user could select or unselect the items. The problem was that it took too much code to implement. I wanted the look and feel just like a standard combo box and that was not possible with a reasonable amount of code.

So I decided to subclass the combo box. A problem when subclassing the combo box is that you have no window handle to the list portion of the combo box that you may subclass. You only have the combo box window handle and that doesn't help.

The trick is to listen to the WM_CTLCOLORLISTBOX message. When the WM_CTLCOLORLISTBOX message is sent, lParam contains the window handle of the list box. This is the time to do the subclassing.

The code below shows how this is done:

BEGIN_MESSAGE_MAP(CCheckComboBox, CComboBox)
    ...
    ON_MESSAGE(WM_CTLCOLORLISTBOX, OnCtlColorListBox)
    ...
END_MESSAGE_MAP()

...
LRESULT CCheckComboBox::OnCtlColorListBox(WPARAM wParam, LPARAM lParam) 
{
    // If the listbox hasn't been subclassed yet, do so...
    if (m_hListBox == 0) {
        HWND hWnd = (HWND)lParam;

        if (hWnd != 0 && hWnd != m_hWnd) {
           // Save the listbox handle
           m_hListBox = hWnd;

           // Do the subclassing
           m_pWndProc = (WNDPROC)GetWindowLong(m_hListBox, GWL_WNDPROC);
           SetWindowLong(m_hListBox, GWL_WNDPROC, (LONG)ComboBoxListBoxProc);
        }
    }


    return DefWindowProc(WM_CTLCOLORLISTBOX, wParam, lParam);
}

After this is done, the rest is fairly straight forward. The ComboBoxListBoxProc() routine takes care of selecting/unselecting items and key down events. The overridden DrawItem() routine draws both the list items and the static portion of the combo box. If it is an item, it draws a checkmark followed by the text. If it is the static portion, it draws the text from all selected items separated by the standard list separator.

Please note that the CCheckComboBox must be created with the CBS_DROPDOWNLIST and the CBS_OWNERDRAWVARIABLE styles set. Also the CBS_HASSTRINGS style must be specified since I let the combo box handle the item strings (sorting etc.).

Since the check mark information is stored in the combo box item data, this may not be used by the application. Setting it to zero unselects the item otherwise it selects the item. But use the GetCheck() and SetCheck() routines instead since they handle redrawing correctly. If you need your own item data, you must implement this yourself.

It is easy to use this control since it is derived from the MFC CComboBox. Add CheckComboBox.h and CheckComboBox.cpp to your project and use it as a standard CComboBox. When used inside a dialog, simply select the category "Control" and variable type "CCheckComboBox" under the "Member Variables" page of the Class Wizard. This will declare a member variable in your dialog of type CCheckComboBox ready for you to use.

Well, I hope someone finds this useful. At least I did.

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

About the Author

Magnus Egelberg, Lundalogik
Sweden Sweden
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionUnable to increase drop down wdithmemberNipunG25 Sep '12 - 20:44 
Hi...I am developing an owner draw ComboBox using your CCheckComboBox class. But I am unable to increse the with of the combo box. I tried with SetDroppedWidth() function too but no success.
Any clue?
QuestionCBN_SELCHANGE?memberbosfan31 Jul '12 - 1:31 
Hi,
many thanks for this work.
I have a question, if i ad a function with CBN_SELCHANGE this event is called
four times as much if i have four items in a combo box?
For everey item one time? How to avoid this, so the CBN_SELCHANGE is called only one time if i select or unselect an item??
 
Best regards
BugWin x64 failmemberAJG8514 May '12 - 13:13 
This doesn't compile on 64bit Windows, after fixing the compatibility errors with GetWindowLong and SetWindowLong it throws exceptions when calling the user defined callback and terminates the application.
 
Not very useful in this decade ;-(
GeneralRe: Win x64 failmemberAJG8515 May '12 - 11:40 
I didn't go quite far enough with my updates initially, so here's the fix for reference:
 
Replace GWL_ID with GWLP_ID
Replace GWL_WNDPROC with GWLP_WNDPROC
Replace GetWindowLong with GetWindowLongPtr
Replace SetWindowLong with SetWindowLongPtr
Replace (LONG) casts with (LONG_PTR) casts
 
and the piece I forgot yesterday:
 
Replace the callback signature extern "C" LRESULT FAR PASCAL ComboBoxListBoxProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
with LONG_PTR CALLBACK ComboBoxListBoxProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
 
This will make it work on 64bit windows and is backwards compatible with 32bit windows so no ifdefs needed.
QuestionHow to use GetDlgItem()memberamitwadekar17 Jan '12 - 2:08 
How to use GetDlgItem() in this case.
HWND m_hWndGroup = GetHWND(); //Obtain HWND 
CWnd *pWnd = CWnd::FromHandle(  m_hWndGroup );;
CCheckComboBox* combocheck =  (CCheckComboBox *)pWnd->GetDlgItem(IDC_TEST);//IDC_TEST- ID of combobox
 
But it behaving like normal CComboBox. I want to use it in command bar dialog.
Please help me.
 
-Amit
GeneralMy vote of 5memberEmmo2 Jun '11 - 5:20 
Nice and simple, does what it says. Thanks!
GeneralMy vote of 5memberPhil Outram6 Aug '10 - 5:00 
Very useful and seems robust. Many thanks.
GeneralMy vote of 1memberxinkmt3 Aug '10 - 15:09 
old
GeneralBug - before subclassing behaviormemberJohn59027 Aug '09 - 0:37 
I have found a little but annying bug.
If you start the demo and only press the tab key to reach the combo box and then you press the UP or DOWN keys then the combo shows the checkbox and test of the currently selected item instead of the checked items list.
 
To fix this annoying problem you only need to correct this line:
// Check if we are drawing the static portion of the combobox
if( (LONG)lpDrawItemStruct->itemID < 0 ) {
 
TO
 
// Check if we are drawing the static portion of the combobox
if( (LONG)lpDrawItemStruct->itemID < 0 || m_hListBox == 0 ) {
 
I hope this help all those that are using this class.
GeneralRe: Bug - before subclassing behavior...and fix to get arrow keys opening drop down boxmemberPhil Outram6 Aug '10 - 5:23 
If you use the arrow keys when you've tabbed to the control, you actually want it to drop down.
 
This isn't the default ComboBox behviour, so OnKeyDown needs to be overidden...
 
//////////////////////////////////////////////////////////////////////////////////////////////////
// Trap arrow keys when list is not dropped down and drop the list.  This isn't normal combobox 
// behaviour which usually just switches through the combobox items without using the dropdown
// box.
void CCheckComboBox::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
    if ((nChar == VK_DOWN) || (nChar == VK_LEFT) || (nChar == VK_RIGHT) || (nChar == VK_UP))
        ShowDropDown();
 
    CComboBox::OnKeyDown(nChar, nRepCnt, nFlags);
}

GeneralExcellent controlmembersimbakid26 Mar '09 - 22:14 
Magnus, thank you for this control, it's so simple to use and works flawlessly.
 
Thumbs Up | :thumbsup: Smile | :)
Questioncombobox show only one item at dropdownmemberrotalume17 Jan '09 - 6:16 
I've tried your sample code and it works fine with my environment.
Then I put the same setting as your code with a CComboBox in a CDialog inheritance then set the class as CCheckComboBox and it works fine except one problem, even I add item more than one (may be 7 or more), the drop down list only show one item at once, I can only view every item by click the left scroll bar. Does anything need to be noticed?
AnswerRe: combobox show only one item at dropdownmemberrotalume18 Jan '09 - 18:55 
I've solved myself. In my case, I need to use "MoveWindow" to set Height of ComboBox so that the drop content can be shown.
QuestionCan you give more explain?memberparadise of pig20 Oct '08 - 8:35 
This explame is very good!But I Can't Understand very well.Can you give more explain?about CCheckComboBox Smile | :)
GeneralCan't see the List after click on the combo box.membernankyu119 Oct '08 - 20:25 
Hi.
 
I use your CheckComboBox control on a modal dialog. I declared "CheckComboBox.h" in my dialog header file.
I could not see the list of strings that I put, dropping down. However, when I use up/down button on keyboard to see what's inside (strings), I could see one by one in combo box. Why is it so? Please can you guide me?
 
n_super
GeneralRe: Can't see the List after click on the combo box.memberMagnus Egelberg19 Oct '08 - 20:35 
This can happen when the combobox height is too small. Is that the case?
GeneralRe: Can't see the List after click on the combo box.membernankyu119 Oct '08 - 21:05 
No. It is not. I cannot see the dropdown list at all once I clicked on it. I think it is not.
I have two Visual Studio 2003 and 2005. I ran your sample project in VS 2003 and it is very OK. But once I just copy and paste your codes to display in a modal dialog of my project in VS 2005 , I couldn't see the list. What should I do?
Thanks alot for reply.
GeneralRe: Can't see the List after click on the combo box.memberMartin Chapman20 Jan '10 - 17:20 
The fix to this issue is to set the "Owner Draw" property of the control to "Fixed" instead of "Variable". This property can be set by viewing the properties of the control in the resource editor.
GeneralRe: Can't see the List after click on the combo box.memberMartin Chapman20 Jan '10 - 17:27 
Ok, better yet, change this part of the code:
 
BOOL CCheckComboBox::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
dwStyle &= ~0xF;
dwStyle |= CBS_DROPDOWNLIST;
dwStyle |= CBS_OWNERDRAWVARIABLE;
dwStyle |= CBS_HASSTRINGS;
return CExtComboBox::Create(dwStyle, rect, pParentWnd, nID);
}
 
Change:
dwStyle |= CBS_OWNERDRAWVARIABLE;
to
dwStyle |= CBS_OWNERDRAWFIXED;
Generalwhere can i find a version written by c#memberlinzhuo25 Jun '08 - 22:10 
i want to get such code
GeneralLicensememberlanreola26 Mar '08 - 6:12 
Can I reuse this code in a commercial application?
QuestionRe: LicensememberScott Bartine6 Dec '11 - 10:11 
We too would like to use your control in a commercial product and are requesting your permission to do so, as well as modify it to create a derivative work and permission to distribute it to our customers.
 
Your reply is appreciated and thank you for making your software available.
 
Kind regards.
Questionhow to disable check box selection ?membermrgoos19 Aug '07 - 4:40 
Hi all.
Great Class but my question is, how can you prevent the user from selecting one/some of the check boxes ?
How to disable a check box ?
Thanks,
Yaron.:->
QuestionTool tip for Combo contolmembersajithomas21 Jun '07 - 22:52 
Hi,
I am writing ATL program. In my Dlg I am having combo contol.
Let me know how to add tool tip for the combobox items.

 
SAJI
GeneralUsing CheckComboBoxmemberjives30 Apr '07 - 2:52 
Hi, I would like to use this excellent control in a MS Access project. How can I do this? Thx.....J

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 25 Nov 1999
Article Copyright 1999 by Magnus Egelberg, Lundalogik
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid