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

Owner-Drawn Menus绘制时如何区分子菜单项与菜单栏菜单项

自绘菜单区分顶层菜单栏项与子菜单项实现方案

可以明确区分两类菜单项,不同技术栈的实现方法如下:

示例示意图


1. Win32 API 实现

处理WM_DRAWITEM消息时,通过DRAWITEMSTRUCT结构体关联的菜单句柄判断父菜单是否存在即可:

  • 顶层菜单栏菜单项的父菜单句柄为NULL
  • 子菜单项的父菜单句柄为非NULL值

示例代码:

LRESULT OnDrawItem(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
    if (lpdis->CtlType != ODT_MENU) return DefWindowProc(hWnd, uMsg, wParam, lParam);
    
    HMENU hCurrentMenu = lpdis->hwndItem;
    if (GetParent(hCurrentMenu) == NULL) {
        // 绘制顶层菜单栏项:按需求实现居中、自适应宽度等样式
    } else {
        // 绘制子菜单项:设置文字左对齐、固定宽度
        RECT drawRect = lpdis->rcItem;
        drawRect.right = drawRect.left + 200; // 固定宽度200px
        DrawText(lpdis->hDC, (LPCSTR)lpdis->itemData, -1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
    }
    return TRUE;
}

2. MFC 实现

重写CMenu类的DrawItem和MeasureItem方法,通过GetParent()返回值判断菜单项类型:

  • GetParent()返回nullptr为顶层菜单栏项
  • GetParent()返回非nullptr为子菜单项,可在MeasureItem中直接指定固定宽度

示例代码:

void CCustomMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
    if (GetParent() != nullptr) {
        lpMeasureItemStruct->itemWidth = 200; // 子菜单项固定宽度
    } else {
        // 顶层项根据文字内容计算宽度
        CString text = GetMenuString(lpMeasureItemStruct->itemID);
        lpMeasureItemStruct->itemWidth = GetTextExtent(text).cx + 16;
    }
    lpMeasureItemStruct->itemHeight = 24;
}

void CCustomMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    CString itemText = GetMenuString(lpDrawItemStruct->itemID);
    if (GetParent() == nullptr) {
        // 绘制顶层菜单栏项
        DrawText(lpDrawItemStruct->hDC, itemText, &lpDrawItemStruct->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    } else {
        // 绘制子菜单项
        DrawText(lpDrawItemStruct->hDC, itemText, &lpDrawItemStruct->rcItem, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
    }
}

3. Qt 实现

可以通过两种方式实现:

  • 代码层面判断:自定义QMenu绘制逻辑时,若parentWidget()类型为QMenuBar则为顶层项,若为QMenu则为子项
  • QSS样式直接区分:无需写逻辑代码,直接通过选择器设置不同样式

QSS示例:

/* 顶层菜单栏项样式 */
QMenuBar::item {
    padding: 4px 12px;
    text-align: center;
}

/* 子菜单项样式 */
QMenu::item {
    width: 200px;
    text-align: left;
    padding: 4px 8px;
}

注意事项

  • 子菜单项固定宽度需要大于所有子项文字+图标+快捷键的总宽度,避免内容被截断
  • Win32/MFC环境下如果需要显示快捷键,记得在子项宽度中预留右侧快捷键的绘制区域

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 23:45:04