windows编程之菜单操作

分清几个概念

<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 indicator
LOWORD(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

 

注意:不能放在一起的命令组合

  • MF_BYCOMMAND and MF_BYPOSITION
  • MF_DISABLED, MF_ENABLED, and MF_GRAYED
  • MF_BITMAP, MF_STRING, MF_OWNERDRAW, and MF_SEPARATOR
  • MF_MENUBARBREAK and MF_MENUBREAK
  • MF_CHECKED and MF_UNCHECKED

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;
}



你可能感兴趣的:(菜单栏,右键菜单,动态菜单,系统菜单,加速键)