Click here to Skip to main content
6,306,412 members and growing! (17,618 online)
Email Password   helpLost your password?
Desktop Development » Combo & List Boxes » ComboBox Controls     Intermediate

AdvComboBox - Version 2.1

By Mathias Tunared

A Combobox in which the user can resize the drop window. Can be standard style or flat style.
VC6Win2K, WinXP, MFC, Dev
Posted:16 Jul 2002
Updated:5 Sep 2002
Views:298,656
Bookmarked:125 times
Announcements
Loading...
 
Search    
Advanced Search
printPrint   Broken Article?Report       add Share
  Discuss Discuss   Recommend Article Email
75 votes for this article.
Popularity: 8.95 Rating: 4.77 out of 5
3 votes, 7.9%
1
1 vote, 2.6%
2
1 vote, 2.6%
3
2 votes, 5.3%
4
31 votes, 81.6%
5

Sample Image - CAdvComboBox

AdvComboBox Article Index

   Introduction
   Installation
   Functions
   Notifications
   Styles
   Future upgrades
   Hints & Tips
   Improvements and Bug Fixes

What's new in Version 2.1

I got really tired of having to add all items in the InitDialog function, which can be really annoying in the case where you have several CAdvComboBox in one page. This class will now look for an entry in the stringtable with the same ID as the CAdvComboBox control has in the resource editor. The demo project has been upgraded to display this feature. More information about this has been added under Installation. If you want to add another stringtable entry, just call the new function LoadString(UINT nID) where nID refers to the stringtable entry.

In this version, I have added the code so the CAdvComboBox can be used with the macro RUNTIME_CLASS. Requested by Krishna.

I've also added the missing functionality that opens the dropdown window by pressing Alt-Down or Alt-Up. This was requested by Thomas Freudenberg.

Introduction

I started to work on a control that I was going to use in another program that had combo boxes within a CListBox. The first criteria that I wanted was that the combobox should be flat (no shadows). I looked around for a while and could not find any suitable so I had to create my own somehow. When I had started to work on the flat combobox, I come to think of another cool feature that would be nice to have. How many times have you wanted the same functionality as the address bar in IE. When you type an address and the IAutoComplete COM-object goes to work. Wonderful!...or not. I wanted the same functionality in a my combobox, and especially the resizeable dropdown window. And so, back to the drawing board. After many long nights and several different approaches, I got it to work.

This ComboBox is not subclassing the MFC's CComboBox mostly because I wanted to be able to resize the drop-down window. Instead, I created a CWnd object that looks almost the same as MFC's CComboBox. The tricky part was to get the dropdown window to react the same way as CComboBox. First of all, the dropdown window has to be a child to the desktop, and then there is the nasty problem with the mouse and keyboard capture. The solution to that problem was to have one window that has a listbox and a scrollbar within itself. The scrollbar that the CListBox class uses could not be used due to the capture problem.

During the development more features were added; checked items and disabled items in the dropdown window.

Below is a picture over the class structure.

Class overview
Picture 1

The dropdown window of the AdvComboBox is of an autosize style, that is, it calculates the size it needs to show all items in the list.
So the result is a combobox that acts almost the same as the MFC's CComboBox. You should not have to change any code that are already in use, besides that you have to change the resource from the standard combobox to a custom control. I have tested on W2K and XP. Now I turn to CodeProject's members and other to help me test and find bugs, and maybe some new features to add.

Installation

Installation Index
   Create a new project
   Upgrade your current project
   Use CAdvComboBox in a MFC DLL

This article contains of three different ways of implementing the CAdvComboBox class into your project. One describes the workorder for a new project, and the second how to upgrade your current projects, and the last how to implement the CAdvComboBox in a MFC DLL.

