CCombobox 字符串插入给出乱码

CCombobox string insertion gives gibberish

我通过扩展 CComboBox 来实现 DrawItem() 函数来创建自定义 CCustomCombo。这是它的代码。

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();
}

创作部分 -

m_selectionCombo.Create( WS_VSCROLL |
        CBS_DROPDOWNLIST | WS_VISIBLE | WS_TABSTOP| CBS_OWNERDRAWFIXED,
        rect, &m_wndSelectionBar, ID_TEMP_BTN))

现在的问题是将字符串项添加到组合框。当我使用字符串对象时,它总是显示一些 unicode 乱码。

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

AddString 出现相同的结果。问题是我有一组必须插入组合框的双打。而且我无法在不显示乱码的情况下将它们转换为字符串。我尝试了六种转换方法,none 成功了。我真是无计可施了!

有趣的是,在我使用 CComboBox 而不是我的 CCustomCombo class/CBS_OWNERDRAWFIXED 之前,它工作得很好。我尝试使用 CBS_HASSTRINGS,但它没有显示任何内容,甚至没有显示乱码,所以不知怎的,字符串甚至没有被添加到 CBS_HASSTRINGS 中。

我需要自定义 Draw 方法,因为我打算突出显示某些下拉项。我正在使用 windows 32,VS 2017。

如有任何帮助,我们将不胜感激。 谢谢

LPCTSTR lpszText = (LPCTSTR)lpDrawItemStruct->itemData;

OwnerDraw 函数正在查看 itemDataitemData 使用 CComboBox::SetItemData 赋值。它不是使用 InsertString 或其他文本函数分配的。

char * one = "one"; 
m_selectionCombo.InsertString(0, one ); //works

不设置CBS_HASSTRINGS时,字符串和item数据存放在同一个内存地址。

另请参阅 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.

所以基本上 itemData returns 一个指针 one,在这种情况下它工作正常。

CString one = "one"; 
m_selectionCombo.InsertString(0, one ); //shows gibberish

这次是在栈上创建字符串,函数存在后销毁。 itemData 指向无效地址。


解决方案:

如果您使用 InsertString/AddString 设置文本,请确保已设置 CBS_HASSTRINGS。并使用 GetLBText 读取字符串。示例:

//LPCTSTR lpszText = (LPCTSTR)lpDrawItemStruct->itemData; <- remove this

if(lpDrawItemStruct->itemID >= GetCount())
    return;

CString str;
GetLBText(lpDrawItemStruct->itemID, str);
LPCTSTR lpszText = str;

否则使用SetItemData设置数据,使用itemData读取。