. Home Feedback Contents Search

ComboBox 

Back Up Next

ComboBox Tips, Tricks, Techniques and Samples

There are three types of standard combo boxes. The first and most simple is the somewhat redundantly name Simple Combo. The combo’s list is always expanded and the user is only able to select one of the list members, which is then displayed in the edit portion of the combo. The edit itself does not accept user input. The second is a variation on the Simple, the Drop List Combo. Like the Simple, the edit does not accept user input. The list appears upon user demand and the user may select one of the members from this list. The third is the Dropdown Combo. Like the Drop List, the combo’s list appears upon user invocation but, unlike either of the other two, the user may supply new values through the use of the combo’s edit.

Getting a String From a Drop List In A Dialog Box - The DDX for a Drop List ComboBox returns an index, not a string. Here's the fix.

Sort Warning - Searching for an item in a ComboBox can return unexpected results. Here's why.

Getting the edit window handle.

Sometimes you need to have the window handle of the edit box that is associated with a ComboBox. This is not something that is directly available from the ComboBox class itself but you can take advantage of the fact that the edit box is always going to reside in a known location within the rectangle defined by the ComboBox control. Once you have that, everything else just falls into place.

CComboCox combo;
CEdit edit;
// combobox creation ...
// ...
POINT tmpPoint = {1,1};
edit.SubclassWindow( combo.ChildWindowFromPoint(tmpPoint)->GetSafeHwnd() );

Getting a String From a Drop List In A Dialog Box.

The Drop List Combo’s support in MFC is somewhat less than optimal. When the user selects an item in a Drop List Combo, you would expect that the returned value would be a string. Sadly, this is not the case. Instead, the standard DDX routine extracts the index of the selected item rather than the string itself for return to the caller. This is not what we or any normal person would want but that’s what was built for our use. Fear not, for we are brave of heart, quick of wit and pure in purpose and can provide thee with the means of thy salvation. Failing that, here’s how to get the Droplist Combo box to return a real string.

 In the H file, declare the routine we are going to insert.

     void AFXAPI DDX_CBString(CDataExchange *pDX, int nIDC, CString& value);

 In the CPP file, implement the code to be executed.

// The standard CComboBox DDX_CBString macro has a bug in it that
// causes it to fail with combo boxes with the drop list style.
// Ergo, a need for a hack, err, ah, an elegant amendment to the normal process.

void AFXAPI CMyDlg::DDX_CBString(CDataExchange* pDX, int nIDC, CString& value)
     {
     HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
     if (pDX->m_bSaveAndValidate)
         {
         // Get current edit item text (or drop list static)
         int nLen = ::GetWindowTextLength(hWndCtrl);
         if (nLen != -1 && nLen != 0xFFFF)
             {
             // Get known length
             ::GetWindowText(hWndCtrl, value.GetBufferSetLength(nLen), nLen+1);
             }
         else
             {
             // GetWindowTextLength does not work for drop lists assume
             // max of 255 characters
             ::GetWindowText(hWndCtrl, value.GetBuffer(255), 255+1);
             }
         value.ReleaseBuffer();
         }
     else
         {
         // Set current selection based on model string
         if (::SendMessage(hWndCtrl, CB_SELECTSTRING, (WPARAM)-1,
             (LPARAM)(LPCTSTR)value) == CB_ERR)
             {
             // Set the edit text (will be ignored if DROPDOWNLIST)
             ::SetWindowText(hWndCtrl, value);
             }
         }
     }

There's one additional little thing to be considered. Now that the combo has been coerced into returning a string from the drop list, we are going to need to define a place for that string to go. This is going to have to be done manually because the Wizard is stuck in its own little world of drop lists return indexes. There are two approaches that you can do.

1 Go into the dialog template and change all of the drop lists to dropdown combos. Go into the Wizard and associated CStrings with the combos. Go back into the dialog editor and change the combos back to drop lists.

2 Manually add a CString with an appropriate name for each combo you want to support. In the H file, declare a CString variable with an appropriate name for each combo to be supported. In the CPP file, add a CBString macro to the AFX_DATA_MAP for each of the supported combos.

Sort Warning

The default behavior of a combo at drop list time is to search for the first item in the list that is equal to or greater than the value that is in the combo’s edit. If the list is unsorted then even if an exact match exists further down, the search will terminate early.

For example, let’s say you have an unsorted drop list with

“ZZZ”
“ZZ”
“ORDERS”
“ORDER”

and “ZZ” is in the edit. When the combo’s drop button is activated we see the selected row as “ZZZ”, not the expected “ZZ”.

 

Back to top

Subclassing the listbox portion of the combo.

Back Up Next