Create a new project

  1. Create a dialog application using the App Wizard.

  2. The explanation below are built upon that you call your application AdvCBDemo

  3. Insert the following files to your workspace
  4. AdvComboBox.h
    AdvComboBox.cpp
    DropWnd.h
    DropWnd.cpp
    DropListBox.h
    DropListBox.cpp
    DropScrollBar.h
    DropScrollBar.cpp
    VisualStylesXP.h
    VisualStylesXP.h

  5. Include the file AdvComboBox.h in your AdvCBDemoDlg.h file

  6. Add a custom control to your dialog

  7. In resource editor, place a new custom control in the dialog by using the Custom Control tool in the toolbar. Enter the properties for the control as shown in the picture below.

    The CAdvComboBox custom control class name is AdvComboBoxCtrl which is defined in AdvComboBox.h.

    Custom control properties
    Picture 2

    Descriptions of the different styles to set:
     Combo style  Value in property window
     CBS_DROPDOWN  0x_____002
     CBS_DROPDOWNLIST  0x_____103
     CBS_AUTOHSCROLL  0x_____043
     CBS_SORT  0x_____103

    So this means that if you want your combobox to have the styles CBS_DROPDOWN, CBS_AUTOHSCROLL, and CBS_SORT the style value should end with 142(as seen in picture 2). You can also edit the resource file in text mode and add the styles there. The resouce editor then translate the style you have choosen into this value.

    The following styles has not been implemented yet:

       CBS_DISABLENOSCROLL
       CBS_HASSTRINGS
       CBS_LOWERCASE
       CBS_NOINTEGRALHEIGHT
       CBS_OEMCONVERT
       CBS_OWNERDRAWFIXED
       CBS_OWNERDRAWVARIABLE
       CBS_SIMPLE
       CBS_UPPERCASE

  8. Add the following public member variable to your CAdvCBDemoDlg class in the AdvCBDemoDlg.h header file:
  9. CAdvComboBox	m_ctlAdvCombo;
  10. Add the following DXX_ call in your AdvCBDemoDlg.cpp file
    DDX_Control(pDX, IDC_ADV_COMBO, m_ctlAdvCombo);
    Add it outside of AFX_DATA_MAP to avoid any mishaps in the future.
    Now, the function DoDataExchange(...) should look like this:
    void CAdvCBDemoDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	//{{AFX_DATA_MAP(CAdvCBDemoDlg)
    
    		// NOTE: the ClassWizard will add DDX and DDV calls here
    
    	//}}AFX_DATA_MAP
    
    	DDX_Control(pDX, IDC_ADV_COMBO, m_ctlAdvCombo);
    }
    
  11. Compile and run

  12. You should now be able to test your dialog with the AdvComboBox within it.

    Another feature that still has to be implemented is how to get and set data from the control. This is described below.

  13. Set and get data from AdvComboBox

  14. You can use the same way to get and set data as you would with a normal CComboBox, except one small difference.
    The DDX_CBIndex and DDX_CBString should be changed to DDX_ACBIndex and DDX_ACBString for it to work. These functions can be found in the AdvComboBox.cpp file.

    To add functionality to get and set data add one of, or both, the following variables in your AdvCBDemoDlg.h file

    int	m_nAdvCombo;
    CString	m_strAdvCombo;
    You also have to initialize the value to these variables in the constructor of CAdvCBDemoDlg. Add the following code outside AFX_DATA_INIT.
    m_nAdvCombo = -1;
    m_strAdvCombo = "";
    Add also the DDX_ calls in the function DoDataExchange(...) in AdvCBDemoDlg.cpp file below the DDX_Control that you added in step 6.
    DDX_ACBIndex( pDX, IDC_ADV_COMBO, m_nAdvCombo );
    DDX_ACBString( pDX, IDC_ADV_COMBO, m_strAdvCombo );

    You should now be able to use the AdvComboBox control in the same way as the MFC's CComboBox.

    The following was added in version 2.1

  15. Use a stringtable entry to populate the CAdvComboBox list.

  16. To be able to use the stringtable with this combobox, a stringtable entry has to be created with the same identifier as the control was created with in the resource editor. In this case, the stringtable entry ID should be IDC_ADV_COMBO. Below is a picture (picture 3) of this example that you can add to your project.

    In the stringtable entry, a newline ('\n') represents the ending of one item in the combobox list. Please look into the demo project for further information on how to implement this.

    Stringtable entry
    Picture 3

Upgrade your current project

