如何正确使用SetMenuItemBitmaps替换菜单项的默认位图?
问题排查与解决方法
- 首先你调用
GetMenu(hWnd)的时机有误:WM_CREATE触发时窗口的菜单还未完成挂载,此时GetMenu会返回NULL,函数调用自然不生效。你可以把SetMenuItemBitmaps的调用逻辑移到WM_INITMENUPOPUP消息中,或者在调用CreateWindow创建窗口、SetMenu挂载菜单之后主动调用一次。 - 其次要确认
LoadBitmap的返回值是否合法:你可以增加判断逻辑,如果返回的HBITMAP为NULL,说明资源加载失败,大概率是bmp资源的ID或路径配置错误。另外注意LoadBitmap加载的位图需要调用DeleteObject手动释放,避免出现资源泄漏。 - 还要注意高DPI适配问题:
SM_CXMENUCHECK和SM_CYMENUCHECK返回的是当前DPI下的尺寸,如果你在高DPI环境下开发,固定尺寸的bmp可能会出现缩放模糊,建议优先使用LoadIcon或者把矢量图标转换为对应尺寸的位图再传入。 - 另外
SetMenuItemBitmaps仅会替换菜单项的勾选状态图标,如果你的菜单项没有设置MFT_CHECKBOX属性,或者默认是普通文本菜单项,图标不会正常显示。如果要给普通菜单项加自定义图标,建议改用SetMenuItemInfo,设置MIIM_BITMAP属性来实现。
修正后的代码参考:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static HBITMAP hRedBmp = NULL; switch (message) { case WM_CREATE: // 提前加载位图 hRedBmp = LoadBitmap(hInst, L"red.bmp"); // 可选:触发菜单重绘 DrawMenuBar(hWnd); return 0; case WM_INITMENUPOPUP: if (hRedBmp != NULL) { SetMenuItemBitmaps((HMENU)wParam, ID_RED, MF_BYCOMMAND, hRedBmp, hRedBmp); } return 0; case WM_DESTROY: // 销毁窗口时释放位图资源 if (hRedBmp != NULL) { DeleteObject(hRedBmp); } PostQuitMessage(0); return 0; } [...] }
内容的提问来源于stack exchange,提问作者TomPeterson
相关产品推荐
相关产品推荐

