博客
关于我
《Windows程序设计》读书笔十 菜单和其他资源
阅读量:360 次
发布时间:2019-03-04

本文共 49504 字,大约阅读时间需要 165 分钟。

第十章  菜单和资源


windows通过LoadIcon LoadCursor等函数来加载资源


图标

鼠标指针

字符串

自定义资源

菜单

键盘加速键

对话框

位图


10.1  图标,鼠标指针,字符串和自定义资源

10.1.1 向程序添加图标

Tools->Options->Build->Export makefile when saving project file.

导出mak文件

注:该方法在VS2015中已经不可用。VS2015需要自己写makefile或者使用makefile project来生成mak文件,然后使用nmake编译文件。

nmake的配置方法参考

http://www.cnblogs.com/cvbnm/articles/1954872.html


源代码

#include <windows.h>   #include "resource.h"LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	static      TCHAR szAppName[] = TEXT("IconDemo");	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class      	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.      	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));//LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.       	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.      	hwnd = CreateWindow(szAppName,      //Window class name      		TEXT("Icon Demo"),      //Window caption      		WS_OVERLAPPEDWINDOW,            //Window Style      		CW_USEDEFAULT,                  //initial x position      		CW_USEDEFAULT,                  //initial y position      		CW_USEDEFAULT,                  //initial x size      		CW_USEDEFAULT,                  //initial y size      		NULL,                           //parent window handle      		NULL,                           //window menu handle      		hInstance,                      //program instance handle      		NULL);                          //creation parameters      	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.      						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc      LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HICON	hIcon;	static int		cxIcon, cyIcon, cxClient, cyClient;	HDC				hdc;	HINSTANCE		hInstance;	PAINTSTRUCT		ps;	int				x, y;	switch (message) //get the message      	{	case WM_CREATE:		hInstance = ((LPCREATESTRUCT)lParam)->hInstance;		hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));		cxIcon = GetSystemMetrics(SM_CXICON);		cyIcon = GetSystemMetrics(SM_CYICON);		return 0;	case WM_SIZE:		cxClient = LOWORD(lParam);		cyClient = HIWORD(lParam);		return 0;	case WM_PAINT:		hdc = BeginPaint(hwnd, &ps);		for (y = 0; y < cyClient; y += cyIcon)			for (x = 0; x < cxClient; x += cxIcon)				DrawIcon(hdc, x, y, hIcon);		EndPaint(hwnd, &ps);		return 0;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}

这段代码不能够直接编译

还需要创建资源文件,使用AddItem来增加icondemo.rc文件,VS会自动创建Resource.h头文件。

使用Resource Editor中的Add Resource 添加图标资源


原书中的图标是32x32的,在VS2015和Win7时代已经支持256x256的超大图标了


同时将ICON的ID改为IDI_ICON

然后可以编译程序了

运行结果


SM_CXICON  和SM_CYICON 为32x32

更小的图标是  SM_CXSMSIZE   和  SM_CYSMSIZE


10.1.2 获得图标的句柄

hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));


#define MAKEINTRESOURCE (i) (LPTSTR) ((DWORD)((WORD)(i)))

资源ID也可以直接使用字符串

10.3.3  在应用程序中使用图标

RegisterClassEx   使用  WNDCLASSEX结构

有额外字段

ebSize   表示WNDCLASSEX结构大小

hIconSm  应该设定为小图标的句柄。

因此你需要设定两个图标句柄, 一个标准一个是小

在程序运行时改变图标,使用  SetClassLong函数实现。

SetClassLong(hwnd, GCL_HICON, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ALTICON));

不想保存图标句柄可以使用一下函数

DrawIcon(hdc, x, y, GetClassLong(hwnd, GCL_HICON));

hIcon 是特例 生成的句柄不需要手动销毁,


10.1.4   使用自定义鼠标指针

和图标类似,在资源编辑器中添加指针

然后

wndclass.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR));

或者用文本名字来定义鼠标指针

当鼠标在基于此类创建的窗口上,自定义的鼠标指针就会显示出来。

更改子窗口的hCursor字段

