用代码添加
这种方法的思路是:首先在全局范围内定义一个HMENU的变量,用来保存窗口中菜单栏的句柄,根菜单(菜单栏)可以CreateMenu函数来创建,接着可以使用AppendMenu函数或者InsertMenuItem函数来创建菜单项。
HMENU hRoot;//定义菜单的全局变量
void CreateMyMenu();//声明创建菜单的函数
//函数的实现
//创建菜单
void CreateMyMenu()
{
hRoot = CreateMenu();//根菜单用此函数创建菜单
if(!hRoot)
return;
HMENU pop1 = CreatePopupMenu();//竖立的弹出菜单,通常作为另一个菜单的子菜单或右键菜单的顶级菜单
AppendMenu(hRoot,MF_POPUP,(UINT_PTR)pop1,TEXT("操作"));//将子菜单添加到根菜单中
// 一种方法是使用AppendMenu函数
HMENU pop1_1 = CreatePopupMenu();
AppendMenu(pop1,MF_STRING,(UINT_PTR)pop1_1,TEXT("飞机"));
// 另一种方法是使用InsertMenuItem函数
HMENU pop1_2 = CreatePopupMenu();
MENUITEMINFO mif;
mif.cbSize = sizeof(MENUITEMINFO);
mif.cch = 100;
mif.dwItemData = NULL;
mif.dwTypeData = TEXT("机关枪");
mif.fMask = MIIM_ID | MIIM_STRING | MIIM_STATE;
mif.fState = MFS_ENABLED;
mif.fType = MIIM_STRING;
mif.wID = (UINT_PTR)pop1_2;
InsertMenuItem(pop1,(UINT_PTR)pop1_2,FALSE,&mif);
}
在主函数中,创建窗口前先调用函数,然后在创建窗口时改变倒数第三个参数为菜单全局变量
//创建菜单
CreateMyMenu();
//3、 创建窗口
HWND WINAPI hwnd = CreateWindow(wc.lpszClassName,TEXT("WINDOWS"),WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,hRoot,hINstance,NULL);
通过资源添加
在资源中编辑菜单,主要是显示的内容和ID,命名为IDM_XXX
在主函数中修改两个地方
//级别类在设计窗口时添加,不需要在CreateWindow时指定参数也能显示菜单
wc.lpszMenuName = (CHAR *)IDR_MENU1;//菜单名称
//3、 创建窗口
//窗口类,在再创建窗口时指定菜单,此时必须指定参数
HWND WINAPI hwnd = CreateWindow(wc.lpszClassName,TEXT("WINDOWS"),WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,LoadMenu(hINstance,MAKEINTRESOURCE(IDR_MENU1 )),hINstance,NULL);
菜单响应
当用户单击某个菜单项后,窗口处理程序(WindowProc)会收到一条WM_COMMAND消息,它的两个附加参数:wParam(选中的菜单项)IParam(窗口句柄)
在WindowProc中
case WM_COMMAND:
{
switch(LOWORD(wparam))
{
case IDM_OPEN:
{
MessageBox(hwnd,TEXT("按下打开菜单"),TEXT("菜单"),MB_OK);
break;
}
case IDM_CLOSE:
{
MessageBox(hwnd,TEXT("按下关闭菜单"),TEXT("菜单"),MB_OK);
break;
}
case IDM_FIND:
{
MessageBox(hwnd,TEXT("按下查找菜单"),TEXT("菜单"),MB_OK);
break;
}
case IDM_REPALCE:
{
MessageBox(hwnd,TEXT("按下替换菜单"),TEXT("菜单"),MB_OK);
break;
}
}
break;
}
单选菜单
1.菜单ID必须连续
2.在窗口过程函数中定义变量用来获取有单选范围的子菜单
auto hmm = GetMenu(hwnd);//菜单
auto hfmn = GetSubMenu(hmm,2);//水果子菜单
在选中菜单的case中写CheckMenuRadioItem函来来Check菜单
case IDM_APPLE:
{
//菜单句柄,单选范围,选中项,最后一项固定用ID来标识
CheckMenuRadioItem(hfmn,IDM_APPLE,IDM_BANANA,IDM_APPLE,MF_BYCOMMAND);
MessageBox(hwnd,TEXT("你选择了苹果"),TEXT("提示"),MB_OK);
break;
}
case IDM_PEAR:
{
//菜单句柄,单选范围,选中项,最后一项固定用ID来标识
CheckMenuRadioItem(hfmn,IDM_APPLE,IDM_BANANA,IDM_PEAR,MF_BYCOMMAND);
MessageBox(hwnd,TEXT("你选择了梨"),TEXT("提示"),MB_OK);
break;
}
case IDM_BANANA:
{
//菜单句柄,单选范围,选中项,最后一项固定用ID来标识
CheckMenuRadioItem(hfmn,IDM_APPLE,IDM_BANANA,IDM_BANANA,MF_BYCOMMAND);
MessageBox(hwnd,TEXT("你选择了香蕉"),TEXT("提示"),MB_OK);
break;
}
创建右键菜单
- 用资源编辑器创建菜单
- 当我们在窗口上按下鼠标右键,WM_CONTEXTMENU消息,我们通过响应这条消息来决定是否弹出菜单。
case WM_CONTEXTMENU://右键
{
RECT rect;//矩形区
GetClientRect(hwnd,&rect);
//获取鼠标右键的坐标
POINT pt;//点
pt.x = LOWORD(lparam);
pt.y = HIWORD(lparam);
//把屏幕坐标转换为客户区坐标
ScreenToClient(hwnd, &pt);
if(PtInRect(&rect, pt))//点是否在矩形区
{
//加载菜单
auto rightmenu = LoadMenu((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), MAKEINTRESOURCE(IDR_MENU2));
if(rightmenu)
{
//获取弹出菜单
auto shirenmenu = GetSubMenu(rightmenu,0);
//把客户区坐标转换为屏幕坐标
ClientToScreen(hwnd, &pt);
//显示快捷菜单
TrackPopupMenu(shirenmenu,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON,
pt.x,
pt.y,
0,
hwnd,
NULL);
// 用完后要销毁菜单资源
DestroyMenu(shirenmenu);
}
}
break;
}
- 计算菜单弹出的位置,一般在我们鼠标指针的右下方,该坐标是基于屏幕的,不是窗口的。
- 调用TrackPopupMenu函数显示快捷菜单。
- 因为这种菜单是不属于某个窗口的,它的内存资源不会在窗口销毁时被回收,因此,在TrackPopupMenu返回后要调用DestroyMenu来销毁菜单的资源,释放内存。
- 在WM_COMMAND中响应菜单项