The CComboBox Class wraps a native Combo Box control. It is a fairly basic implementation that meets the most common use case: Displaying strings for selection by the user.
If you need additional functionality, you can use a CComboBoxEx Class instead. It exposes the full set of operations of the underlying ComboBoxEx control. In particular, the items can be configured to retrieve a string representation for items at runtime, based on arbitrary information.
The following is assuming, that your custom item data layout is as follows:
struct CustomItemData {
CStringW m_Name;
int m_SomeInteger;
};
The item data can be arbitrarily complex, and hold any information you wish to store. Populating a CComboBoxEx
with items requires calling CComboBoxEx::InsertItem, passing an appropriately filled COMBOBOXEXITEM structure:
// CustomItemData's lifetime must exceed that of the CComboBoxEx; don't use a
// stack-based (automatic) variable.
CustomItemData* pcid = new CustomItemData( myName, myInteger );
CCOMBOBOXEXITEM cbei = { 0 };
cbei.mask = CBEIF_TEXT | CBEIF_LPARAM;
cbei.iItem = currentIndex; // The zero-based index of the item.
cbei.pszText = LPSTR_TEXTCALLBACK; // The control will request the information by using
// the CBEN_GETDISPINFO notification codes.
cbei.lParam = reinterpret_cast<LPARAM>( pcid ); // Assign custom data to item.
myComboBox.InsertItem( &cbei );
At this point, the ComboBox control is populated with items, and will request the display information from the application. The CBEN_GETDISPINFO is sent to the control parent, so the notification handler must be placed into the parent's window (usually a dialog) implementation. The handler is connected to the notification message using the ON_NOTIFY macro:
// Inside the parent's message map:
ON_NOTIFY( CBEN_GETDISPINFO, IDC_MY_COMBOBOX, GetCBDispString )
// Message handler inside the parent's class
void CMyDlg::GetCBDispString( NMHDR* pNMHDR, LRESULT* pResult ) {
NMCOMBOBOXEX* pncbe = reinterpret_cast<NMCOMBOBOXEX*>( pNMHDR );
COMBOBOXEXITEM& cbei = pncbe->ceItem;
if ( cbei.mask & CBEIF_TEXT ) {
// Text is requested -> fill the appropriate buffer.
const CustomItemData& cd = *reinterpret_cast<const CustomItemData*>( cbei.lParam );
wcscpy( cbei.pszText, cd.m_Name );
// Prevent future callbacks for this item. This is an optional optimization
// and can be used, if the m_Name member doesn't change.
cbei |= CBEIF_DI_SETITEM;
}
// Mark notification as handled
*pResult = 0;
}
Occasionally it is desired to put the
CBEN_GETDISPINFO
callback inside the custom ComboBox implementation. MFC provides the necessary infrastructure to implement message reflection (see
TN062: Message Reflection for Windows Controls). This allows a parent window to reflect notification messages back to the respective child control for handling. It can be useful at times, but is not required to implement a solution to this question.
If you do not need full control over constructing display strings at runtime, you can go with a simple
CComboBox
control, and attach additional information calling
CComboBox::SetItemData or
CComboBox::SetItemDataPtr, as illustrated in
πάντα ῥεῖ's answer.