分清几个概念
<1>“主菜单” 和 “顶层菜单” 是一个意思。
<2>主菜单中的项目叫做 “弹出菜单” 或者 “子菜单”。
<3>弹出菜单的项目可以是另外一个弹出菜单。
<4>菜单的状态:启用,禁用,无效化,无效化跟前两者的区别是灰色显示文字。
(1)菜单消息
<1>WM_INITMENU
wParam, // handle to menu (HMENU) lParam // not used
<2>WM_MENUSELECT
菜单项被选中的时候
wParam, // menu item (UINT) and flags (UINT) lParam //handle to menu (HMENU)
其中
LOWORD(wParam) //被选中项目:菜单ID或者弹出式菜单句柄 HIWORD(wParam) //选择旗标
旗标是MF_GRAYED、MF_DISABLED、MF_CHECKED、MF_BITMAP、MF_POPUP、MF_HELP、MF_SYSMENU和MF_MOUSESELECT的集合。
<3>WM_INITMENUPOPUP
当下拉菜单被激活的时候就会发出这样的消息
WPARAM wParam, // handle to menu (HMENU) LPARAM lParam // item position and indicatorLOWORD(lParam)代表的是菜单项索引,HIWORD(lParam)表示的是TRUE,或者FALSE,菜单是系统菜单的时候表示的TRUE,非系统菜单的时候表示的是FALSE。
<4>WM_COMMAND
表示使用者已经从菜单中选择了一个被启用的菜单项,
LOWORD (wParam):菜单命令ID
HIWORD(wParam):0
lParam:0
<5>WM_MENUCHAR
(2)菜单项中的字母的下划线
把字母前面加&字符,就可以出现字母下划线的效果,当用Alt键+ 字符,可以快捷的弹出子菜单,或者执行菜单项命令。
对应属性
(3)菜单项的选中和去选中状态
CheckMenuItem(hMenu, iSelection, MF_UNCHECKED) ; CheckMenuItem(hMenu, iSelection, MF_CHECKED) ;
(4)关于Menu的函数
关于菜单的操作从大体方向上看无外乎增删改查四种操作。
4.1 HMENUCreateMenu(VOID);
4.2 BOOL AppendMenu( HMENU hMenu, // handle to menu
UINT uFlags, //menu-item options
UINT_PTR uIDNewItem, // identifier, menu, or submenu
LPCTSTR lpNewItem //menu-item content);
其中uFlags 可以是:
MF_BITMAP,MF_OWNERDRAW,MF_STRING
示例:
AppendMenu (hMenuPopup, MF_STRING, IDM_APP_EXIT,"E&xit") ;
AppendMenu (hMenu, MF_POPUP, hMenuPopup,"&File") ;
4.3 BOOLInsertMenu( HMENU hMenu, // handle to menu
UINT uPosition, // item that new item precedes
UINT uFlags, // options
UINT_PTR uIDNewItem, // identifier, menu, or submenu
LPCTSTR lpNewItem // menu item content);
这个函数和AppendMenu相比除了uPosition这个参数外,其余完全相同
uPosition:表示被插的位置索引或者菜单ID,具体是哪一个取决于uFlags中是MF_BYCOMMAND还是MF_BYPOSITION。
uIDNewItem:插入项是命令项的时候表示的是ID,插入项是菜单的时候表示的菜单句柄。
lpNewItem: 插入项的内容,具体取决于uFlags中包含的MF_BITMAP,MF_STRING,MF_OWNERDRAW
注意:不能放在一起的命令组合
4.4 BOOLInsertMenuItem( HMENU hMenu, // handle to menu
UINT uItem, // identifier or position
BOOL fByPosition, // meaning of uItem
LPCMENUITEMINFO lpmii // menu item information);
typedef struct tagMENUITEMINFO { UINT cbSize; UINT fMask; UINT fType; UINT fState; UINT wID; HMENU hSubMenu; HBITMAP hbmpChecked; HBITMAP hbmpUnchecked; ULONG_PTR dwItemData; LPTSTR dwTypeData; UINT cch; HBITMAP hbmpItem; } MENUITEMINFO, *LPMENUITEMINFO;
4.5 BOOL RemoveMenu( HMENU hMenu, // handle to menu
UINT uPosition, // menu item identifier or position
UINT uFlags // options);
4.6 BOOLModifyMenu( HMENU hMnu, // handle to menu
UINT uPosition, // menu item to modify
UINTuFlags, // options
UINT_PTR uIDNewItem, // identifier, menu, or submenu
LPCTSTR lpNewItem // menu item content);
4.7 BOOLDeleteMenu( HMENU hMenu, // handle to menu
UINT uPosition, // menu item identifier or position
UINT uFlags // option);
删除菜单项,如果菜单项时弹出菜单,那么就会释放菜单句柄所指向的内存。
4.7 BOOLDrawMenuBar( HWND hWnd // handle to window);
4.8 HMENUGetSubMenu( HMENU hMenu, // handle to menu
int nPos // menu item position);
当菜单栏发生变化时候,必须调用这个函数重新绘制菜单//经常验证,未必
(6)右键菜单
右键菜单跟一般的菜单没什么区别,只是弹出的时候,需要用到这个函数
BOOLTrackPopupMenu( HMENU hMenu, // handle to shortcut menu UINT uFlags, // options int x, // horizontal position int y, // vertical position int nReserved, // reserved, must be zero HWND hWnd, // handle to owner window CONST RECT *prcRect // ignored);
其中的uFlags参数指定了菜单中菜单中的对齐方式,左键右键选定菜单项
TPM_CENTERALIGN,TMP_LEFTALIGN,TMP_RIGHTALIGN
TPM_BOTTOMALIGN, TPM_TOPALIGN, TPM_VCENTERALIGN
TPM_LEFTBUTTPON,TPM_RIGHTBUTTON
TPM_NONOTIFY, TPM_RETURNCMD
(7)系统菜单
获取系统菜单句柄
HMENU GetSystemMenu(
HWNDhWnd, // handle to window
BOOL bRevert // reset option);
其中bRevert = FALSE时候,表示,复制系统的菜单,并且返回复制菜单的句柄,这个菜单可以进行修改。当bRevert = TRUE 时,设置系统菜单为默认的原始状态,并且函数返回值是NULL.
(8) 加速键
加速键也是一种资源,它可以使用快捷键迅速的打开命令项。加速键 可以在在资源中自己添加,也可以直接使用程序编写。加速键中主要的改变的code有
while(GetMessage(&msg,NULL,0,0))
{
if (!TranslateAccelerator(hWnd,hAccel,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
在这里 TranslateAccelerator函数把 一些按键消息翻译成WM_COMMAND,或者WM_SYSCOMMAND消息。
(9)代码示例
一下示例是一个完全依靠code不依赖创建资源的菜单demo,其中包含菜单栏,右键菜单,系统菜单,加速键可以对菜单进行动态的修改,删除,添加操作。
#define OEMRESOURCE # include<Windows.h> #define IDM_FILE_OPEN 100 #define IDM_FILE_NEW 101 #define IDM_FILE_PIC 102 #define IDM_FILE_EXIT 103 #define IDM_MENU_ADD 104 #define IDM_MENU_REM 105 #define IDM_MENU_DEL 106 #define IDM_MENU_MOD 107 #define IDM_ABOUT 108 #define IDM_VERSION 109 #define IDM_MENU_NEW 110 #define IDM_POP_ONE 200 #define IDM_POP_TWO 201 #define IDM_SYS_ONE 300 #define IDM_SYS_TWO 301 LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam); HMENU createOwnMenu(HWND hwnd); HMENU createPopMenu(HWND hwnd); HACCEL createAccelerator(HWND hwnd); TCHAR* szAppName = TEXT("MenuClass"); TCHAR* szWndName = TEXT("ChangeMenu"); HACCEL hAccel = NULL; int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR lpCmdLine,int iCmdShow) { WNDCLASS wndCls; HWND hWnd; MSG msg; wndCls.cbClsExtra = 0; wndCls.cbWndExtra = 0; wndCls.lpfnWndProc = WndProc; wndCls.style = CS_HREDRAW | CS_VREDRAW; wndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndCls.hCursor = LoadCursor(NULL,IDC_ARROW); wndCls.hIcon = LoadIcon(NULL,IDI_APPLICATION); wndCls.hInstance = hInstance; wndCls.lpszClassName = szAppName; wndCls.lpszMenuName = NULL; if(!RegisterClass(&wndCls)) { MessageBox(NULL,TEXT("Register window failed"),TEXT("Error"),MB_OK); } hWnd = CreateWindow(szAppName,szWndName,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,NULL,hInstance,NULL); UpdateWindow(hWnd); ShowWindow(hWnd,SW_NORMAL); while(GetMessage(&msg,NULL,0,0)) { if(!TranslateAccelerator(hWnd,hAccel,&msg)) TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { static int nAdd = 1; HMENU hMenu,hSonMenu,hTmpMenu; HMENU hTrack,hSon; HMENU hSysMenu; POINT pt; switch(msg) { case WM_CREATE: hMenu = createOwnMenu(hwnd); SetMenu(hwnd,hMenu); hSysMenu = GetSystemMenu(hwnd,FALSE); AppendMenu(hSysMenu,MF_SEPARATOR,0,NULL); AppendMenu(hSysMenu,MF_STRING,IDM_SYS_ONE,TEXT("SysOne")); AppendMenu(hSysMenu,MF_STRING,IDM_SYS_TWO,TEXT("SysTwo")); hAccel = createAccelerator(hwnd); break; case WM_SYSCOMMAND: switch(LOWORD(wParam)) { case IDM_SYS_ONE: MessageBox(NULL,TEXT("This is added system menu item1"),NULL,MB_OK); break; case IDM_SYS_TWO: MessageBox(NULL,TEXT("This is added system menu item2"),NULL,MB_OK); break; } break; case WM_COMMAND: hMenu = GetMenu(hwnd); switch(LOWORD(wParam)) { case IDM_FILE_OPEN: MessageBox(NULL,TEXT("File Open selected"),TEXT("Test check"),MB_OK); break; case IDM_MENU_ADD: hTmpMenu = GetSubMenu(hMenu,2); AppendMenu(hTmpMenu,MF_STRING,IDM_MENU_NEW+nAdd,TEXT("New Item")); nAdd++; DrawMenuBar(hwnd); break; case IDM_MENU_REM: hTmpMenu = GetSubMenu(hMenu,2); if( nAdd >1 ) { nAdd--; RemoveMenu(hTmpMenu,IDM_MENU_NEW+nAdd,MF_BYCOMMAND); } // 当菜单项时弹出菜单的时候,仅仅切断弹出菜单跟所属菜单的联系,但不销毁对象 /*GetSubMenu(hTmpMenu,2); RemoveMenu(hTmpMenu,2,MF_BYPOSITION);*/ DrawMenuBar(hwnd); break; case IDM_MENU_MOD: hTmpMenu = GetSubMenu(hMenu,2); ModifyMenu(hTmpMenu,0,MF_BYPOSITION,IDM_ABOUT,TEXT("Modified Item")); DrawMenuBar(hwnd); break; case IDM_MENU_DEL: hTmpMenu = GetSubMenu(hMenu,2); DeleteMenu(hTmpMenu,2,MF_BYPOSITION); DrawMenuBar(hwnd); break; } break; case WM_RBUTTONDOWN: hTrack = createPopMenu(hwnd); hSon = GetSubMenu(hTrack,0); pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); ClientToScreen(hwnd,&pt); TrackPopupMenu(hSon,TPM_LEFTBUTTON| TPM_RIGHTALIGN,pt.x,pt.y,0,hwnd,NULL); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hwnd,msg,wParam,lParam); } HMENU createOwnMenu(HWND hwnd) { HMENU hMenu = CreateMenu(); HMENU hPopMenu = CreateMenu(); //MF_BYPOSIOTION,MF_BYCOMMAND is not useful here in AppendMenu AppendMenu(hPopMenu,MF_STRING|MF_CHECKED|MF_GRAYED,IDM_FILE_OPEN,TEXT("&Open")); InsertMenu(hPopMenu,0,MF_BYPOSITION|MF_STRING|MF_DISABLED,IDM_FILE_NEW,TEXT("&New")); HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE); HBITMAP hBmp = (HBITMAP)LoadImage(hInstance,TEXT("bitmap1.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE); AppendMenu(hPopMenu,MF_BITMAP,IDM_FILE_PIC,(LPCWSTR)hBmp); AppendMenu(hPopMenu,MF_SEPARATOR,NULL,NULL); AppendMenu(hPopMenu,MF_STRING,IDM_FILE_EXIT,TEXT("&Exit")); SetMenuItemBitmaps(hPopMenu,IDM_FILE_PIC,MF_BYCOMMAND,hBmp,hBmp); AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hPopMenu,TEXT("File")); hPopMenu = CreateMenu(); AppendMenu(hPopMenu,MF_STRING,IDM_MENU_ADD,TEXT("&Add")); AppendMenu(hPopMenu,MF_STRING,IDM_MENU_REM,TEXT("&Remove")); AppendMenu(hPopMenu,MF_STRING,IDM_MENU_MOD,TEXT("&Modify")); AppendMenu(hPopMenu,MF_STRING,IDM_MENU_DEL,TEXT("&Delete")); AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hPopMenu,TEXT("Menu")); hPopMenu = CreateMenu(); AppendMenu(hPopMenu,MF_STRING,IDM_ABOUT,TEXT("About")); AppendMenu(hPopMenu,MF_STRING,IDM_VERSION,TEXT("Version")); HMENU hSonMenu = CreateMenu(); AppendMenu(hSonMenu,MF_STRING,IDM_MENU_NEW,TEXT("Son")); AppendMenu(hPopMenu,MF_POPUP,(UINT_PTR)hSonMenu,TEXT("Son Menu")); AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hPopMenu,TEXT("Change")); return hMenu; } HMENU createPopMenu(HWND hwnd) { HMENU hMenu = CreateMenu(); HMENU hPop = CreateMenu(); AppendMenu(hPop,MF_STRING,IDM_POP_ONE,TEXT("One")); AppendMenu(hPop,MF_STRING,IDM_POP_TWO,TEXT("Twod")); AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hPop,TEXT("Pop")); return hMenu; } HACCEL createAccelerator(HWND hwnd) { ACCEL acce[2]; acce[0].fVirt = FCONTROL | FNOINVERT | FVIRTKEY; acce[0].key = 'A'; acce[0].cmd = IDM_MENU_ADD; acce[1].fVirt = FCONTROL | FNOINVERT | FVIRTKEY; acce[1].key = 'R'; acce[1].cmd = IDM_MENU_REM; HACCEL hAccel = CreateAcceleratorTable(acce,2); return hAccel; }