SetClassLong(hwndChild, GCL_HCURSOR, LoadCursor(hInstance, TEXT("childcursor"));

也可以使用SetCursor(hCursor);  来设定鼠标指针

应该在WM_MOUSEMOVE时调用SetCursor 否则一旦移动鼠标指针windows会重绘鼠标指针


10.1.5 字符串资源

使用资源管理器新建String Table

使用LoadString 来加载字符串

LoadString(hInstance, id, szBuffer, iMaxLength);  支持c语言的格式设置符号

所有字符串表都是以Unicode格式保持,LoadStringW直接加载Unicode文本,  LoadStringA则会进行代码页转换


10.1.6 自定义资源

hResource = LoadResource(hInstance, FindResource(hInstance, MAKEINTRESOURCE(IDR_BINTYPE), TEXT("BINTYPE")));

需要访问文本时

pData = LockResource(hResource);

使用完以后释放

FreeResource(hResource);

一个使用图标,字符串和自定义资源的例子

poepoem.cpp

#include <windows.h>   #include "resource.h"LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    HINSTANCE hInst;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	static      TCHAR szAppName[16], szCaption[64], szErrMsg[64];	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class   	hInst = hInstance;	LoadString(hInstance, IDS_APPNAME, szAppName, sizeof(szAppName) / sizeof(TCHAR));	LoadString(hInstance, IDS_CAPTION, szCaption, sizeof(szCaption) / sizeof(TCHAR));	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.      	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(hInstance, szAppName);//LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.       	if (!RegisterClass(&wndClass))	{		//Support the ANSI encode.		LoadStringA(hInstance, IDS_APPNAME, (char*)szAppName, sizeof(szAppName));		LoadStringA(hInstance, IDS_ERRMSG, (char*)szErrMsg, sizeof(szErrMsg));		MessageBoxA(NULL, (char *)szErrMsg,			(char *)szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.      	hwnd = CreateWindow(szAppName,      //Window class name      		szCaption,      //Window caption      		WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,            //Window Style      		CW_USEDEFAULT,                  //initial x position      		CW_USEDEFAULT,                  //initial y position      		CW_USEDEFAULT,                  //initial x size      		CW_USEDEFAULT,                  //initial y size      		NULL,                           //parent window handle      		NULL,                           //window menu handle      		hInstance,                      //program instance handle      		NULL);                          //creation parameters      	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.      						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc      LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static char*		pText;	static HGLOBAL		hResource;	static HWND			hScroll;	static int			iPosition, cxChar, cyChar, cyClient, iNumLines, xScroll;	HDC					hdc;	PAINTSTRUCT			ps;	RECT				rect;	TEXTMETRIC			tm;	int ilength;	switch (message) //get the message      	{	case WM_CREATE:		hdc = GetDC(hwnd);		GetTextMetrics(hdc, &tm);		cxChar = tm.tmAveCharWidth;		cyChar = tm.tmHeight + tm.tmExternalLeading;		ReleaseDC(hwnd, hdc);		xScroll = GetSystemMetrics(SM_CXVSCROLL);		hScroll = CreateWindow(TEXT("scrollbar"), NULL,			WS_CHILD | WS_VISIBLE | SBS_VERT,			0, 0, 0, 0,			hwnd, (HMENU)1, hInst, NULL);		hResource = LoadResource(hInst, FindResource(hInst, TEXT("AnnabelLee"),			TEXT("TEXT")));		pText = (char *)LockResource(hResource);		iNumLines = 0;		while (*pText != TEXT('\\') && *pText != TEXT('\0'))		{			if (*pText == TEXT('\n'))				iNumLines++;			pText = AnsiNext(pText);		}		//*pText = TEXT('\0');		SetScrollRange(hScroll, SB_CTL, 0, iNumLines, FALSE);		SetScrollPos(hScroll, SB_CTL, 0, FALSE);		return 0;	case WM_SIZE:		MoveWindow(hScroll, LOWORD(lParam) - xScroll, 0,			xScroll, cyClient = HIWORD(lParam), TRUE);		SetFocus(hwnd);		return 0;	case WM_SETFOCUS:		SetFocus(hScroll);		return 0;	case WM_VSCROLL:		switch (wParam)		{		case SB_TOP:			iPosition = 0;			break;		case SB_BOTTOM:			iPosition = iNumLines;			break;		case SB_LINEUP:			iPosition -= 1;			break;		case SB_LINEDOWN:			iPosition += 1;			break;		case SB_PAGEUP:			iPosition -= cyClient / cyChar;			break;		case SB_PAGEDOWN:			iPosition += cyClient / cyChar;			break;		case SB_THUMBPOSITION:		case SB_THUMBTRACK:			iPosition = LOWORD(lParam);			break;		}		iPosition = max(0, min(iPosition, iNumLines));		if (iPosition != GetScrollPos(hScroll, SB_CTL))		{			SetScrollPos(hScroll, SB_CTL, iPosition, TRUE);			InvalidateRect(hwnd, NULL, TRUE);		}		return 0;	case WM_PAINT:		hdc = BeginPaint(hwnd, &ps);		pText = (char*)LockResource(hResource);		GetClientRect(hwnd, &rect);		rect.left += cxChar;		rect.top += cyChar * (1 - iPosition);		DrawTextA(hdc, pText, -1, &rect, DT_EXTERNALLEADING);		EndPaint(hwnd, &ps);		return 0;	case WM_DESTROY:		FreeResource(hResource);		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}



poepoem.rc

// Microsoft Visual C++ generated resource script.//#include "resource.h"#define APSTUDIO_READONLY_SYMBOLS///// Generated from the TEXTINCLUDE 2 resource.//#include "winres.h"/#undef APSTUDIO_READONLY_SYMBOLS/// Chinese (Simplified, PRC) resources#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED#ifdef APSTUDIO_INVOKED///// TEXTINCLUDE//1 TEXTINCLUDE BEGIN    "resource.h\0"END2 TEXTINCLUDE BEGIN    "#include ""winres.h""\r\n"    "\0"END3 TEXTINCLUDE BEGIN    "\r\n"    "\0"END#endif    // APSTUDIO_INVOKED///// Icon//// Icon with lowest ID value placed first to ensure application icon// remains consistent on all systems.PoePoem                 ICON                    "POEPOEM.ICO"///// TEXT//ANNABELLEE              TEXT    DISCARDABLE     "poepoem.txt"///// String Table//STRINGTABLEBEGIN    IDS_APPNAME             "PoePoem"    IDS_CAPTION             """Annabel Lee"" by Edgar Allan Poe"    IDS_ERRMSG              "This program requires Windows NT!"END#endif    // Chinese (Simplified, PRC) resources/#ifndef APSTUDIO_INVOKED///// Generated from the TEXTINCLUDE 3 resource.///#endif    // not APSTUDIO_INVOKED

resource.h

//{  {NO_DEPENDENCIES}}// Microsoft Visual C++ generated include file.// Used by poepoem.rc//#define IDS_APPNAME                     102#define IDS_CAPTION                     103#define IDS_ERRMSG                      104// Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE        105#define _APS_NEXT_COMMAND_VALUE         40001#define _APS_NEXT_CONTROL_VALUE         1001#define _APS_NEXT_SYMED_VALUE           101#endif#endif

运行结果



10.2.1和菜单有关的概念

主菜单or顶级菜单

子菜单or 下拉菜单


弹出菜单可以被选中,顶级菜单不能被选中

菜单可以被启用,或禁用。 活动 ,非活动。


10.2.2 菜单结构

每个菜单有三个特征定义。  菜单显示什么, 文本或位图

ID号或者指向菜单的句柄

菜单的属性,是否禁用或选中


10.2.3 定义菜单

使用&F  windows会使用ALT+F 激活菜单

gray  菜单变灰

enabled  文字变灰

checked  菜单可选

Separator 选项会绘制一条水平的分割线

\t后面的文本会被放置在右边足够远的新栏中

\a 会使后面的文本右对齐

指定ID值是windows在菜单消息发送给窗口过程的数字。ID值在一个菜单中应该是唯一的。

使用IDM_XXX 开头


10.2.4 在程序中引用菜单

wndClass.lpszMenuName = szAppName; //给菜单指定一个和程序一样的名字菜单资源的ID

或者

hMenu = LoadMenu(hInstance, TEXT("MyMenu"));

或者

hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(ID_MENU));

作为CreateWindow的参数hMenu

CreateWindow中指定的菜单会覆盖窗口类中指定的任何菜单。如果第九个参数为NULL 则基于窗口类中指定的菜单创建窗口。

也可以在窗口创建后

SetMenu(hwnd, hMenu); 来设定菜单

动态改变窗口


当窗口被销毁时,附加到该窗口的任何菜单也将被销毁。而在程序结束前,任何没有附加到窗口的菜单应该通过DestoryMenu调用被显示销毁(DestroyIcon, DestroyCursor等 销毁自己创建的其他资源句柄,自定义资源使用FreeResource)


10.2.5 菜单和消息

当用户选择菜单windows会像窗口过程发送几个不同消息。多数情况下,应用程序可以忽略大部分交给DefWindowProc处理

有一个消息如下WM_INITMENU

wParam   主菜单句柄

lParam    0

即使用户选择了第一项,wParam也是主菜单的句柄。

WM_MENUSELECT 消息。移动鼠标时,这对实现状态栏非常有用

LOWORD(wParam) 所选的菜单项, 菜单ID或者弹出菜单的索引

HIWORD(wParam) 所选的标记

lParam    锁选菜单项的句柄

选中标记可以是, MF_GRAYED, MF_DISABLED, MF_CHECKED, MF_BITMAP, MF_POPUP, MF_HELP, MF_SYSMENU 或MF_MOUSESELECT.

windows 要显示弹出菜单,会像窗口过程发送一个带有如下参数的WM_INITMENUPOPUP

wParam   弹出菜单的句柄

LOWORD(lParam) 弹出菜单的索引

HIWORD(lParam) 1代表系统菜单,0代表其他菜单


最重要的是WM_COMMAND 

如果子菜单和子窗口控件使用相同的ID

检查lParam 对于窗口,该值是0


