Click here to Skip to main content
15,868,164 members
Articles / Desktop Programming / MFC
Article

Custom ComboBox

Rate me:
Please Sign up or sign in to vote.
4.80/5 (21 votes)
4 May 2006CPOL4 min read 227K   7.6K   122   31
A combo box control with a custom popup control.

Classic ComboBox control

ComboBox with ListView control

ComboBox with MFCGrid control

ComboBox with popup dialog

Overview

This article describes how you can implement a combo box with various popup controls, including a dialog containing any kind of control. The article also shows the implementation of a combo box with the CListCtrl control, MFCGrid control, and a combo box with a popup dialog. As we already know, the combo box control contains two controls inside. The edit control which you can type text into, and a list box control containing string items which you can choose to appear in the edit area of the combo box.

Using the CCstmComboBox class

The CCstmComboBox class is derived from the MFC CComboBox class, and supports dialog data exchange and validation with DDX_CBString for CString and DDX_CBIndex for int variables like the ordinary CComboBox MFC class.

CCstmComboBox data members

enum e_popup_type
{
__CCB_STANDARD  = 0,
__CCB_LIST_CTRL = 1,
__CCB_MFC_GRID  = 2,
__CCB_DLGIALOG  = 4,
};

e_popup_type contains all the available types of popup controls.

protected:

//Height of a popup control
UINT             m_nHeight;
//Combo box information struct
PCOMBOBOXINFO    m_pcbInfo;
//Pointer to Popup Control
CWnd*            m_lstPopup;
//Subclassed edit control of a combo box control
CCstmEditCombo   m_wndEditCombo;
//Enabling/disabling autocompletion
bool             m_bAutoComplete;

CCstmComboBox Implementation

bool SetCustomPopupCtrl(
    e_popup_type _type
)
Description:Changes the classic popup list box control with the control of the specified type.
Parameter:

e_popup_type

Enumeration of the available popup controls.

Returns:true if change is successful, otherwise false.
CWnd* GetPopupCtrl(
    void
)
Description:Returns the current popup control. Not available for classic combo box.
Parameter:None.
Returns:Returns the window of the current popup control.
int SetDroppedHeight(
    UINT nHeight
)
Description:Sets the height of the popup control.
Parameter:

hHeight

Height in pixels.

Returns:nHeight of the popup control, otherwise CB_ERR.
void EnsureVisible(
    int nItem
)
Description:Ensures that an item of the popup control is visible.
Parameter:

nItem

Index of the item that is to be visible.

Returns:Nonzero if successful; otherwise zero.

Combo box class members

The following list also contains members of the MFC combo box. Details of them can be found in the MSDN documentation.

  • GetCount

    Retrieves the number of items in the popup control of a combo box.

  • GetCurSel

    Retrieves the index of the currently selected item, if any, in the popup control of a combo box.

  • GetDroppedControlRect

    Retrieves the screen coordinates of the visible (dropped-down) popup control of a drop-down combo box.

  • GetLBText

    Gets a string from the popup control of a combo box.

  • GetLBTextLen

    Gets the length of a string in the popup control of a combo box.

  • SetCurSel

    Selects a string in the popup control of a combo box.

  • SetDroppedWidth

    Sets the minimum allowable width for the drop-down popup control portion of a combo box.

  • AddString

    Adds a string to the end of the list in the list box of a combo box, or at the sorted position for list boxes with the CBS_SORT style. Only applicable for yje classic combo box.

  • DeleteString

    Deletes a string from the popup control of a combo box.

  • Dir

    Adds a list of filenames to the list box of a combo box. Only applicable for the classic combo box.

  • FindString

    Finds the first string that contains the specified prefix in the popup control of a combo box.

  • FindStringExact

    Finds the first popup control string (in a combo box) that matches the specified string.

  • InsertString

    Inserts a string into the list box of a combo box. Available only for the classic combo box.

  • SelectString

    Searches for a string in the popup control of a combo box and, if the string is found, selects the string in the popup control and copies the string to the edit control.

  • ResetContent

    Removes all items from the popup control and edit control of a combo box.

