如何移除或修改MFC中自定义弹出菜单的边框
你当前重写的MeasureItem和DrawItem仅负责单个菜单项的内容绘制,弹出菜单外围的灰色边框属于菜单弹出窗口的非客户区样式和系统默认的菜单内边距,不属于菜单项本身的绘制范围,因此无法通过这两个函数修改。具体实现方案如下:
方案1:移除默认灰色边框
- 重写自定义
CMenu类的TrackPopupMenu方法,拿到菜单弹出窗口句柄后删除系统默认边框样式:
BOOL CNewMenu::TrackPopupMenu(UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect /*= NULL*/) { BOOL bRet = CMenu::TrackPopupMenu(nFlags | TPM_RETURNCMD, x, y, pWnd, lpRect); // 菜单窗口的系统固定类名为#32768 HWND hMenuWnd = ::FindWindow(L"#32768", NULL); if (hMenuWnd != NULL) { // 移除普通边框样式 LONG_PTR style = ::GetWindowLongPtr(hMenuWnd, GWL_STYLE); style &= ~(WS_BORDER | WS_THICKFRAME); ::SetWindowLongPtr(hMenuWnd, GWL_STYLE, style); // 移除扩展边框样式 LONG_PTR exStyle = ::GetWindowLongPtr(hMenuWnd, GWL_EXSTYLE); exStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE); ::SetWindowLongPtr(hMenuWnd, GWL_EXSTYLE, exStyle); // 生效样式修改 ::SetWindowPos(hMenuWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); } return bRet; }
- 修改菜单全局配置,删除系统预留的边框边距:
// 在CNewMenu构造函数中添加以下代码 MENUINFO mi = {0}; mi.cbSize = sizeof(MENUINFO); mi.fMask = MIM_STYLE | MIM_APPLYTOSUBMENUS; mi.dwStyle = MNS_NOCHECK; // 同时去掉复选框预留位置,可根据需求调整 SetMenuInfo(&mi);
方案2:自定义边框样式
如果需要修改为指定颜色/宽度的边框,可以子类化菜单弹出窗口自行绘制:
- 定义菜单窗口子类,处理非客户区计算和绘制消息:
// 调整非客户区大小,预留自定义边框的位置 LRESULT CCustomMenuWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) { // 示例:预留2像素的边框位置 lpncsp->rgrc[0].left += 2; lpncsp->rgrc[0].top += 2; lpncsp->rgrc[0].right -= 2; lpncsp->rgrc[0].bottom -= 2; return 0; } // 绘制自定义边框 LRESULT CCustomMenuWnd::OnNcPaint(HRGN hRgn) { CRect rcWindow; GetWindowRect(&rcWindow); rcWindow.OffsetRect(-rcWindow.TopLeft()); CDC* pDC = GetWindowDC(); // 示例:绘制红色边框 pDC->FillSolidRect(rcWindow, RGB(255,0,0)); ReleaseDC(pDC); return 0; }
- 在
TrackPopupMenu中拿到菜单窗口句柄后,调用SetWindowSubclass接口子类化窗口即可生效。
你原有的DrawItem代码可以补充选中、禁用状态的分支判断,交互效果会更完善。
内容的提问来源于stack exchange,提问作者amballip
相关产品推荐
相关产品推荐