WM_SYSCOMMAND 类似于WM_COMMAND 不过他表示用户从系统菜单选择了一个启用的菜单项

wParam   菜单ID

lParam    0

如果WM_SYSCOMMAND是鼠标单击的结果,LOWORD(lParam) HIWORD(lParam)将包含鼠标指针的x和y坐标

系统菜单

SC_SIZE, SC_MOVE  SC_MINIMIZE  SC_MAXIMIZE  SC_NEXTWINDOW, SC_PREVWINDOW, SC_CLOSE< SC_VSCROLL, SC_HSCROLL, SC_ARRANGE,

SC_RESTORE,  SC_TASKLIST.


WM_MENUCHAR 按下Alt和不对应于任何菜单项的字符犍  或者   弹出菜单时,用户按了一个不对应任何弹出菜单项的字符键

LOWORD(wParam)    字符码

HIWORD(wParam)    选择码

lParam    菜单句柄


选择码如下

0  没有弹出菜单显示

MF_POPUP 弹出菜单被显示

MF_SYSMENU 系统弹出菜单被显示

一般程序会把改消息传给DefWindowProc, 然后DefWindowProc返回0, 使得windows发出嘟嘟声。


10.2.6 范例程序

menudemo.cpp

#include <windows.h>   #include "resource.h"#define ID_TIMER	1LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    TCHAR szAppName[] = TEXT("MenuDemo");HINSTANCE hInst;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class   	hInst = hInstance;	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.      	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = szAppName;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.       	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.      	hwnd = CreateWindow(szAppName,      //Window class name      		TEXT("Menu Demonstration"),      //Window caption      		WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,            //Window Style      		CW_USEDEFAULT,                  //initial x position      		CW_USEDEFAULT,                  //initial y position      		CW_USEDEFAULT,                  //initial x size      		CW_USEDEFAULT,                  //initial y size      		NULL,                           //parent window handle      		NULL,                           //window menu handle      		hInstance,                      //program instance handle      		NULL);                          //creation parameters      	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.      						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc      LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static int	idColor[5] = {WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH, 								  DKGRAY_BRUSH, BLACK_BRUSH};	static int	iSelection = IDM_BKGND_WHITE;	HMENU		hMenu;	switch (message) //get the message      	{	case WM_COMMAND:		hMenu = GetMenu(hwnd);		switch (LOWORD(wParam))		{		case IDM_FILE_NEW:		case IDM_FILE_OPEN:		case IDM_FILE_SAVE:		case IDM_FILE_SAVE_AS:			MessageBeep(0);			return 0;		case IDM_FILE_EXIT:			SendMessage(hwnd, WM_CLOSE, 0, 0);		case IDM_EDIT_UNDO:		case IDM_EDIT_CUT:		case IDM_EDIT_COPY:		case IDM_EDIT_PASTE:		case IDM_EDIT_CLEAR:			MessageBeep(0);			return 0;		//The logic below assumes that IDM_WHITE through IDM_BLACK 		//are consecutive numbers in the order show here.		case IDM_BKGND_WHITE:		case IDM_BKGND_LTGRAY:		case IDM_BKGND_GRAY:		case IDM_BKGND_DKGRAY:		case IDM_BKGND_BLACK:			CheckMenuItem(hMenu, iSelection, MF_UNCHECKED);			iSelection = LOWORD(wParam);			CheckMenuItem(hMenu, iSelection, MF_CHECKED);			SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)				GetStockObject(idColor[LOWORD(wParam) - IDM_BKGND_WHITE]));			InvalidateRect(hwnd, NULL ,TRUE);			return 0;		case IDM_TIMER_START:			if (SetTimer(hwnd, ID_TIMER, 1000, NULL))			{				EnableMenuItem(hMenu, IDM_TIMER_START, MF_GRAYED);				EnableMenuItem(hMenu, IDM_TIMER_STOP, MF_ENABLED);			}			return 0;		case IDM_TIMER_STOP:			KillTimer(hwnd, ID_TIMER);			EnableMenuItem(hMenu, IDM_TIMER_START, MF_ENABLED);			EnableMenuItem(hMenu, IDM_TIMER_STOP, MF_GRAYED);			return 0;		case IDM_APP_HELP:			MessageBox(hwnd, TEXT("Help not yet implemented!"),				szAppName, MB_ICONEXCLAMATION | MB_OK);			return 0;		case IDM_APP_ABOUT:			MessageBox(hwnd, TEXT("Menu Demonstration Program\n")				TEXT("(c) Charles Petzold, 1998"),				szAppName, MB_ICONINFORMATION | MB_OK);			return 0;		}		break;	case WM_TIMER:		MessageBeep(0);		return 0;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}



menudemo.rc


//Microsoft Developer Studio generated resource script.//#include "resource.h"#define APSTUDIO_READONLY_SYMBOLS///// Generated from the TEXTINCLUDE 2 resource.//#include "afxres.h"/#undef APSTUDIO_READONLY_SYMBOLS/// English (U.S.) resources#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)#ifdef _WIN32LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US#pragma code_page(1252)#endif //_WIN32#ifdef APSTUDIO_INVOKED///// TEXTINCLUDE//1 TEXTINCLUDE DISCARDABLE BEGIN    "resource.h\0"END2 TEXTINCLUDE DISCARDABLE BEGIN    "#include ""afxres.h""\r\n"    "\0"END3 TEXTINCLUDE DISCARDABLE BEGIN    "\r\n"    "\0"END#endif    // APSTUDIO_INVOKED///// Menu//MENUDEMO MENU DISCARDABLE BEGIN    POPUP "&File"    BEGIN        MENUITEM "&New",                        ID_MENUITEM40020        MENUITEM "&Open",                       IDM_FILE_OPEN        MENUITEM "&Save",                       IDM_FILE_SAVE        MENUITEM "Save &As...",                 IDM_FILE_SAVE_AS        MENUITEM SEPARATOR        MENUITEM "E&xit",                       IDM_APP_EXIT    END    POPUP "&Edit"    BEGIN        MENUITEM "&Undo",                       IDM_EDIT_UNDO        MENUITEM SEPARATOR        MENUITEM "C&ut",                        IDM_EDIT_CUT        MENUITEM "&Copy",                       IDM_EDIT_COPY        MENUITEM "&Paste",                      IDM_EDIT_PASTE        MENUITEM "De&lete",                     IDM_EDIT_CLEAR    END    POPUP "&Background"    BEGIN        MENUITEM "&White",                      IDM_BKGND_WHITE, CHECKED        MENUITEM "&Light Gray",                 IDM_BKGND_LTGRAY        MENUITEM "&Gray",                       IDM_BKGND_GRAY        MENUITEM "&Dark Gray",                  IDM_BKGND_DKGRAY        MENUITEM "&Black",                      IDM_BKGND_BLACK    END    POPUP "&Timer"    BEGIN        MENUITEM "&Start",                      IDM_TIMER_START        MENUITEM "S&top",                       IDM_TIMER_STOP, GRAYED    END    POPUP "&Help"    BEGIN        MENUITEM "&Help...",                    IDM_APP_HELP        MENUITEM "&About MenuDemo...",          IDM_APP_ABOUT    ENDEND#endif    // English (U.S.) resources/#ifndef APSTUDIO_INVOKED///// Generated from the TEXTINCLUDE 3 resource.///#endif    // not APSTUDIO_INVOKED


