创建顶级菜单CreateMenu
创建菜单。 菜单最初为空,但可以使用 InsertMenuItem、 AppendMenu 和 InsertMenu 函数填充菜单项。
将新项追加到指定菜单栏的末尾、下拉菜单、子菜单或快捷菜单。 可以使用此函数指定菜单项的内容、外观和行为。
BOOL AppendMenuA(
[in] HMENU hMenu,
[in] UINT uFlags,
[in] UINT_PTR uIDNewItem,
[in, optional] LPCSTR lpNewItem
);
[in] uFlags
类型: UINT
控制新菜单项的外观和行为。 此参数可以是以下值的组合。
Value 含义
MF_BITMAP
0x00000004L
使用位图作为菜单项。 lpNewItem 参数包含位图的句柄。
MF_CHECKED
0x00000008L
在菜单项旁边放置复选标记。 如果应用程序提供复选标记位图 (请参阅 SetMenuItemBitmaps,此标志会显示菜单项旁边的复选标记位图。
MF_DISABLED
0x00000002L
禁用菜单项,使其无法选中,但标志不会灰显。
MF_ENABLED
0x00000000L
启用菜单项,以便可以选择菜单项,并从其灰色状态还原它。
MF_GRAYED
0x00000001L
禁用菜单项并将其灰显,以便无法选择它。
MF_MENUBARBREAK
0x00000020L
与菜单栏 的MF_MENUBREAK 标志相同。 对于下拉菜单、子菜单或快捷菜单,新列与旧列之间将用一条竖线分隔。
MF_MENUBREAK
0x00000040L
将项放在菜单栏的新行 () 或 (的下拉菜单、子菜单或快捷菜单) 中,而不分隔列。
MF_OWNERDRAW
0x00000100L
指定该项是所有者绘制的项。 首次显示菜单之前,拥有菜单的窗口会收到 WM_MEASUREITEM 消息以检索菜单项的宽度和高度。 然后 ,只要 必须更新菜单项的外观,WM_DRAWITEM消息就会发送到所有者窗口的窗口过程。
MF_POPUP
0x00000010L
指定菜单项打开下拉菜单或子菜单。 uIDNewItem 参数指定下拉菜单或子菜单的句柄。 此标志用于向菜单栏添加菜单名称,或将子菜单打开到下拉菜单、子菜单或快捷菜单的菜单项。
MF_SEPARATOR
0x00000800L
绘制一条水平分割线。 此标志仅在下拉菜单、子菜单或快捷菜单中使用。 行不能灰显、禁用或突出显示。 忽略 lpNewItem 和 uIDNewItem 参数。
MF_STRING
0x00000000L
指定菜单项是文本字符串; lpNewItem 参数是指向字符串的指针。
MF_UNCHECKED
0x00000000L
不会在项旁边放置复选标记, (默认) 。 如果应用程序提供复选标记位图 (请参阅 SetMenuItemBitmaps) ,此标志会显示菜单项旁边的清除位图。
将新菜单分配给指定的窗口。
例子
HMENU hMenu = CreateMenu();
AppendMenu(hMenu, MF_STRING, 1000, "menu0");
AppendMenu(hMenu, MF_STRING, 1001, "menu1");
SetMenu(hwnd,hMenu);

创建弹出菜单
创建下拉菜单、子菜单或快捷菜单。 菜单最初为空。 可以使用 InsertMenuItem 函数插入或追加菜单项。 还可以使用 InsertMenu 函数插入菜单项和 AppendMenu 函数来追加菜单项。
同样使用AppendMenu添加菜单项
BOOL AppendMenuA(
[in] HMENU hMenu,
[in] UINT uFlags,
[in] UINT_PTR uIDNewItem,
[in, optional] LPCSTR lpNewItem
);
代码
hPopMenu = CreatePopupMenu();
AppendMenu(hPopMenu, MF_STRING, 1010, "popmenu0");
AppendMenu(hPopMenu, MF_STRING, 1011, "popmenu1");
弹出菜单
在指定位置显示快捷菜单,并跟踪菜单上的项目选择。 快捷菜单可在屏幕上的任意位置显示。
BOOL TrackPopupMenu(
[in] HMENU hMenu,
[in] UINT uFlags,
[in] int x,
[in] int y,
[in] int nReserved,
[in] HWND hWnd,
[in, optional] const RECT *prcRect
);
参数
[in] hMenu
类型: HMENU
要显示的快捷菜单的句柄。 可以通过调用 CreatePopupMenu 来创建新的快捷菜单,或通过调用 GetSubMenu 检索与现有菜单项关联的子菜单的句柄来获取句柄。
[in] uFlags
类型: UINT
使用更多这些标志中的零来指定函数选项。
使用以下标志之一指定函数水平定位快捷菜单的方式。
Value 含义
TPM_CENTERALIGN
0x0004L
将快捷菜单水平相对于 x 参数指定的坐标居中。
TPM_LEFTALIGN
0x0000L
定位快捷菜单,使其左侧与 x 参数指定的坐标对齐。
TPM_RIGHTALIGN
0x0008L
定位快捷菜单,使其右侧与 x 参数指定的坐标对齐。
使用以下标志之一指定函数如何垂直定位快捷菜单。
Value 含义
TPM_BOTTOMALIGN
0x0020L
定位快捷菜单,使其底部与 y 参数指定的坐标对齐。
TPM_TOPALIGN
0x0000L
定位快捷菜单,使其顶部与 y 参数指定的坐标对齐。
TPM_VCENTERALIGN
0x0010L
将快捷菜单垂直相对于 y 参数指定的坐标居中。
使用以下标志控制用户选择的发现,而无需为菜单设置父窗口。
Value 含义
TPM_NONOTIFY
0x0080L
当用户单击菜单项时,该函数不会发送通知消息。
TPM_RETURNCMD
0x0100L
该函数在返回值中返回用户选择的菜单项标识符。
使用以下标志之一指定快捷菜单跟踪的鼠标按钮。
Value 含义
TPM_LEFTBUTTON
0x0000L
用户可以仅选择鼠标左键的菜单项。
TPM_RIGHTBUTTON
0x0002L
用户可以选择带有左右鼠标按钮的菜单项。
使用以下标志的任何合理组合来修改菜单的动画。 例如,通过选择水平标志和垂直标志,可以实现对角动画。
Value 含义
TPM_HORNEGANIMATION
0x0800L
从右到左对菜单进行动画处理。
TPM_HORPOSANIMATION
0x0400L
从左到右对菜单进行动画处理。
TPM_NOANIMATION
0x4000L
显示没有动画的菜单。
TPM_VERNEGANIMATION
0x2000L
从下到上对菜单进行动画处理。
TPM_VERPOSANIMATION
0x1000L
从上到下对菜单进行动画处理。
若要发生任何动画, SystemParametersInfo 函数必须设置 SPI_SETMENUANIMATION。 此外,如果菜单淡化动画处于打开状态,则忽略除 TPM_NOANIMATION之外的所有TPM_*ANIMATION 标志。 有关详细信息,请参阅 SystemParametersInfo 中的SPI_GETMENUFADE标志。
使用 TPM_RECURSE 标志显示另一个菜单时显示菜单。 这旨在支持菜单中的上下文菜单。
对于从右到左的文本布局,请使用 TPM_LAYOUTRTL。 默认情况下,文本布局从左到右。
[in] x
类型: int
快捷菜单的水平位置,以屏幕坐标为单位。
[in] y
类型: int
快捷菜单的垂直位置,以屏幕坐标为单位。
[in] nReserved
类型: int
保留;必须为零。
[in] hWnd
类型:HWND
拥有快捷菜单的窗口的句柄。 此窗口从菜单中接收所有消息。 在函数返回之前,该窗口不会从菜单中收到 WM_COMMAND 消息。 如果在 uFlags 参数中指定TPM_NONOTIFY,函数不会将消息发送到 hWnd 标识的窗口。 但是,仍必须在 hWnd 中传递窗口句柄。 它可以是应用程序的任何窗口句柄。
[in, optional] prcRect
类型: const RECT*
已忽略。
实现右键弹出菜单,只需要在窗体过程回调函数中对WM_RBUTTONUP(右键释放事件)消息进行处理,弹出菜单
switch(uMsg){
case WM_RBUTTONUP:
{
POINT p;
//lParam低位储存鼠标x位置
p.x = LOWORD(lParam);
//lParam高位储存鼠标y位置
p.y = HIWORD(lParam);
//客户端转换成屏幕坐标:
ClientToScreen(hwnd,&p);
//弹出菜单
TrackPopupMenu(hPopMenu,TPM_RIGHTBUTTON,p.x,p.y,0,hwnd,NULL);
}
break;
...
}
添加子菜单
使用AppendMenu函数可以实现子菜单的添加
AppendMenu(菜单句柄,MF_POPUP,(UINT)次级弹出菜单句柄,子菜单名称)
代码
hPopMenu = CreatePopupMenu();
AppendMenu(hPopMenu, MF_STRING, 1010, "popmenu0");
AppendMenu(hPopMenu, MF_STRING, 1011, "popmenu1");
//子菜单
HMENU hPopMenuSubmenu = CreatePopupMenu();
AppendMenu(hPopMenuSubmenu, MF_STRING, 10120, "submenu0");
AppendMenu(hPopMenuSubmenu, MF_STRING, 10121, "submenu1");
//添加子菜单
AppendMenu(hPopMenu,MF_POPUP,(UINT)hPopMenuSubmenu,"popmenu2");
菜单点击处理
在窗体过程函数中,VM_COMMAND消息类型,通过判断wParam参数可以判断菜单ID并且进行处理
switch(uMsg){
case WM_COMMAND:
{
switch(wParam){
case 1000:
MessageBox(NULL,"you clicked menu 0!","",MB_OK);
break;
case 1010:
MessageBox(NULL,"you clicked POP menu 0!","",MB_OK);
break;
}
}
break;
...
}
完整代码
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
{
// Register the window class.
const char CLASS_NAME[] = "testtClass";
WNDCLASSA wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClassA(&wc);
// Create the window.
HWND hwnd = CreateWindowExA(
0, // Optional window styles.
CLASS_NAME, // Window class
"Test window", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window
NULL, // Menu
hInstance, // Instance handle
NULL // Additional application data
);
if (hwnd == NULL)
{
return 0;
}
ShowWindow(hwnd, nCmdShow);
// Run the message loop.
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
HMENU hMenu;
HMENU hPopMenu;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
{
//建立顶级菜单
hMenu = CreateMenu();
AppendMenu(hMenu, MF_STRING, 1000, "menu0");
AppendMenu(hMenu, MF_STRING, 1001, "menu1");
//设置窗体菜单
SetMenu(hwnd,hMenu);
//建立子菜单
HMENU hMenuSubmenu = CreatePopupMenu();
AppendMenu(hMenuSubmenu, MF_STRING, 10020, "submenu0");
AppendMenu(hMenuSubmenu, MF_STRING, 10021, "submenu1");
//添加子菜单到顶级菜单
AppendMenu(hMenu,MF_POPUP,(UINT)hMenuSubmenu,"menu2");
//建立弹出菜单
hPopMenu = CreatePopupMenu();
AppendMenu(hPopMenu, MF_STRING, 1010, "popmenu0");
AppendMenu(hPopMenu, MF_STRING, 1011, "popmenu1");
//建立子菜单
HMENU hPopMenuSubmenu = CreatePopupMenu();
AppendMenu(hPopMenuSubmenu, MF_STRING, 10120, "submenu0");
AppendMenu(hPopMenuSubmenu, MF_STRING, 10121, "submenu1");
//添加子菜单到弹出菜单
AppendMenu(hPopMenu,MF_POPUP,(UINT)hPopMenuSubmenu,"popmenu2");
}
break;
case WM_RBUTTONUP://鼠标右键事件
{
POINT p;
//lParam低位储存鼠标x位置
p.x = LOWORD(lParam);
//lParam高位储存鼠标y位置
p.y = HIWORD(lParam);
//客户端转换成屏幕坐标:
ClientToScreen(hwnd,&p);
//弹出菜单
TrackPopupMenu(hPopMenu,TPM_RIGHTBUTTON,p.x,p.y,0,hwnd,NULL);
}
break;
case WM_COMMAND:
{
switch(wParam){
case 1000://点击了顶级菜单0
MessageBox(NULL,"you clicked menu 0!","",MB_OK);
break;
case 1010://点击了弹出菜单0
MessageBox(NULL,"you clicked POP menu 0!","",MB_OK);
break;
}
}
break;
case WM_DESTROY:
DestroyMenu(hPopMenu);
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// All painting occurs here, between BeginPaint and EndPaint.
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

销毁菜单
函数原型:BOOL DestroyMenu(HMENU hMenu);
参数:
hMenu:要销毁的菜单的句柄。
返回值:如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
备注:一个应用程序在关闭之前,必须调用函数DestroyMenu来销毁一个没被分配给窗口的菜单。分配给窗口的菜单,当应用程序关闭时,被自动销毁。