65.9K
CodeProject 正在变化。 阅读更多。
Home

WTL 中的所有者绘制上下文菜单

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.71/5 (21投票s)

2006 年 3 月 13 日

CPOL

3分钟阅读

viewsIcon

139501

downloadIcon

2082

一篇解释如何创建 owner-drawn 上下文菜单的文章。

WTL Context Menu

引言

我一直在寻找在 WTL 中实现 owner-drawn 上下文菜单的代码,但找不到任何代码;我找到的所有代码都会修改 CCommandBarCtrl 的行为,并且不能用于例如由编辑控件显示的上下文菜单。

在本文中,我将向您展示如何实现 owner-drawn 上下文菜单,以及如何使用我的类 CCoolContextMenu 轻松地为您的应用程序添加美观的菜单。

实现

为了使一个项目成为 owner-drawn 项目,您必须创建一个新的菜单项,或通过设置 MFT_OWNERDRAW 菜单标志来修改现有的菜单项。

您可以使用 InsertMenuItemSetMenuItemInfo 函数来设置或更改有关菜单项的信息。在调用这两个函数时,您必须指定一个指向 MENUITEMINFO 结构的指针,该结构指定了菜单项的属性。

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

MenuItemData 结构通过 WM_MEASUREITEMWM_DRAWITEM 消息发送到菜单的所有者窗口。GetMenuItemInfo 函数用于随时检索菜单的项目数据。

LRESULT InitMenuPopupHandler(UINT uMsg, WPARAM wParam, 
                             LPARAM lParam, BOOL& bHandled)
{
    // System menu, do nothing

    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))
        // not already an ownerdraw item

        {
            MenuItemData * pMI = new MenuItemData;
            ATLASSERT(pMI != NULL);

            if (pMI)
            {
                // Make this menu item an owner-drawn

                mii.fType |= MFT_OWNERDRAW;

                pMI->fType = mii.fType;
                pMI->fState = mii.fState;

                // Associate an image with a menu item

                static_cast<T*>(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);
            }
        }
    }

    // Add it to the list

    m_stackMenuHandle.Push(menuPopup.m_hMenu);
    
    return 0;
}

在内部,CCoolContextMenu 实现了 WM_MEASUREITEMWM_DRAWITEMWM_INITMENUPOPUPWM_MENUSELECT 消息,因此您不必担心任何事情。

使用代码

要使用 CCoolContextMenu 类,您所要做的就是从 CCoolContextMenu 派生您的类,并按照接下来的几个步骤操作

class CCoolEdit : public CWindowImpl<CCoolEdit, CRichEditCtrl>,
                  public CRichEditCommands<CCoolEdit>,
                  public CCoolContextMenu<CCoolEdit>

在消息映射中,使用 CHAIN_MSG_MAP 将消息重定向到 CCoolContextMenu 的消息映射

BEGIN_MSG_MAP(CCoolEdit)
    ...
    CHAIN_MSG_MAP(CCoolContextMenu<CCoolEdit>)
END_MSG_MAP()

在您的对话框类的 OnInitDialog() 函数中,或在窗口类的 OnCreate() 函数中,调用 CCoolContextMenuGetSystemSettings() 方法

LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, 
                     LPARAM lParam, BOOL& bHandled)
{
    ...
    GetSystemSettings();
    ...
}

但是等等!图片呢?别担心,只需创建图像列表并在您的 CCoolContextMenu 派生类中实现 AssociateImage(CMenuItemInfo& mii, MenuItemData * pMI) 函数

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 的代码相结合,您的窗口将看起来完全不同。

感谢

历史

  • 2006 年 3 月 13 日 - 初始发布。
  • 2006 年 3 月 15 日 - 在 CCoolContextMenu 类中放入一个消息映射。感谢 Jörgen Sigvardsson 建议它。
  • 2006 年 4 月 24 日 - 为 CCoolContextMenu 类添加了 AssociateImage 函数的默认实现。

免责声明

本软件及其附带的文件按“原样”分发,不提供任何形式的保证,无论是明示的还是暗示的。对于可能造成的任何损害,概不负责。用户必须承担使用本软件的全部风险。

© . All rights reserved.