resource.h


//{  {NO_DEPENDENCIES}}// Microsoft Visual C++ generated include file.// Used by menudemo.rc//#define IDM_FILE_NEW                    40001#define IDM_FILE_OPEN                   40002#define IDM_FILE_SAVE                   40003#define IDM_FILE_SAVE_AS                40004#define IDM_FILE_EXIT                   40005#define IDM_EDIT_UNDO                   40006#define IDM_EDIT_CUT                    40007#define IDM_EDIT_COPY                   40008#define IDM_Menu                        40009#define IDM_EDIT_CLEAR                  40010#define IDM_BKGND_WHITE                 40011#define IDM_BKGND_LTGRAY                40012#define IDM_BKGND_GRAY                  40013#define IDM_BKGND_DKGRAY                40014#define IDM_BKGND_BLACK                 40015#define IDM_TIMER_START                 40016#define IDM_TIMER_STOP                  40017#define IDM_APP_HELP                    40018#define IDM_APP_ABOUT                   40019#define IDM_EDIT_PASTE                  40039// Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE        102#define _APS_NEXT_COMMAND_VALUE         40040#define _APS_NEXT_CONTROL_VALUE         1001#define _APS_NEXT_SYMED_VALUE           101#endif#endif

运行结果如下



10.2.7 菜单设计中的规范

10.2.8 定义菜单的繁琐方式

可以不适用资源脚本而使用CreateMenu和AppendMenu 动态创建菜单。完成定以后可以把菜单句柄传递给CreateWindow 或者使用SetMenu来设定窗口菜单。

hMenu = CreateMenu();

对于顶级菜单和弹出菜单必须使用不同的句柄

hMenuPop = CreateMenu();

AppendMenu(hMenuPopup, MF_STRING, IDM_FILE_NEW, "&NEW");

...


AppendMenu(hMenu, MF_POPUP, hMenuPopup, "&File");


hMenuPop = CreateMenu();

...

具体例子参考截图




第三种方法,  使用LoadMenuIndirect函数接受一个指向MENUITEMPLATE类型的结构指针,并返回一个指向菜单的句柄。


10.2.9 浮动弹出菜单

popmenu.cpp

#include <windows.h>   #include "resource.h"LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    HINSTANCE	hInst;TCHAR		szAppName[] = TEXT("PopMenu");int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class   	hInst = hInstance;	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.      	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.       	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.      	hwnd = CreateWindow(szAppName,      //Window class name      		TEXT("PopupMenu Demonstration"),      //Window caption      		WS_OVERLAPPEDWINDOW,            //Window Style      		CW_USEDEFAULT,                  //initial x position      		CW_USEDEFAULT,                  //initial y position      		CW_USEDEFAULT,                  //initial x size      		CW_USEDEFAULT,                  //initial y size      		NULL,                           //parent window handle      		NULL,                           //window menu handle      		hInstance,                      //program instance handle      		NULL);                          //creation parameters      	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.      						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc      LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HMENU	hMenu;	static int		idColor[5] = { WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,		DKGRAY_BRUSH, BLACK_BRUSH };	static int		iSelection = IDM_BKGND_WHITE;	POINT			point;	switch (message) //get the message      	{	case WM_CREATE:		hMenu = LoadMenu(hInst, szAppName);		hMenu = GetSubMenu(hMenu, 0);		return 0;	case WM_RBUTTONUP:		point.x = LOWORD(lParam);		point.y = HIWORD(lParam);		ClientToScreen(hwnd, &point);		TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y,			0, hwnd, NULL);		return 0;	case WM_COMMAND:		switch (LOWORD(wParam))		{		case IDM_FILE_NEW:		case IDM_FILE_OPEN:		case IDM_FILE_SAVE:		case IDM_FILE_SAVE_AS:			MessageBeep(0);			return 0;		case IDM_APP_EXIT:			SendMessage(hwnd, WM_CLOSE, 0, 0);		case IDM_EDIT_UNDO:		case IDM_EDIT_CUT:		case IDM_EDIT_COPY:		case IDM_EDIT_PASTE:		case IDM_EDIT_CLEAR:			MessageBeep(0);			return 0;			//The logic below assumes that IDM_WHITE through IDM_BLACK 			//are consecutive numbers in the order show here.		case IDM_BKGND_WHITE:		case IDM_BKGND_LTGRAY:		case IDM_BKGND_GRAY:		case IDM_BKGND_DKGRAY:		case IDM_BKGND_BLACK:			CheckMenuItem(hMenu, iSelection, MF_UNCHECKED);			iSelection = LOWORD(wParam);			CheckMenuItem(hMenu, iSelection, MF_CHECKED);			SetClassLong(hwnd, GCL_HBRBACKGROUND, (LONG)				GetStockObject(idColor[LOWORD(wParam) - IDM_BKGND_WHITE]));			InvalidateRect(hwnd, NULL, TRUE);			return 0;		case IDM_APP_HELP:			MessageBox(hwnd, TEXT("Help not yet implemented!"),				szAppName, MB_ICONEXCLAMATION | MB_OK);			return 0;		case IDM_APP_ABOUT:			MessageBox(hwnd, TEXT("Menu Demonstration Program\n")				TEXT("(c) Charles Petzold, 1998"),				szAppName, MB_ICONINFORMATION | MB_OK);			return 0;		}		break;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}

popmenu.rc

//Microsoft Developer Studio generated resource script.//#include "resource.h"#define APSTUDIO_READONLY_SYMBOLS///// Generated from the TEXTINCLUDE 2 resource.//#include "afxres.h"/#undef APSTUDIO_READONLY_SYMBOLS/// English (U.S.) resources#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)#ifdef _WIN32LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US#pragma code_page(1252)#endif //_WIN32#ifdef APSTUDIO_INVOKED///// TEXTINCLUDE//1 TEXTINCLUDE DISCARDABLE BEGIN    "resource.h\0"END2 TEXTINCLUDE DISCARDABLE BEGIN    "#include ""afxres.h""\r\n"    "\0"END3 TEXTINCLUDE DISCARDABLE BEGIN    "\r\n"    "\0"END#endif    // APSTUDIO_INVOKED///// Menu//POPMENU MENU DISCARDABLE BEGIN    POPUP "MyMenu"    BEGIN        POPUP "&File"        BEGIN            MENUITEM "&New",                        IDM_FILE_NEW            MENUITEM "&Open",                       IDM_FILE_OPEN            MENUITEM "&Save",                       IDM_FILE_SAVE            MENUITEM "Save &As",                    IDM_FILE_SAVE_AS            MENUITEM SEPARATOR            MENUITEM "E&xit",                       IDM_APP_EXIT        END        POPUP "&Edit"        BEGIN            MENUITEM "&Undo",                       IDM_EDIT_UNDO            MENUITEM SEPARATOR            MENUITEM "Cu&t",                        IDM_EDIT_CUT            MENUITEM "&Copy",                       IDM_EDIT_COPY            MENUITEM "&Paste",                      IDM_EDIT_PASTE            MENUITEM "De&lete",                     IDM_EDIT_CLEAR        END        POPUP "&Background"        BEGIN            MENUITEM "&White",                      IDM_BKGND_WHITE, CHECKED            MENUITEM "&Light Gray",                 IDM_BKGND_LTGRAY            MENUITEM "&Gray",                       IDM_BKGND_GRAY            MENUITEM "&Dark Gray",                  IDM_BKGND_DKGRAY            MENUITEM "&Black",                      IDM_BKGND_BLACK        END        POPUP "&Help"        BEGIN            MENUITEM "&Help...",                    IDM_APP_HELP            MENUITEM "&About PopMenu...",           IDM_APP_ABOUT        END    ENDEND#endif    // English (U.S.) resources/#ifndef APSTUDIO_INVOKED///// Generated from the TEXTINCLUDE 3 resource.///#endif    // not APSTUDIO_INVOKED

