C++ 重载EditBox默认ContextMenu

问题背景

      在做windows下的C++客户端程序开发的时候,经常会遇到自定义右键菜单的功能点的开发。
      这时候,我们一般只需要在窗口的事件过程中处理WM_CONTEXTMENU消息。处理时,根据需要可以使用CreatePopupMenu创建弹出菜单,并插入指定的子菜单项,最后处理对应菜单项的消息这样的流程来实现一个自定义的右键菜单列表。也可以通过拿到菜单项的句柄,枚举并修改菜单列表的形式重载一些已经实现的或者已经定义的菜单列表。
      之前遇到一个需求,需要继承Edit默认的右键菜单,在此基础上添加一些自定义的右键菜单项。然而,按照之前的理解,写代码的过程中发现,WM_CONTEXTMENU消息触发的时候,不能获取到默认的右键菜单句柄信息,也就拿不到右键菜单中的菜单列表条目。因此也不能继续进行右键菜单项的自定义操作。下面用代码演示一下,一般自定义右键菜单的方法和在editbox中实现重载默认Context的方法。

自定义右键菜单

在这里用代码表示一般的右键菜单创建和处理的过程:

//编辑框事件处理
#define EDIT_NEW_MENU_ITEM WM_USER + 800
static LRESULT CALLBACK WndProcForEditCtrl(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        case WM_CONTEXTMENU: {
            //创建菜单项列表
             HMENU popup = CreatePopupMenu();
             WCHAR temp[50] = {0};
             wcscpy(temp, L"自定义菜单");
             AppendMenu(popup, MF_STRING, (UINT_PTR)EDIT_NEW_MENU_ITEM, tmp);
             POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
             TrackPopupMenu(popup, TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, pt.x,
             pt.y, 0,hwnd, nullptr);
            return true;
        }
        break;
        case EDIT_NEW_MENU_ITEM:{
        //根据具体的需求处理消息
        }
        break;
        default:
            break;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

重载系统默认右键菜单

//获取列表中pos处的菜单项
MENUITEMINFO GetMenuInfoByPosition(HMENU menu, UINT nPos) {
    TCHAR szMenuStr[256] = {0};
    MENUITEMINFO mInfo = {0};

    mInfo.cbSize = sizeof(mInfo);
    mInfo.fMask = 0 |MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU| MIIM_TYPE| 0;
    mInfo.dwTypeData = szMenuStr;
    mInfo.cch = _countof(szMenuStr);

    GetMenuItemInfo(menu, nPos, TRUE, &mInfo);
    return mInfo;
}

#define EDIT_NEW_MENU_ITEM WM_USER + 800
static bool isInitMenu = true;
static LRESULT CALLBACK WndProcForEditCtrl(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
        case WM_CONTEXTMENU: {
            isInitMenu = true;
        } break;
        case WM_ENTERIDLE: {
            if (wParam == MSGF_MENU) {//表示为菜单消息,当wParam为MSGF_DIALOGBOX表示的是对话框消息
                //这里表示菜单进入空闲状态
                if (isInitMenu) {
                    isInitMenu = false;
                    MENUBARINFO mbi;
                    memset(&mbi, 0, sizeof(MENUBARINFO));
                    mbi.cbSize = sizeof(MENUBARINFO);
                    GetMenuBarInfo((HWND)lParam, OBJID_CLIENT, 0, &mbi);
                    if (::IsMenu((HMENU)mbi.hMenu)) {
                        for (int i = 0; i < GetMenuItemCount(mbi.hMenu) - 1; i++) {
                            MENUITEMINFO menuInfo = GetMenuInfoByPosition(mbi.hMenu, i);
                            auto aa = menuInfo.dwTypeData;
                            if (str::Len(menuInfo.dwTypeData)) {
                                WCHAR menuName[50] = {0};
                                wcscpy(menuName, menuInfo.dwTypeData);
                                win::menu::SetText(mbi.hMenu, menuInfo.wID, menuName);
                            }
                        }
                        WCHAR menuStr[50] = {0};
                        wcscpy(menuStr, L"自定义菜单");
                        AppendMenu(mbi.hMenu, MF_STRING, (UINT_PTR)9000, menuStr);
                    }
                }
            }
        } break;
        default:
            break;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

参考资料

https://stackoverrun.com/cn/q...
https://docs.microsoft.com/en...

重要说明

==欢欢迎大家关注我的个人微信公众号,一起探讨和学习C++后端、客户端的开发知识!==
在这里插入图片描述

你可能感兴趣的:(C++ 重载EditBox默认ContextMenu)