This description is not so detailed as the one above. Hopefully you have enough knowledge to manage the following.
  1. Insert the following files to your workspace
  2. AdvComboBox.h
    AdvComboBox.cpp
    DropWnd.h
    DropWnd.cpp
    DropListBox.h
    DropListBox.cpp
    DropScrollBar.h
    DropScrollBar.cpp
    VisualStylesXP.h
    VisualStylesXP.h

  3. Include the file AdvComboBox.h in your header file

  4. Change classnames

  5. Rename all of your CComboBox variable definitions to CAdvComboBox in your header file.

  6. Replace resource comboboxes

  7. Replace your current comboboxes in the resource editor to custom controls and set the properties as shown in picture 2. You can of course change the style of the custom control.

    Tip! Use the same ID for your custom controls as you had for the comboboxes. This makes it a lot easier further on so that you won't have to change ID's for all your events(ON_CBN_SELCHANGE, etc.) currectly assigned to the standard comboboxes.

  8. Change DDX_ calls

  9. Change all DDX_CBIndex and DDX_CBString to DDX_ACBIndex and DDX_ACBString in your .cpp file. Change the ID's in these calls if you didn't set the same ID's on your new custom controls as you had on the old comboboxes.
  10. Compile and test

  11. Your project should now work except the limitations of the CAdvComboBox.

Use CAdvComboBox in a MFC DLL

This is just a small description of how to use this class in a DLL that has windows(dialogs) in the DLL, and those windows uses CAdvComboBox. To be able to register the class, you have to change the code somewhat. The HINSTANCE in the structure WNDCLASS must have the DLL's HINSTANCE, and not the calling applications HINSTANCE.
  1. Declare a CAdvComboBox variable

  2. Create the class like this:
    CAdvComboBox m_ctlAdvCombo( TRUE )
  3. Global HINSTANCE variable

  4. You also have to add a global HINSTANCE variable the the DLL project.
    Add the following to, for example, StdAfx.cpp in your DLL project:
    HINSTANCE g_hDLLInstance = NULL;
    Then, add the extern definition in the StdAfx.h file like this:
    extern HINSTANCE g_hDLLInstance;
  5. Initialize the global HINSTANCE

  6. Set the hDllInstance in the DllMain function.
    g_hDLLInstance = hInstance;
  7. Change code in CAdvComboBox

  8. Next thing is to find the function RegisterWindowClass() in the AdvComboBox.cpp file. Change the function so it looks like this:
    BOOL CAdvComboBox::RegisterWindowClass()
    {
        WNDCLASS wndcls;
        HINSTANCE hInst;
        if( m_bInst )
        {
            hInst = g_hDLLInstance;
        }
        else
        {
            hInst = AfxGetInstanceHandle();
        }
    
        ASSERT( hInst != 0 );
    
        ...
    	
        return TRUE;
    }
    

  9. Export the CAdvComboBox class

  10. Last, but not least, you have to make the class exported if you want to be able to use it outside the DLL. Remember to make the two DDX_ functions exported too. Class definition:
    class __declspec(dllexport) CAdvComboBox : public CWnd
    DDX_ Definitions:
    _declspec(dllexport) void AFXAPI DDX_ACBIndex( CDataExchange* pDX, 
                                                   int nIDC, int& index );
    _declspec(dllexport) void AFXAPI DDX_ACBString( CDataExchange* pDX, 
                                                    int nIDC, CString& value );

AdvComboBox Functions