resource.h

//{  {NO_DEPENDENCIES}}// Microsoft Developer Studio generated include file.// Used by PopMenu.rc//#define IDM_FILE_NEW                    40001#define IDM_FILE_OPEN                   40002#define IDM_FILE_SAVE                   40003#define IDM_FILE_SAVE_AS                40004#define IDM_APP_EXIT                    40005#define IDM_EDIT_UNDO                   40006#define IDM_EDIT_CUT                    40007#define IDM_EDIT_COPY                   40008#define IDM_EDIT_PASTE                  40009#define IDM_EDIT_CLEAR                  40010#define IDM_BKGND_WHITE                 40011#define IDM_BKGND_LTGRAY                40012#define IDM_BKGND_GRAY                  40013#define IDM_BKGND_DKGRAY                40014#define IDM_BKGND_BLACK                 40015#define IDM_HELP_HELP                   40016#define IDM_APP_HELP                    40016#define IDM_APP_ABOUT                   40017// Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE        102#define _APS_NEXT_COMMAND_VALUE         40018#define _APS_NEXT_CONTROL_VALUE         1000#define _APS_NEXT_SYMED_VALUE           101#endif#endif

运行结果



10.2.10 使用系统菜单

包含WS_SYSMENU样式创建窗口,在标题栏左边会有一个系统该菜单。

系统菜单加入ID号必须小于0xF000. 否则会和windows标准命令的ID冲突

并且处理完WM_SYSCOMMAND消息要把其他消息传递给DefWindowProc


#include <windows.h>   LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    #define IDM_SYS_ABOUT	1#define IDM_SYS_HELP	2#define IDM_SYS_REMOVE	3static	TCHAR	szAppName[] = TEXT("PoorMenu");int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	HMENU		hMenu;	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class   	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.      	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.       	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.      	hwnd = CreateWindow(szAppName,      //Window class name      		TEXT("The Poor-Person's Menu"),      //Window caption      		WS_OVERLAPPEDWINDOW,            //Window Style      		CW_USEDEFAULT,                  //initial x position      		CW_USEDEFAULT,                  //initial y position      		CW_USEDEFAULT,                  //initial x size      		CW_USEDEFAULT,                  //initial y size      		NULL,                           //parent window handle      		NULL,                           //window menu handle      		hInstance,                      //program instance handle      		NULL);                          //creation parameters   	hMenu = GetSystemMenu(hwnd, FALSE);	AppendMenu(hMenu, MF_SEPARATOR,	0,					NULL);	AppendMenu(hMenu, MF_STRING,	IDM_SYS_ABOUT,		TEXT("About..."));	AppendMenu(hMenu, MF_STRING,	IDM_SYS_HELP,		TEXT("Help..."));	AppendMenu(hMenu, MF_STRING,	IDM_SYS_REMOVE,		TEXT("Remove Additions"));	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.      						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc      LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	switch (message) //get the message      	{	case WM_SYSCOMMAND:		switch (LOWORD(wParam))		{		case IDM_SYS_ABOUT:			MessageBox(hwnd, TEXT("Menu Demonstration Program\n")				TEXT("(c) Charles Petzold, 1998"),				szAppName, MB_ICONINFORMATION | MB_OK);			return 0;		case IDM_SYS_HELP:			MessageBox(hwnd, TEXT("Help not yet implemented!"),				szAppName, MB_ICONEXCLAMATION | MB_OK);			return 0;		case IDM_SYS_REMOVE:			GetSystemMenu(hwnd, TRUE);			return 0;		}		break;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}


GetSystemMenu(hwnd, FALSE)  表明系统菜单将要被修改


GetSystemMenu(hwnd, TRUE); 还原被修改的系统菜单


10.2.11 改变菜单

windows3.0 以前使用ChangeMenu

现在使用 

AppendMenu 在菜单末尾追加一个新菜单项

DeleteMenu 从菜单中删除已存在菜单项并销毁他

InsertMenu 像菜单中插入一个新菜单

ModifyMenu  修改一个已经存在的菜单项

RemoveMenu 从菜单中去除一个已有的菜单项


DeleteMenu 会销毁该弹出菜单而Remove不会。


10.2.12 其他菜单命令
改变一个顶级菜单以后,知道windows重绘菜单才能显示。

DrawMenuBar(hwnd) 强制重绘菜单

hwnd为窗口句柄


hMenuPopup = GetSubMenu(hMenu, iPosition);  //获得弹出菜单的句柄

iPosition为弹出菜单在顶级菜单中的索引


iCount = GetMenuItemCount(hMenu) //顶级菜单或弹出菜单中现有菜单项的数目


id = GetMenuItemID(hMenuPopup, iPosition) // 获得弹出菜单中某个菜单项的ID


CheckMenuItem(hMenu, id, iCheck); 在弹出菜单中选择和取消选择某一菜单项 MF_CHECKED 或 MF_UNCHECKED  hMenu是顶级菜单句柄


如果hMenu是弹出菜单,那么id可以使iPosition

CheckMenuItem(hMenu, iPosition, MF_CHECKED | MF_BYPOSITION);  使用索引而非ID


EnableMenuItem(hMenu, id, MF_ENABLED);

第三个参数可以是  MF_ENABLED, MF_DISABLED, MF_GRAYED.   如果在顶级菜单上使用,并且改菜单项还有子菜单。那么第三个参数必须使用MF_BYPOSITION


HiliteMenuItem       MF_HILITE   MF_UNHILITE 加亮显示 


iFlags = GetMenuString(hMenu, id, pString, iMaxCount, iFlag)   iFlag 可以使MF_BYCOMMAND 或者MF_BYPOSITION   //获得菜单项的string


iFlags = GetMenuState(hMenu, id, iFlag)   iFlag 是 MF_COMMAND 或者MF_BYPOSITION。 iFlags是当前标识的组合值

可能是 MF_CHECKED, MF_SIABLED, MF_GRAYED, MF_MENUBREAK, MF_MENUUNBREAK, MF_SEPARATOR


