You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CBS_DROPDOWNLIST风格CComboBox自定义OnPaint后标准文本绘制问题求助

解决CComboBox自定义绘制时标准文本覆盖问题及选中项文本获取方法

问题根源分析

你遇到的标准文本覆盖自定义绘制内容的问题,核心原因是:

  • 未给组合框设置所有者绘制风格,系统在选择切换/滚轮操作时会触发默认文本绘制流程;
  • 若重写OnPaint时调用了基类CComboBox::OnPaint(),会强制触发系统默认绘制逻辑;
  • 未处理WM_DRAWITEM消息,无法完全接管所有场景下的绘制控制(包括选择变化后的显示区更新)。

解决步骤

1. 设置所有者绘制风格

确保你的CComboBoxX控件拥有CBS_OWNERDRAWFIXED(固定项高度)或CBS_OWNERDRAWVARIABLE(可变项高度)风格,同时保留CBS_DROPDOWNLIST:

  • 资源编辑器中:选中组合框,在「属性」→「所有者绘制」选择「固定」或「可变」;
  • 动态创建时:
m_comboX.Create(CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | WS_VISIBLE | WS_CHILD, 
                CRect(10,10,200,30), this, IDC_MY_COMBO);

2. 重写OnDrawItem完全接管绘制

这是所有者绘制控件的核心处理函数,覆盖所有场景(下拉列表项、选择后的显示区)的绘制:

void CComboBoxX::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
    CDC dc;
    dc.Attach(lpDIS->hDC);

    // 获取当前项文本
    CString strItemText;
    if (lpDIS->itemID != UINT(-1))
    {
        GetLBText(lpDIS->itemID, strItemText);
    }

    // 处理选中/非选中状态的背景与文本色
    if (lpDIS->itemState & ODS_SELECTED)
    {
        dc.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
        dc.SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
        dc.FillSolidRect(&lpDIS->rcItem, GetSysColor(COLOR_HIGHLIGHT));
    }
    else
    {
        dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
        dc.SetBkColor(GetSysColor(COLOR_WINDOW));
        dc.FillSolidRect(&lpDIS->rcItem, GetSysColor(COLOR_WINDOW));
    }

    // 绘制焦点框(可选)
    if (lpDIS->itemState & ODS_FOCUS)
    {
        dc.DrawFocusRect(&lpDIS->rcItem);
    }

    // 自定义绘制文本,可调整对齐方式
    dc.DrawText(strItemText, &lpDIS->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

    dc.Detach();
}

3. 按需重写OnMeasureItem(仅可变高度风格)

如果设置了CBS_OWNERDRAWVARIABLE,需要指定每个下拉项的高度:

void CComboBoxX::MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
{
    lpMIS->itemHeight = 22; // 自定义项高度
}

4. 修正OnPaint实现(可选,若仍需单独处理显示区)

如果保留OnPaint重写,必须去掉基类CComboBox::OnPaint()的调用,完全自行绘制显示区:

void CComboBoxX::OnPaint()
{
    CPaintDC dc(this);
    CRect rcClient, rcDropBtn;
    GetClientRect(rcClient);
    GetDroppedControlRect(rcDropBtn);

    // 绘制背景
    dc.FillSolidRect(rcClient, GetSysColor(COLOR_WINDOW));

    // 绘制下拉按钮
    dc.DrawFrameControl(rcDropBtn, DFC_SCROLL, DFCS_SCROLLCOMBOBOX);

    // 获取选中项文本并绘制
    CString strSelText;
    int nSel = GetCurSel();
    if (nSel != CB_ERR)
    {
        GetLBText(nSel, strSelText);
    }
    // 留出按钮空间,避免文本被遮挡
    rcClient.right = rcDropBtn.left - 2;
    dc.DrawText(strSelText, rcClient, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
}

5. 获取选中项文本的正确方式

无需复杂操作,直接通过GetCurSel()+GetLBText()即可获取:

CString GetSelectedText()
{
    CString strText;
    int nSelIndex = GetCurSel();
    if (nSelIndex != CB_ERR)
    {
        GetLBText(nSelIndex, strText);
    }
    return strText;
}

关键注意事项

  • 绝对不要在自定义绘制的OnPaint或OnDrawItem中调用基类的对应函数,否则会触发系统默认文本绘制;
  • 确保所有绘制逻辑都在OnDrawItem中完成,它是所有者绘制控件的标准入口,能覆盖所有交互场景的绘制需求。

内容的提问来源于stack exchange,提问作者natefoust

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:00:15