一般来说,创建并使用快捷菜单,可以按照以下步骤进行:
1、用资源编辑器创建菜单。
2、当我们在窗口上按下鼠标右键,当系统处理WM_RBUTTONUP时会向我们的应用程序发送一条WM_CONTEXTMENU消息,我们通过响应这条消息来决定是否弹出菜单。
3、计算菜单弹出的位置,一般在我们鼠标指针的右下方,该坐标是基于屏幕的,不是窗口的。
4、调用TrackPopupMenu函数显示快捷菜单。
5、因为这种菜单是不属于某个窗口的,它的内存资源不会在窗口销毁时被回收,因此,在TrackPopupMenu返回后要调用DestroyMenu来销毁菜单的资源,释放内存。
接下来就是捕捉WM_CONTEXTMENU消息。显示菜单。
case WM_CONTEXTMENU:
{
RECT rect;
POINT pt;
// 获取鼠标右击是的坐标
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
//获取客户区域大小
GetClientRect((HWND)wParam, &rect);
//把屏幕坐标转为客户区坐标
ScreenToClient((HWND)wParam, &pt);
//判断点是否位于客户区域内
if (PtInRect(&rect, pt))
{
//加载菜单资源
HMENU hroot = LoadMenu((HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), MAKEINTRESOURCE(IDR_CONTEXT));
if (hroot)
{
// 获取第一个弹出菜单
HMENU hpop = GetSubMenu(hroot, 0);
// 把客户区坐标还原为屏幕坐标
ClientToScreen((HWND)wParam, &pt);
//显示快捷菜单
TrackPopupMenu(hpop,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
pt.x,
pt.y,
0,
(HWND)wParam,
NULL);
// 用完后要销毁菜单资源
DestroyMenu(hroot);
}
}
}
点击做出反应效果
case 32781:
MessageBox(hWnd, L"哈哈。", L"提示", MB_OK);
break;
case 32782:
MessageBox(hWnd, L"呵呵。", L"提示", MB_OK);
break;
case 32783:
MessageBox(hWnd, L"嘎嘎。", L"提示", MB_OK);
break;
}
定义
#define ID_haha 32781
#define ID_hehe 32782
#define ID_gaga 32783
根据MSDN文档的说明,WM_CONTEXTMENU消息的wParam参数指的是弹出菜单的窗口的句柄,lParam参数的低字位是鼠标指针的水平坐标,高字位指的是垂直坐标。
但我们不用自己去转换,我们通过GET_X_LPARAM和GET_Y_LPARAM两个宏可以把lParam中的值转为坐标值,类型为int,要使用这两个宏,需要包含WindowsX.h头文件。接着调用TrackPopupMenu来显示菜单,最后销毁菜单。
现在在窗口的标题栏上右击,快捷菜单不会再出现了,但是,同时,系统菜单也没有出现。因为系统菜单是由系统来处理的,所以,解决这问题很简单,只要我们把WM_CONTEXT消息发回给系统来处理就行了。
方法一:我们判断了如果右击点在窗口的客户区域时显示菜单,那么,如果不在这个区域内,就把消息再传回给系统处理。
else
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
方法二:在WindowsProc函数的最后,统一把所有消息都返回给操作系统处理。
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return DefWindowProc(hWnd, message, wParam, lParam);