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

CButton派生类中先调用基类DrawItem再自定义绘制的问题

问题原因及解决方法
  • 问题根源:CButton类的DrawItem成员函数,当按钮带有BS_OWNERDRAW样式时,基类实现本身不会执行标准绘制逻辑——因为OWNERDRAW模式下,系统默认将绘制控制权完全交给子类。你在DrawItem内部临时修改样式的操作,无法改变基类DrawItem的执行逻辑(函数调用时的状态已确定),而且ModifyStyle还可能触发窗口消息干扰当前绘制流程。

  • 正确实现方式:直接调用系统API绘制标准按钮外观,再叠加自定义内容,无需修改按钮样式。示例代码如下:

void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    // 1. 绘制标准按钮外观
    UINT uStyle = DFCS_BUTTONPUSH;
    if ((lpDrawItemStruct->itemState & ODS_SELECTED) != 0)
        uStyle |= DFCS_PUSHED;
    if ((lpDrawItemStruct->itemState & ODS_DISABLED) != 0)
        uStyle |= DFCS_INACTIVE;

    // 绘制按钮边框和背景
    ::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, DFC_BUTTON, uStyle);

    // 绘制按钮文本(保留标准文本逻辑)
    CString strText;
    GetWindowText(strText);
    if (!strText.IsEmpty())
    {
        UINT uFormat = DT_CENTER | DT_VCENTER | DT_SINGLELINE;
        if ((lpDrawItemStruct->itemState & ODS_DISABLED) != 0)
            uFormat |= DT_GRAYTEXT;

        // 调整文本区域,避开按钮边框
        RECT rcText = lpDrawItemStruct->rcItem;
        ::InflateRect(&rcText, -4, -4);
        ::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(), &rcText, uFormat);
    }

    // 2. 绘制自定义内容,示例:按钮右上角添加红色小标记
    RECT rcCustom = {
        lpDrawItemStruct->rcItem.right - 10,
        lpDrawItemStruct->rcItem.top + 5,
        lpDrawItemStruct->rcItem.right - 5,
        lpDrawItemStruct->rcItem.top + 10
    };
    ::FillRect(lpDrawItemStruct->hDC, &rcCustom, (HBRUSH)::GetStockObject(RED_BRUSH));
}
  • 补充说明:如果想最大化复用CButton的内部逻辑,也可以通过获取按钮状态后,调用系统消息让原生控件完成绘制,但上述DrawFrameControl的方式更直接可控,且避免了样式修改带来的潜在问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 08:43:38