The functions in CAdvComboBox class are the same as in MFC's CComboBox. For mor help on those, look in MSDN.
There are also some extra functions that can be used. These are described below
  • GetComboRect
  •  
     Description: Retrieve the pos and size of the combobox with this function
     Definition: CRect& GetComboRect()
     Returns: Rect of the AdvComboBox
     
  • GetDefaultVisibleItems     New in ver 2.0
  •  
     Description: Returns the default number of visible items of the dropdown window. To set the default number, use SetDefaultVisibleItems(int)
     Definition: int GetDefaultVisibleItems()
     Returns: Number of items.
     
  • GetItemChecked
  •  
     Description: Get the checked status of an item
     Definition: BOOL GetItemChecked( int nIndex )
     Parameter: nIndex
     Item index in list
     Returns: TRUE if item nIndex is checked, or CB_ERR if an error occurred.
     
  • GetItemDisabled
  •  Description: Get the disabled status of an item
     Definition: BOOL GetItemDisabled( int nIndex )
     Parameter: nIndex
     Item index in list
     Returns: TRUE if item nIndex is disabled, or CB_ERR if an error occurred.
     
  • GetMinVisibleItems     New in ver 1.2
  •  Description: Get the minimum visible listbox items in the dropwindow, before the dropwindow will be placed above the combobox.
     Definition: int GetMinVisibleItems()
     Returns: Number of minimum visible listbox item.
     
  • LoadString     New in ver 2.1
  •  Description: Load an entry from the stringtable and add the items in that entry in the dropwindow list.
     Definition: void LoadString( UINT nStringID )
     Parameter: nStringID
    ID of the string to load.
     Returns: void
     
  • ModifyACBStyle
  •  Description: Modify the style of the CAdvComboBox. The available styles can be found here. This function handles only the ACBS_ styles. It work as MFC's ModifyStyle.
     Definition: void ModifyACBStyle(UINT nRemoveStyle, UINT nAddStyle)
     Parameter: nRemoveStyle
     ACBS style to remove.
     Parameter: nAddStyle
     ACBS style to add.
     Returns: void
     
  • PointInWindow
  •  Description: Is a CPoint within the combobox rect?
     Definition: BOOL PointInWindow( CPoint ptScreenPoint )
     Parameter: ptScreenPoint
     Is this point within the combobox.
     Returns: TRUE if the point is in combobox window.
     
  • SetDefaultVisibleItems     New in ver 2.0
  •  Description: Set the default visible number of items in the dropdown window.
     Definition: void SetDefaultVisibleItems( int nItems = -1 );
     Parameter: nItems
     Number of items to be visible when the dropdown window is shown. Set this to -1 if the style should be autosize.
     Returns: void
     
  • SetItemChecked
  •  Description: Set an item in combo to either check or un-checked.
     Definition: void SetItemChecked( int nIndex, BOOL bChecked )
     Parameter: nIndex
     Zero-based item index to the item to set.
     Parameter: bChecked
     New state of the item to set.
     Returns: void
     
  • SetItemDisabled
  •  Description: Set an item in combo to either disabled or enabled.
     Definition: void SetItemDisabled(int nIndex, BOOL bDisabled)
     Parameter: nIndex
     Zero-based item index to the item to set.
     Parameter: bDisabled
     New state of the item to set.
     Returns: void
     
  • SetMinVisibleItems     New in ver 1.2
  •  Description: Set the minimum visible listbox items in the dropwindow, before the dropwindow will be placed above the combobox. The default is five items.
     Definition: void SetMinVisibleItems(int nMinItems)
     Parameter: nMinItems
     Number of minimum listbox items.
     Returns: void
     
  • DDX_ACBIndex
  •  Description: Use this function to get and set data with MFC's UpdateData(...)
     Definition: void AFXAPI DDX_ACBIndex( CDataExchange* pDX, int nIDC, int& index )
     
  • DDX_ACBString
  •  Description: Use this function to get and set data with MFC's UpdateData(...)
     Definition: void AFXAPI DDX_ACBString( CDataExchange* pDX, int nIDC, CString& value )

Below is a list of CComboBox functions implemented in CAdvComboBox.

  • AddString
  • DeleteString
  • FindString
  • FindStringExact
  • GetCount
  • GetCurSel
  • GetDroppedControlRect
  • GetDroppedState
  • GetEditSel
  • GetItemData
  • GetItemDataPtr
  • GetLBText
  • GetLBTextLen
  • GetTopIndex
  • InsertString
  • LimitText     New in ver 1.2
  • ResetContent
  • SelectString
  • SetCurSel
  • SetEditSel
  • SetItemData
  • SetItemDataPtr
  • SetTopIndex
  • ShowDropDown