Destory(hMenu) 销毁菜单,使得该菜单句柄无效


10.2.13菜单的另类用法


#include <windows.h>   #include "resource.h"LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	static TCHAR	szAppName[] = TEXT("NoPopUps");	HWND			hwnd;	MSG				msg;	WNDCLASS		wndClass;       //The window Class   	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.      	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);	wndClass.lpszMenuName = NULL;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.       	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.      	hwnd = CreateWindow(szAppName,      //Window class name      		TEXT("No-Popup Nested Menu Demonstration"),      //Window caption      		WS_OVERLAPPEDWINDOW,            //Window Style      		CW_USEDEFAULT,                  //initial x position      		CW_USEDEFAULT,                  //initial y position      		CW_USEDEFAULT,                  //initial x size      		CW_USEDEFAULT,                  //initial y size      		NULL,                           //parent window handle      		NULL,                           //window menu handle      		hInstance,                      //program instance handle      		NULL);                          //creation parameters      	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.      						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		TranslateMessage(&msg);		DispatchMessage(&msg);	}	return msg.wParam;}//define the Window Procedure WndProc      LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HMENU	hMenuMain, hMenuEdit, hMenuFile;	HINSTANCE		hInstance;	switch (message) //get the message      	{	case WM_CREATE:		hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);		hMenuMain = LoadMenu(hInstance, TEXT("MenuMain"));		hMenuFile = LoadMenu(hInstance, TEXT("MenuFile"));		hMenuEdit = LoadMenu(hInstance, TEXT("MenuEdit"));				SetMenu(hwnd, hMenuMain);		return 0;	case WM_COMMAND:		switch (LOWORD(wParam))		{		case IDM_MAIN:			SetMenu(hwnd, hMenuMain);			return 0;		case IDM_FILE:			SetMenu(hwnd, hMenuFile);			return 0;		case IDM_EDIT:			SetMenu(hwnd, hMenuEdit);		case IDM_FILE_NEW:		case IDM_FILE_OPEN:		case IDM_FILE_SAVE:		case IDM_FILE_SAVE_AS:		case IDM_EDIT_UNDO:		case IDM_EDIT_CUT:		case IDM_EDIT_COPY:		case IDM_EDIT_PASTE:		case IDM_EDIT_CLEAR:			MessageBeep(0);			return 0;		}		break;	case WM_DESTROY:		SetMenu(hwnd, hMenuMain);		DestroyMenu(hMenuFile);		DestroyMenu(hMenuEdit);		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}

NOPOPUPS.rc

// Microsoft Visual C++ generated resource script.//#include "resource.h"#define APSTUDIO_READONLY_SYMBOLS///// Generated from the TEXTINCLUDE 2 resource.//#include "winres.h"/#undef APSTUDIO_READONLY_SYMBOLS/// Chinese (Simplified, PRC) resources#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED#ifdef APSTUDIO_INVOKED///// TEXTINCLUDE//1 TEXTINCLUDE BEGIN    "resource.h\0"END2 TEXTINCLUDE BEGIN    "#include ""winres.h""\r\n"    "\0"END3 TEXTINCLUDE BEGIN    "\r\n"    "\0"END#endif    // APSTUDIO_INVOKED///// Menu//MENUMAIN MENUBEGIN    MENUITEM "MAIN:",                       0, INACTIVE    MENUITEM "&File...",                    IDM_FILE    MENUITEM "&Edit...",                    IDM_EDITENDMENUFILE MENUBEGIN    MENUITEM "FILE:",                       0, INACTIVE    MENUITEM "&New",                        IDM_FILE_NEW    MENUITEM "&Open...",                    IDM_FILE_OPEN    MENUITEM "&Save",                       IDM_FILE_SAVE    MENUITEM "Save &As",                    IDM_FILE_SAVE_AS    MENUITEM "(&Main)",                     IDM_MAINENDMENUEDIT MENUBEGIN    MENUITEM "EDIT:",                       ID_EDIT, INACTIVE    MENUITEM "&Undo",                       IDM_EDIT_UNDO    MENUITEM "Cu&t",                        IDM_EDIT_CUT    MENUITEM "&Copy",                       IDM_EDIT_COPY    MENUITEM "&Paste",                      IDM_EDIT_PASTE    MENUITEM "De&lete",                     IDM_EDIT_CLEAR    MENUITEM "(&Main)",                     IDM_MAINEND#endif    // Chinese (Simplified, PRC) resources/#ifndef APSTUDIO_INVOKED///// Generated from the TEXTINCLUDE 3 resource.///#endif    // not APSTUDIO_INVOKED

resource.h

//{  {NO_DEPENDENCIES}}// Microsoft Visual C++ generated include file.// Used by nopopups.rc//#define IDM_FILE                        40001#define IDM_EDIT                        40002#define IDM_FILE_NEW                    40003#define IDM_FILE_OPEN                   40004#define IDM_FILE_SAVE                   40005#define IDM_FILE_SAVE_AS                40006#define IDM_MAIN                        40007#define IDM_EDIT_UNDO                   40008#define IDM_EDIT_CUT                    40009#define IDM_EDIT_COPY                   40010#define IDM_EDIT_PASTE                  40011#define IDM_EDIT_CLEAR                  40012#define ID_EDIT                         40013// Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE        102#define _APS_NEXT_COMMAND_VALUE         40014#define _APS_NEXT_CONTROL_VALUE         1001#define _APS_NEXT_SYMED_VALUE           101#endif#endif


运行结果



10.3 键盘加速

可以生成WM_COMMAND  或者有时候是 WM_SYSCOMMAND


10.3.1 为什么你应该使用键盘加速键

windows会把WM_COMMAND消息发送给在windows函数TranslateAccelerator中指定的窗口过程,多窗口编程中非常重要


10.3.2 指定加速键的一些原则





常见加速键 F1  帮助,  F4~F6 用在多文档界面


10.3.3 加速键表

作为一种资源加载  每个加速键有一个ID和一个击键组合

可以使虚拟代码或者ascii字符与shift, ctrl 或alt的组合。

Tab字符能把文本和加速犍分开,这样加速键会排在第二列。

可以使用文字在菜单项后面说明 例如  (Shift+F6)


10.3.4 加载加速键列表

使用LoadAccelerators 加载

HANDLE hAccel;

hAccel = LoadAccelerators(hInstance, TEXT("MyAccelerators"));

也可以使用 MAKEINTRESOURCE 使用ID, 或者使用 #数字


10.3.5  键盘按键

修改消息循环


	while (GetMessage(&msg, NULL, 0, 0))	{		if (!TranslateAccelerator(hwnd, hAccel, &msg))		{			TranslateMessage(&msg);			DispatchMessage(&msg);		}		}
TranslateAccelerator 会优先判断是否有加速键消息,然后发给对于的窗口过程

当该返回返回0,说明消息已经被翻译过,不需要再处理。继续吓一条消息


模态对话框或消息框有输入焦点时,TranslateAccelerator不翻译键盘消息,因为这些窗口的消息不通过程序的消息循环。

有些时候应用程序另一窗口拥有输入焦点时,你不想翻译键盘消息。如何处理该情况参考11章