Popup Control (CListCtrl, CGridCtrl, CDialog)

Each popup control has common members which interact with a combo box.

  • bool CreatePopupCtrl(CWnd* pOwner);

    Creates a popup control. Returns true if successful, otherwise false.

  • int GetCount(void) const;

    Retrieves the number of items in the popup control of a combo box.

  • int GetCurrentSelection(void) const;

    Retrieves the index of the currently selected item.

  • int SetCurrentSelection(int nSelect);

    Sets the currently selected item.

  • void GetItemText(int nIndex,CString& rString) const;

    Gets the string of the selected item of the popup control.

  • int DeleteItem(UINT nIndex);

    Deletes an item from the popup control.

  • int FindString(int nStartAfter, LPCTSTR lpszString) const;

    Finds the first string that contains the specified prefix in the popup control.

  • int FindStringExact(int nStartAfter, LPCTSTR lpszString) const;

    Finds the first popup control string that matches the specified string.

  • void RemoveAllItems();

    Removes all items from the popup control.

Hot to use CCstmComboBox

Using CCstrmComboBox is the same as using a standard combo box.

In OnInitDilog, you have to call SetCustomPopupCtrl(e_popup_type _type) with the right enum type.

Populating a popup control

To populate a popup control, call GetPopupCtrl, and cast it based on the type of control you specified in the previous function call. Populating the popup control is specific and depends on the control implementation.

Populating the CListCtrl popup control

The code below shows populating the ListCtrl popup control.

//Combo with ListCtrl 
if(!m_cmbWithListCtrl.SetCustomPopupCtrl(
          CCstmComboBox::__CCB_LIST_CTRL))
   return FALSE;
m_cmbWithListCtrl.SetDroppedWidth(337);
m_cmbWithListCtrl.SetDroppedHeight(148);
CPopupListCtrl* pPopup = 
  (CPopupListCtrl*)m_cmbWithListCtrl.GetPopupCtrl();
pPopup->InsertColumn(0,_T("Column 1"), 
                    LVCFMT_LEFT, 150);
pPopup->InsertColumn(1, _T("Column 2"), 
                     LVCFMT_LEFT, 150);

for (int i = 0 ; i < 160; i++)
{
  CString item;
  item.Format(_T("Item %i,0"), i);
  int nItem = pPopup->InsertItem(pPopup->GetItemCount(), item);
  item.Format(_T("SubItem %i,1"), i);
  pPopup->SetItemText(nItem, 1, item);
}

