Reputation: 1279
I created a custom CCustomCombo by extending CComboBox to implement a DrawItem() function. Here's the code for it.
void CCustomCombo::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
ASSERT( lpDrawItemStruct->CtlType == ODT_COMBOBOX );
LPCTSTR lpszText = ( LPCTSTR ) lpDrawItemStruct->itemData;
ASSERT( lpszText != NULL );
if ( lpDrawItemStruct->itemID == -1 || lpszText == NULL)
return;
CDC dc;
dc.Attach( lpDrawItemStruct->hDC );
// Save these value to restore them when done drawing.
COLORREF crOldTextColor = dc.GetTextColor();
COLORREF crOldBkColor = dc.GetBkColor();
// If this item is selected, set the background color
// and the text color to appropriate values. Erase
// the rect by filling it with the background color.
if ( ( lpDrawItemStruct->itemAction & ODA_SELECT ) &&
( lpDrawItemStruct->itemState & ODS_SELECTED ) )
{
dc.SetTextColor( ::GetSysColor( COLOR_HIGHLIGHTTEXT ) );
dc.SetBkColor( ::GetSysColor( COLOR_HIGHLIGHT ) );
dc.FillSolidRect( &lpDrawItemStruct->rcItem, ::GetSysColor( COLOR_HIGHLIGHT ) );
}
else
{
dc.FillSolidRect( &lpDrawItemStruct->rcItem, crOldBkColor );
}
// Draw the text.
dc.DrawText(
lpszText,
( int ) _tcslen( lpszText ),
&lpDrawItemStruct->rcItem,
DT_CENTER | DT_SINGLELINE | DT_VCENTER );
// Reset the background color and the text color back to their
// original values.
dc.SetTextColor( crOldTextColor );
dc.SetBkColor( crOldBkColor );
dc.Detach();
}
creation part -
m_selectionCombo.Create( WS_VSCROLL |
CBS_DROPDOWNLIST | WS_VISIBLE | WS_TABSTOP| CBS_OWNERDRAWFIXED,
rect, &m_wndSelectionBar, ID_TEMP_BTN))
Now the problem is with the adding string items to the combobox. When I'm using string objects, it always shows some unicode gibberish.
m_selectionCombo.InsertString(0, "One"); //works
char * one = "one";
m_selectionCombo.InsertString(0, one ); //works
CString one = "one";
m_selectionCombo.InsertString(0, one ); //shows gibberish
std::string one = "one";
char *cstr = &one[0];
m_wndSelectionBar.m_selectionCombo.InsertString(0, cstr ); //shows gibberish
The same results appear for AddString. The problem is that I have a set of doubles that I have to insert to the combobox. And I have no way of converting them to string without displaying gibberish. I tried half-a-dozen conversion methods and none worked. I'm literally at my wits end!
The funny thing is it worked perfectly before when I used CComboBox and not my CCustomCombo class/CBS_OWNERDRAWFIXED. I tried using CBS_HASSTRINGS, but it displayed nothing, not even the gibberish, so somehow the strings don't even get added in with CBS_HASSTRINGS.
I need the custom Draw method since I plan to highlight some of the dropdown items. I'm using windows 32, VS 2017.
Any help would be highly appreciated. Thanks.
Upvotes: 2
Views: 390
Reputation: 31669
LPCTSTR lpszText = (LPCTSTR)lpDrawItemStruct->itemData;
OwnerDraw function is looking at itemData
. itemData
is assigned using CComboBox::SetItemData
. It is not assigned using InsertString
or other text functions.
char * one = "one"; m_selectionCombo.InsertString(0, one ); //works
The string and item data are stored in the same memory address when CBS_HASSTRINGS
is not set.
See also documentation for CB_SETITEMDATA
If the specified item is in an owner-drawn combo box created without the CBS_HASSTRINGS style, this message replaces the value in the lParam parameter of the CB_ADDSTRING or CB_INSERTSTRING message that added the item to the combo box.
So basically itemData
returns a pointer one
, and it works fine in this case.
CString one = "one"; m_selectionCombo.InsertString(0, one ); //shows gibberish
This time the string is created on stack, it is destroyed after the function exists. itemData
points to invalid address.
If you are setting the text using InsertString/AddString
then make sure CBS_HASSTRINGS
is set. And read the strings using GetLBText
. Example:
//LPCTSTR lpszText = (LPCTSTR)lpDrawItemStruct->itemData; <- remove this
if(lpDrawItemStruct->itemID >= GetCount())
return;
CString str;
GetLBText(lpDrawItemStruct->itemID, str);
LPCTSTR lpszText = str;
Otherwise use SetItemData
to setup data, and use itemData
to read.
Upvotes: 3