The following CComboBox functions are not implemented in CAdvComboBox

  • Clear
  • CompareItem
  • Copy
  • Cut
  • Dir
  • DrawItem
  • DeleteItem
  • GetDroppedWidth
  • GetExtendedUI
  • GetHorizontalExtent
  • GetItemHeight
  • GetLocale
  • MeasureItem
  • Paste
  • SetDroppedWidth
  • SetExtendedUI
  • SetHorizontalExtent
  • SetItemHeight
  • SetLocale

AdvComboBox Notifications

The CAdvComboBox sends the following notifications to the parent, as MFC's CComboBox does.
  • CBN_CLOSEUP
  • CBN_DROPDOWN
  • CBN_EDITCHANGE
  • CBN_EDITUPDATE
  • CBN_KILLFOCUS
  • CBN_SELCHANGE
  • CBN_SELENDCANCEL
  • CBN_SELENDOK
  • CBN_SETFOCUS

The following notifications are not sent.

  • CBN_DBLCLK

  • This message is only sent when the combobox style is CBS_SIMPLE and CAdvComboBox does not support this style.
  • CBN_ERRSPACE

  • There are no memory management built into this control yet, and I'm not sure if I'll ever do that. Boring!

AdvComboBox Styles

The CAdvComboBox has its own styles. They are described here.
  • ACBS_FLAT

  • Makes the combobox flat. With this style the combobox will be drawn all the way out to the borders of the custom control rect in the resources.
  • ACBS_STANDARD

  • With this style the combobox will be drawn as an ordinary combobox, i.e. 3D look.
  • ACBS_CHECKED

  • To make the dropdown window contain a checkable list, use this style.
  • ACBS_AUTOAPPEND

  • The AdvComboBox will automaticallly search the dropwindow items after the nearest match to the text that has been entered in the editbox of the AdvComboBox. If found, it will then append the remaining text to the editbox.
  • ACBS_AUTOSUGGEST

  • While entering text in the editbox, the AdvComboBox will display a list in the dropdown window the matches the entered text.

The CAdvComboBox supports the following CComboBox styles

  • CBS_AUTOHSCROLL
  • CBS_DROPDOWN
  • CBS_DROPDOWNLIST
  • CBS_SORT

The following CComboBox styles are not supported

  • CBS_DISABLENOSCROLL
  • CBS_HASSTRINGS
  • CBS_LOWERCASE
  • CBS_NOINTEGRALHEIGHT
  • CBS_OEMCONVERT
  • CBS_OWNERDRAWFIXED
  • CBS_OWNERDRAWVARIABLE
  • CBS_SIMPLE
  • CBS_UPPERCASE

Future Upgrades

  • .NET compatible

Hints & Tips

  • Use ClassWizard

  • Create your project with MFC's CComboBox so the ClassWizard can help you with notification implementation like ON_CBN_SELCHANGE. When you have created all events for the combobox, change to CAdvComboBox. This is the easiest and fastest way to implement this class.

  • Set style to flat

  • Add a call in OnInitDialog() to ModifyACBStyle(...) like this:
    m_ctlAdvCombo.ModifyACBStyle( 0, ACBS_FLAT );
  • Windows Theme compatible

  • The AdvComboBox is theme compatible, to the extent that I have tested it. Please let me know if any colors or anything else are wrong. Before telling me, compare one more time with a CComboBox please.

Improvements and Bug Fixes

Version 2.1

  • Stringtable entry with same ID will populate the list.


  • Added function LoadString(UINT)


  • Macro RUNTIME_CLASS can now be used.

  • In this version, I have added to the code so the CAdvComboBox can be used with the macro RUNTIME_CLASS. Requested by Krishna.

  • Pressing Alt+Up/Down opens the dropdown window.

  • Added the missing functionality that opens the dropdown window by pressing Alt-Down or Alt-Up. This was a request from Thomas Freudenberg.