10.3.6 接受加速键消息

对应系统菜单项发送  WM_SYSCOMMAND

否则发送WM_COMMAND

WM_COMMAND 消息

如果加速键对应某个菜单项,窗口过程还会接收到WM_INITMENU  WM_INITMENUPOPUP   和  WM_MENUSELECT

在处理WM_INITMENUPOPUP时,可以启用或禁用弹出菜单的菜单项

当一个菜单项变灰,加速键不会对其发送WM_COMMAND 或者WM_SYSOMMAND


如果窗口最小化,映射到系统菜单的键盘加速键会对窗口发送WM_SYSCOMMAND

没映射到系统菜单项的加速键,TranslateAccelerator也会想窗口过程发送WM_COMMAND消息


10.3.7 带有菜单项的POPPAD

#include <windows.h>#include "resource.h"#define ID_EDIT 1  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.    TCHAR   szAppName[] = TEXT("PopPad2");int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,	PSTR szCmdLine, int iCmdShow){	//static      TCHAR szAppName[] = TEXT("Colors1");  	HACCEL		hAccel;	HWND        hwnd;	MSG         msg;	WNDCLASS    wndClass;       //The window Class      	wndClass.style = CS_HREDRAW | CS_VREDRAW;	wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.      	wndClass.cbClsExtra = 0;	wndClass.cbWndExtra = 0;	wndClass.hInstance = hInstance;	wndClass.hIcon = LoadIcon(hInstance, szAppName);// LoadIcon(NULL, IDI_APPLICATION);	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);	wndClass.hbrBackground = CreateSolidBrush(0);//(HBRUSH)GetStockObject(WHITE_BRUSH);  	wndClass.lpszMenuName = szAppName;	wndClass.lpszClassName = szAppName;	//Register the Window Class to the Windows System.       	if (!RegisterClass(&wndClass))	{		MessageBox(NULL, TEXT("This program require Windows NT!"),			szAppName, MB_ICONERROR);		return 0;	}	//This function will generate an WM_CREATE message.      	hwnd = CreateWindow(szAppName,      //Window class name      		szAppName,      //Window caption      		WS_OVERLAPPEDWINDOW,            //Window Style      		GetSystemMetrics(SM_CXSCREEN) / 4,                  //initial x position      		GetSystemMetrics(SM_CYSCREEN) / 4,                  //initial y position      		GetSystemMetrics(SM_CXSCREEN) / 2,                  //initial x size      		GetSystemMetrics(SM_CYSCREEN) / 2,                  //initial y size      		NULL,                           //parent window handle      		NULL,                           //window menu handle      		hInstance,                      //program instance handle      		NULL);                          //creation parameters      	ShowWindow(hwnd, iCmdShow);	UpdateWindow(hwnd); //This function will generate a WM_PAINT message.      	hAccel = LoadAccelerators(hInstance, szAppName);						/* The message loop for this program.						if received the WM_QUIT message, the function will return 0.*/	while (GetMessage(&msg, NULL, 0, 0))	{		if (!TranslateAccelerator(hwnd, hAccel, &msg))		{			TranslateMessage(&msg);			DispatchMessage(&msg);		}	}	return msg.wParam;}int AskConfirmation(HWND hwnd){	return MessageBox(hwnd, TEXT("Really want to close PopPad2?"),		szAppName, MB_YESNO | MB_ICONQUESTION);}//define the Window Procedure WndProc      LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){	static HWND hwndEdit;	int			iSelect, iEnable;	switch (message) //get the message      	{	case WM_CREATE:		hwndEdit = CreateWindow(TEXT("edit"), NULL,			WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |			WS_BORDER | ES_LEFT | ES_MULTILINE |			ES_AUTOHSCROLL | ES_AUTOVSCROLL,			0, 0, 0, 0,			hwnd, (HMENU)ID_EDIT,			((LPCREATESTRUCT)lParam)->hInstance, NULL);		return 0;	case WM_SETFOCUS:		SetFocus(hwndEdit);		return 0;	case WM_SIZE:		MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);		return 0;	case WM_INITMENUPOPUP:		if (lParam == 1)		{			EnableMenuItem((HMENU)wParam, IDM_EDIT_UNDO,				SendMessage(hwndEdit, EM_CANUNDO, 0, 0) ?				MF_ENABLED : MF_GRAYED);			EnableMenuItem((HMENU)wParam, IDM_EDIT_PASTE,				IsClipboardFormatAvailable(CF_TEXT) ?				MF_ENABLED : MF_GRAYED);			iSelect = SendMessage(hwndEdit, EM_GETSEL, 0, 0);			if (HIWORD(iSelect) == LOWORD(iSelect))				iEnable = MF_GRAYED;			else				iEnable = MF_ENABLED;			EnableMenuItem((HMENU)wParam, IDM_EDIT_CUT, iEnable);			EnableMenuItem((HMENU)wParam, IDM_EDIT_COPY, iEnable);			EnableMenuItem((HMENU)wParam, IDM_EDIT_CLEAR, iEnable);		}	case WM_COMMAND:		if (lParam)		{			if (LOWORD(wParam) == ID_EDIT)				if (HIWORD(wParam) == EN_ERRSPACE ||					HIWORD(wParam) == EN_MAXTEXT)					MessageBox(hwnd, TEXT("Edit control out of spae."),						szAppName, MB_OK | MB_ICONSTOP);		}		else switch (LOWORD(wParam))		{		case IDM_FILE_NEW:		case IDM_FILE_OPEN:		case IDM_FILE_SAVE:		case IDM_FILE_SAVE_AS:		case IDM_FILE_PRINT:			MessageBeep(0);			return 0;		case IDM_APP_EXIT:			SendMessage(hwnd, WM_CLOSE, 0, 0);			return 0;		case IDM_EDIT_UNDO:			SendMessage(hwndEdit, WM_UNDO, 0, 0);			return 0;		case IDM_EDIT_CUT:			SendMessage(hwndEdit, WM_CUT, 0, 0);			return 0;		case IDM_EDIT_COPY:			SendMessage(hwndEdit, WM_COPY, 0, 0);			return 0;		case IDM_EDIT_PASTE:			SendMessage(hwndEdit, WM_PASTE, 0, 0);			return 0;		case IDM_EDIT_CLEAR:			SendMessage(hwndEdit, WM_CLEAR, 0, 0);			return 0;		case IDM_EDIT_SELECT_ALL:			SendMessage(hwndEdit, EM_SETSEL, 0, -1);			return 0;		case IDM_HELP_HELP:			MessageBox(hwnd, TEXT("Help not yet implemented!"),				szAppName, MB_ICONEXCLAMATION | MB_OK);			return 0;		case IDM_APP_ABOUT:			MessageBox(hwnd, TEXT("Menu Demonstration Program\n")				TEXT("(c) Charles Petzold, 1998"),				szAppName, MB_ICONINFORMATION | MB_OK);			return 0;		}				return 0;	case WM_CLOSE:		if (IDYES == AskConfirmation(hwnd))			DestroyWindow(hwnd);		return 0;	case WM_QUERYENDSESSION:		if (IDYES == AskConfirmation(hwnd))			return 1;		else			return 0;	case WM_DESTROY:		PostQuitMessage(0);		return 0;	}	return  DefWindowProc(hwnd, message, wParam, lParam);}