Populating CGridCtrl (Chris Maunder's Grid control) popup control

This code populates the MFC Grid control:

//Combo with MFCGrid Ctrl
if(!m_cmbWithMFCGrid.SetCustomPopupCtrl(
          CCstmComboBox::__CCB_MFC_GRID))
    return FALSE;
m_cmbWithMFCGrid.SetDroppedWidth(337);
m_cmbWithMFCGrid.SetDroppedHeight(148);
CPopupMFCGid* pPopupMFC = 
   (CPopupMFCGid*)m_cmbWithMFCGrid.GetPopupCtrl();
m_ImageList.Create(MAKEINTRESOURCE(IDB_IMAGES), 
            16, 1, RGB(255,255,255));

pPopupMFC->SetImageList(&m_ImageList);
pPopupMFC->EnableDragAndDrop(TRUE);
pPopupMFC->GetDefaultCell(FALSE, 
           FALSE)->SetBackClr(RGB(0xFF, 0xFF, 0xE0));
pPopupMFC->SetFixedRowCount(1);
pPopupMFC->SetFixedColumnCount(1);
pPopupMFC->SetRowCount(10);
pPopupMFC->SetColumnCount(5);
pPopupMFC->SetAutoSizeStyle();

TRY {
   pPopupMFC->SetRowCount(16);
   pPopupMFC->SetColumnCount(6);
   pPopupMFC->SetFixedRowCount(1);
   pPopupMFC->SetFixedColumnCount(1);
}
CATCH (CMemoryException, e)
{
   e->ReportError();
   return FALSE;
}
END_CATCH

// fill rows/cols with text
for (int row = 0; row < pPopupMFC->GetRowCount(); row++)
{
    for (int col = 0; col < 
         pPopupMFC->GetColumnCount(); col++)
    {  
        CString str;
        GV_ITEM Item;
        Item.mask = GVIF_TEXT;
        Item.row = row;
        Item.col = col;

        if (row < pPopupMFC->GetFixedRowCount())
            str.Format(_T("Column %d"),col);
        else if (col < pPopupMFC->GetFixedColumnCount()) 
            str.Format(_T("Row %d"), row);
        else 
            str.Format(_T("%d"),row*col);
            Item.strText = str;

        if (rand() % 10 == 1)
        {
            COLORREF clr = RGB(rand()%128 + 128, 
                     rand()%128 + 128, rand()%128 + 128);
            Item.crBkClr = clr; 
            Item.crFgClr = RGB(255,0,0); 
            Item.mask |= (GVIF_BKCLR|GVIF_FGCLR);
        }

        if (col < pPopupMFC->GetFixedColumnCount())
        {
           Item.iImage = rand()%m_ImageList.GetImageCount();
           Item.mask |= (GVIF_IMAGE);
        }
        pPopupMFC->SetItem(&Item);
    }
}

Update History

  • 1.0.0.202 April 19. 2006 - First release version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Bosnia and Herzegovina Bosnia and Herzegovina
Bahrudin Hrnjica holds a Ph.D. degree in Technical Science/Engineering from University in Bihać.
Besides teaching at University, he is in the software industry for more than two decades, focusing on development technologies e.g. .NET, Visual Studio, Desktop/Web/Cloud solutions.

He works on the development and application of different ML algorithms. In the development of ML-oriented solutions and modeling, he has more than 10 years of experience. His field of interest is also the development of predictive models with the ML.NET and Keras, but also actively develop two ML-based .NET open source projects: GPdotNET-genetic programming tool and ANNdotNET - deep learning tool on .NET platform. He works in multidisciplinary teams with the mission of optimizing and selecting the ML algorithms to build ML models.

He is the author of several books, and many online articles, writes a blog at http://bhrnjica.net, regularly holds lectures at local and regional conferences, User groups and Code Camp gatherings, and is also the founder of the Bihac Developer Meetup Group. Microsoft recognizes his work and awarded him with the prestigious Microsoft MVP title for the first time in 2011, which he still holds today.

Comments and Discussions

 
GeneralRe: LVS_OWNERDATA & ListCtrl Pin
Bahrudin Hrnjica10-May-06 10:50
professionalBahrudin Hrnjica10-May-06 10:50 
GeneralRe: LVS_OWNERDATA & ListCtrl Pin
GeorgDuroy20-Dec-06 23:04
GeorgDuroy20-Dec-06 23:04 
GeneralThanks Pin
pgiustinoni5-May-06 12:56
pgiustinoni5-May-06 12:56 
GeneralRe: Thanks Pin
Bahrudin Hrnjica6-May-06 0:17
professionalBahrudin Hrnjica6-May-06 0:17 
GeneralRe: Thanks Pin
pgiustinoni6-May-06 0:52
pgiustinoni6-May-06 0:52 
Generalexcellent idea Pin
.dan.g.4-May-06 13:26
professional.dan.g.4-May-06 13:26 
GeneralRe: excellent idea Pin
Bahrudin Hrnjica4-May-06 23:38
professionalBahrudin Hrnjica4-May-06 23:38 
GeneralRe: excellent idea Pin
Stefan Dahlin5-May-06 1:34
Stefan Dahlin5-May-06 1:34 
That would be really cool with a combobox that shows a tree ctrl. There are some controls on CodeProject that almost works like that. But i don't really like them because they have all made their own tree control, and they dont work like a ordinary tree ctrl.

GeneralRe: excellent idea Pin
Johnnyfartpants20-Jan-07 22:00
Johnnyfartpants20-Jan-07 22:00 
GeneralThanks Pin
Wes Aday4-May-06 9:25
professionalWes Aday4-May-06 9:25 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.