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

C++ Win32菜单栏绘制覆盖自绘菜单项问题如何解决

问题核心原因

你的代码存在3个直接导致该现象的错误,其中最核心的是错误释放了系统提供的绘制DC:

  1. DrawMenuItem 中手动调用 ReleaseDC 释放了系统传入的绘制上下文,导致后续菜单项绘制时DC失效,绘制操作直接被系统忽略,仅第一个菜单项能完成绘制,其余区域被菜单栏背景覆盖
  2. AppendMenu 传参不符合自绘菜单的规则,导致自绘项绑定的自定义数据可能异常
  3. GDI对象使用未遵循上下文恢复规范,可能导致DC状态污染

修复步骤

1. 移除错误的DC释放调用

直接删掉 DrawMenuItem 中最后一行 ReleaseDC(MainWindow, hDC);,DRAWITEMSTRUCT 传入的hDC由系统负责生命周期管理,禁止手动释放。

2. 修正自绘菜单的初始化参数

顶层自绘菜单项如果是弹出菜单入口,需要加上MF_POPUP标志,同时确保传入的字符串生命周期足够,不会被提前释放:

HMENU Bar = CreateMenu();
HMENU File = CreateMenu();
HMENU Edit = CreateMenu();
// 定义静态字符串保证生命周期与程序一致
static const WCHAR szFileMenu[] = L"File";
static const WCHAR szEditMenu[] = L"Edit";
AppendMenu(Bar, MF_OWNERDRAW | MF_POPUP, (UINT_PTR)File, (LPCWSTR)szFileMenu);
AppendMenu(Bar, MF_OWNERDRAW | MF_POPUP, (UINT_PTR)Edit, (LPCWSTR)szEditMenu);

MENUINFO Info;
Info.cbSize = sizeof(Info);
Info.fMask = MIM_BACKGROUND;
Info.hbrBack = (HBRUSH)CreateSolidBrush(RGB(100, 100, 100));
SetMenuInfo(Bar, &Info);
SetMenu(MainWindow, Bar);

3. 修正GDI对象使用规范

绘制完成后恢复DC的原有状态,避免GDI资源泄漏和状态污染:

VOID DrawMenuItem(LPDRAWITEMSTRUCT ItemStruct)
{
    HDC hDC = ItemStruct->hDC;

    // 保存DC原有状态
    HPEN hOldPen = (HPEN)SelectObject(hDC, GetStockObject(DC_PEN));
    HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, GetStockObject(DC_BRUSH));
    int oldBkMode = SetBkMode(hDC, TRANSPARENT);
    COLORREF oldTextColor = GetTextColor(hDC);

    if (ItemStruct->itemState & ODS_HOTLIGHT)
    {
        SetDCPenColor(hDC, RGB(20, 20, 20));
        SetDCBrushColor(hDC, RGB(20, 20, 20));
        SetTextColor(hDC, RGB(255, 255, 255));
    }
    else
    {
        SetDCPenColor(hDC, RGB(70, 70, 70));
        SetDCBrushColor(hDC, RGB(70, 70, 70));
        SetTextColor(hDC, RGB(255, 255, 255));
    }
    Rectangle(hDC, ItemStruct->rcItem.left, ItemStruct->rcItem.top, ItemStruct->rcItem.right, ItemStruct->rcItem.bottom);
    DrawText(hDC, (LPCWSTR)ItemStruct->itemData, -1, &ItemStruct->rcItem, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

    // 恢复DC原有状态
    SelectObject(hDC, hOldPen);
    SelectObject(hDC, hOldBrush);
    SetBkMode(hDC, oldBkMode);
    SetTextColor(hDC, oldTextColor);

    return;
}

可选优化

可以将 MeasureMenuItem 中的 itemHeight 调整为20左右,避免文字因为高度不足被截断。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 02:45:03