POPPAD.rc

// Microsoft Visual C++ generated resource script.//#include "resource.h"#define APSTUDIO_READONLY_SYMBOLS///// Generated from the TEXTINCLUDE 2 resource.//#include "winres.h"/#undef APSTUDIO_READONLY_SYMBOLS/// Chinese (Simplified, PRC) resources#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED#ifdef APSTUDIO_INVOKED///// TEXTINCLUDE//1 TEXTINCLUDE BEGIN    "resource.h\0"END2 TEXTINCLUDE BEGIN    "#include ""winres.h""\r\n"    "\0"END3 TEXTINCLUDE BEGIN    "\r\n"    "\0"END#endif    // APSTUDIO_INVOKED///// Menu//POPPAD2 MENUBEGIN    POPUP "&File"    BEGIN        MENUITEM "&New",                        IDM_FILE_NEW        MENUITEM "&Open...",                    IDM_FILE_OPEN        MENUITEM "&Save",                       IDM_FILE_SAVE        MENUITEM "Save &As...",                 IDM_FILE_SAVE_AS        MENUITEM SEPARATOR        MENUITEM "&Print",                      IDM_FILE_PRINT        MENUITEM SEPARATOR        MENUITEM "E&xit",                       IDM_APP_EXIT    END    POPUP "&Edit"    BEGIN        MENUITEM "&Undo\tCtrl+Z",               IDM_EDIT_UNDO        MENUITEM SEPARATOR        MENUITEM "Cu&t\tCtrl+X",                IDM_EDIT_CUT        MENUITEM "&Copy\tCtrl+C",               IDM_EDIT_COPY        MENUITEM "&Paste\tCtrl+V",              IDM_EDIT_PASTE        MENUITEM "De&lete\tDel",                IDM_EDIT_CLEAR        MENUITEM SEPARATOR        MENUITEM "&Select All",                 IDM_EDIT_SELECT_ALL    END    POPUP "&Help"    BEGIN        MENUITEM "&Help...",                    IDM_HELP_HELP        MENUITEM "&About PopPad2...",           IDM_APP_ABOUT    ENDEND///// Accelerator//POPPAD2 ACCELERATORSBEGIN    VK_DELETE,      IDM_EDIT_CLEAR,         VIRTKEY, NOINVERT    "^C",           IDM_EDIT_COPY,          ASCII,  NOINVERT    "^X",           IDM_EDIT_CUT,           ASCII,  NOINVERT    VK_DELETE,      IDM_EDIT_CUT,           VIRTKEY, SHIFT, NOINVERT    "^V",           IDM_EDIT_PASTE,         ASCII,  NOINVERT    VK_INSERT,      IDM_EDIT_PASTE,         VIRTKEY, CONTROL, NOINVERT    VK_INSERT,      IDM_EDIT_PASTE,         VIRTKEY, SHIFT, NOINVERT    "^Z",           IDM_EDIT_UNDO,          ASCII,  NOINVERT    VK_BACK,        IDM_EDIT_UNDO,          VIRTKEY, ALT, NOINVERT    VK_F1,          IDM_HELP_HELP,          VIRTKEY, NOINVERT    "^A",           IDM_EDIT_SELECT_ALL,    ASCII,  NOINVERTEND///// Icon//// Icon with lowest ID value placed first to ensure application icon// remains consistent on all systems.POPPAD2                 ICON                    "POPPAD2.ICO"#endif    // Chinese (Simplified, PRC) resources/#ifndef APSTUDIO_INVOKED///// Generated from the TEXTINCLUDE 3 resource.///#endif    // not APSTUDIO_INVOKED

resource.h

//{  {NO_DEPENDENCIES}}// Microsoft Visual C++ generated include file.// Used by poppad.rc//#define IDM_FILE_NEW                    40001#define IDM_FILE_OPEN                   40002#define IDM_FILE_SAVE                   40003#define IDM_FILE_SAVE_AS                40004#define IDM_FILE_PRINT                  40005#define IDM_APP_EXIT                    40006#define IDM_EDIT_UNDO                   40007#define IDM_EDIT_CUT                    40008#define IDM_EDIT_COPY                   40009#define IDM_EDIT_PASTE                  40010#define IDM_EDIT_CLEAR                  40011#define IDM_EDIT_SELECT_ALL             40012#define IDM_HELP_HELP                   40013#define IDM_APP_ABOUT                   40014// Next default values for new objects// #ifdef APSTUDIO_INVOKED#ifndef APSTUDIO_READONLY_SYMBOLS#define _APS_NEXT_RESOURCE_VALUE        105#define _APS_NEXT_COMMAND_VALUE         40028#define _APS_NEXT_CONTROL_VALUE         1001#define _APS_NEXT_SYMED_VALUE           101#endif#endif

10.3.8 启动菜单项

判断是否可以做undo

EnableMenuItem((HMENU)wParam, IDM_EDIT_UNDO,
SendMessage(hwndEdit, EM_CANUNDO, 0, 0) ?
MF_ENABLED : MF_GRAYED);


判断是否可以做Paste

EnableMenuItem((HMENU)wParam, IDM_EDIT_PASTE,
IsClipboardFormatAvailable(CF_TEXT) ?
MF_ENABLED : MF_GRAYED);


判断编辑框有文本被选中

iSelect = SendMessage(hwndEdit, EM_GETSEL, 0, 0);


if (HIWORD(iSelect) == LOWORD(iSelect))
iEnable = MF_GRAYED;
else
iEnable = MF_ENABLED;


10.3.9 处理菜单项


WM_CLOSE  用户关闭程序时响应


WM_QUERYENDSESSION  当用户选择关闭windows时响应

返回0 则终止操作失败

你可能感兴趣的文章
【IoT】TI BLE CC2541 串口控制蓝牙详解
查看>>
【产品】项目管理的五个过程和九大知识领域之二
查看>>
【项目管理】项目管理流程浅析
查看>>
【Tool】如何使用 Uniflash 烧写 WIFI 芯片 CC3200
查看>>
copy_{to, from}_user()的思考
查看>>
Web前端安全策略之CSRF的攻击与防御
查看>>
纯客户端页面关键字搜索高亮jQuery插件
查看>>
linux运维中常用的命令
查看>>
M1芯片的macbook安装王者荣耀,原神,崩坏方法
查看>>
Java温故而知新-反射机制
查看>>
eclipse引用sun.misc开头的类
查看>>
firefox中angular2嵌套发送请求问题
查看>>
【mybatis3】调试/断点打印日志
查看>>
C++
查看>>
[CTFSHOW]PHP特性
查看>>
navigator对象
查看>>
关于EFI系统分区(ESP)你应该知道的3件事
查看>>
5.Mybatis复杂映射开发
查看>>
Servlet2.5的增删改查功能分析与实现------删除功能(四)
查看>>
环境配置 jdk_mysql_myeclipse8.6
查看>>