Version 2.0

  • Added function GetDefaultVisibleItems()


  • Added function SetDefaultVisibleItems(int)


  • Added CAdvComboBox style ACBS_AUTOAPPEND


  • Added CAdvComboBox style ACBS_AUTOSUGGEST


  • The CAdvComboBox is now also compatible with CommCtrl 6.0 manifest.

  • I used David Yuheng Zhao's class CVisualStylesXP as the working ground, but I have added some functionality like the functions fetched from the DLL is now static functions, and a function that checks the CommCtrl DLL version to see if we are able to use visual styles. If a manifest is not used, this function will tell us just that even if we're running on WinXP.

  • Added two new files: VisualStylesXP.h and VisualStylesXP.cpp


Version 1.21

  • Fixed a bug when using Create(...)

  • The bug appeared when trying to create the CAdvCombBox class with the function Create(...) and the style was CBS_DROPDOWN. Thanx for finding this bug.

Version 1.2

  • Scrolling the dropwindow with the mousewheel is implemented.


  • The CComboBox function LimitText is now implemented.


  • The need for Windows definition _WIN32_WINNT is removed.


  • Dropwindow above control

  • The dropdown window will be shown above the combobox if the distance to the bottom of the screen is not enough. The default minimum number of listbox items is set to five, but this value can be changed by calling the function SetMinVisibleItems(int) in CAdvComboBox class.

Version 1.1

  • The control can now be disabled.


  • Switching to another program when the dropwindow is down closes the dropwindow.


  • Corrected a minor drawing error under Win2K.

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

Mathias Tunared


Member
I'm a software designer working for Telepo AB in Stockholm, Sweden.

Occupation: Web Developer
Location: Europe Europe

Other popular Combo & List Boxes articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 106 (Total in Forum: 106) (Refresh)FirstPrevNext
GeneralHow to make the width of the scrollbar bigger? Pinmemberdragomir6:34 1 Jun '09  
GeneralMy vote of 2 Pinmemberjoerg-schumann4:10 22 Jan '09  
GeneralRe: Multiple Monitors Pinmemberpietje_013:30 30 Jan '09  
GeneralCDropWnd crash Pinmembersimon heffer6:58 7 Feb '07  
GeneralCListCtrl instead of CListBox will help... Pinmemberanandarv17:58 4 Dec '06  
QuestionUse in commercial application? PinmemberCarl Fredrik Abelson2:12 27 Nov '06  
GeneralQuestion (Virtual List for more than 32736 items) ? Pinmemberana_v12310:23 25 Nov '06  
QuestionNo XP Users PinmemberAngelPortal3:08 14 Nov '06  
GeneralWhy not emplemented clear method? Pinmemberfst-fst22:59 20 Sep '06  
GeneralI had to make the following mods to make it work as I wanted Pinmembercokes3:14 21 Jul '06  
GeneralFeature Request to Mathias Tunared..! Pinmemberana_v1238:05 10 Jul '06  
Generalno case censetive Pinmemberdmit_klg21:54 5 Jun '06  
GeneralAutocompletion scrolling problem PinmemberThomas Blenkers10:21 17 May '06  
GeneralHow to set the height ? Pinmemberouquoi4:20 17 Feb '06  
GeneralProblem with combo in Windows 98 PinmemberManuel Bautista5:52 21 Dec '05  
GeneralWinXP and Classic Theme selection PinmemberManfred Kubica20:29 14 Jul '05  
Generala big bug Pinmemberdirkiller16:47 22 May '05  
GeneralRe: a big bug PinsussAnonymous15:19 24 May '05  
GeneralActive X Control Pinmemberrk8242:44 11 May '05  
GeneralA flat scrollbar will be good Pinmemberz1616615:18 10 Mar '05  
Generala small memory leak bug Pinmemberz1616615:13 10 Mar '05  
GeneralGreat Control and Example! PinmemberGalileomak4:53 28 Nov '04  
GeneralBug with ESC- key PinsussStefan Pfitzner0:42 12 Jul '04  
GeneralI've created this control dynamically, but where EditBox? PinmemberGonsaless7:49 30 May '04  
GeneralA few small changes PinmemberGuy Clinger11:21 7 May '04  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 5 Sep 2002
Editor: Chris Maunder
Copyright 2002 by Mathias Tunared
Everything else Copyright © CodeProject, 1999-2009
Web13 | Advertise on the Code Project