自定义右键菜单实现指南

在Windows应用程序开发中,实现一个自定义的右键菜单是一个常见的需求。然而,标准的Win32 API或WTL(Windows Template Library)并没有直接提供现成的解决方案来创建一个完全自定义的右键菜单。本文将介绍如何使用一个名为CCoolContextMenu的类来实现这一功能。

实现自定义菜单

为了创建一个自定义的菜单项,需要设置菜单项的MFT_OWNERDRAW标志。这可以通过InsertMenuItem或SetMenuItemInfo函数来实现。这两个函数都需要一个指向MENUITEMINFO结构的指针,该结构定义了菜单项的属性。

要将一个菜单项设置为自定义绘制(owner-drawn),需要在MENUITEMINFO结构的fType成员中指定MFT_OWNERDRAW值。此外,还可以为每个菜单项关联一个应用程序定义的值,称为项数据。CCoolContextMenu类定义了一个MenuItemData结构,其中包含了用于绘制菜单项的信息。应用程序使用dwItemData成员来存储指向此结构的指针。

MenuItemData结构会随着WM_MEASUREITEM和WM_DRAWITEM消息一起发送给菜单的所有者窗口。GetMenuItemInfo函数用于在任何时候检索菜单项的数据。

以下是初始化菜单弹出处理的代码示例:

LRESULT InitMenuPopupHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if ((BOOL)HIWORD(lParam)) { bHandled = FALSE; return 1; } CMenuHandle menuPopup = (HMENU)wParam; ATLASSERT(menuPopup.m_hMenu != NULL); TCHAR szString[MAX_MENU_ITEM_TEXT_LENGTH]; BOOL bRet = FALSE; for (int i = 0; i < menuPopup.GetMenuItemCount(); i++) { CMenuItemInfo mii; mii.cch = MAX_MENU_ITEM_TEXT_LENGTH; mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; mii.dwTypeData = szString; bRet = menuPopup.GetMenuItemInfo(i, TRUE, &mii); ATLASSERT(bRet); if (!(mii.fType & MFT_OWNERDRAW)) { MenuItemData *pMI = new MenuItemData; ATLASSERT(pMI != NULL); if (pMI) { mii.fType |= MFT_OWNERDRAW; pMI->fType = mii.fType; pMI->fState = mii.fState; static_cast(this)->AssociateImage(mii, pMI); pMI->lpstrText = new TCHAR[lstrlen(szString) + 1]; ATLASSERT(pMI->lpstrText != NULL); if (pMI->lpstrText != NULL) lstrcpy(pMI->lpstrText, szString); mii.dwItemData = (ULONG_PTR)pMI; bRet = menuPopup.SetMenuItemInfo(i, TRUE, &mii); ATLASSERT(bRet); } } } m_stackMenuHandle.Push(menuPopup.m_hMenu); return 0; }

CCoolContextMenu类的内部实现

CCoolContextMenu类内部实现了WM_MEASUREITEM、WM_DRAWITEM、WM_INITMENUPOPUP和WM_MENUSELECT消息,所以不需要担心这些消息的处理。

如何使用CCoolContextMenu类

要使用CCoolContextMenu类,只需要从CCoolContextMenu派生类,并按照以下步骤操作:

class CCoolEdit : public CWindowImpl, public CRichEditCommands, public CCoolContextMenu { public: // ... }; BEGIN_MSG_MAP(CCoolEdit) // ... CHAIN_MSG_MAP(CCoolContextMenu) END_MSG_MAP() LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // ... GetSystemSettings(); // ... }

关于图像,只需要创建图像列表并在CCoolContextMenu派生类中实现AssociateImage函数:

void AssociateImage(CMenuItemInfo& mii, MenuItemData *pMI) { switch (mii.wID) { case ID_EDIT_UNDO: pMI->iImage = 17; break; case ID_EDIT_CUT: pMI->iImage = 3; break; case ID_EDIT_COPY: pMI->iImage = 4; break; case ID_EDIT_PASTE: pMI->iImage = 5; break; case ID_EDIT_CLEAR: pMI->iImage = 20; break; default: pMI->iImage = -1; break; } }

CCoolContextMenu类允许通过几行代码就为应用程序添加美观的上下文菜单。通过结合Jean-Michel LE FOL的代码,窗口将看起来完全不同。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485