《Windows程序设计》读书笔十 菜单和其他资源
来源:互联网 发布:floyd算法 路径 编辑:程序博客网 时间:2024/05/20 18:53
第十章 菜单和资源
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 HICONhIcon;static intcxIcon, cyIcon, cxClient, cyClient;HDChdc;HINSTANCEhInstance;PAINTSTRUCTps;intx, 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 HGLOBALhResource;static HWNDhScroll;static intiPosition, cxChar, cyChar, cyClient, iNumLines, xScroll;HDChdc;PAINTSTRUCTps;RECTrect;TEXTMETRICtm;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_TIMER1LRESULT 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 intidColor[5] = {WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH, DKGRAY_BRUSH, BLACK_BRUSH};static intiSelection = IDM_BKGND_WHITE;HMENUhMenu;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
//{{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. HINSTANCEhInst;TCHARszAppName[] = 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 HMENUhMenu;static intidColor[5] = { WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,DKGRAY_BRUSH, BLACK_BRUSH };static intiSelection = IDM_BKGND_WHITE;POINTpoint;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_ABOUT1#define IDM_SYS_HELP2#define IDM_SYS_REMOVE3staticTCHARszAppName[] = TEXT("PoorMenu");int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow){HMENUhMenu;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, 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 TCHARszAppName[] = TEXT("NoPopUps");HWNDhwnd;MSGmsg;WNDCLASSwndClass; //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 HMENUhMenuMain, hMenuEdit, hMenuFile;HINSTANCEhInstance;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"); HACCELhAccel;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;intiSelect, 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;elseiEnable = 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;elsereturn 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 则终止操作失败
- 《Windows程序设计》读书笔十 菜单和其他资源
- Windows 程序设计 (菜单及其它资源)
- Windows程序设计-菜单及其它资源
- 第十章 菜单和其他资源
- 第 10 章 菜单和其他资源
- 《Windows程序设计》读书笔二 Unicode简介
- 《Windows程序设计》读书笔四 文本输出
- 《Windows程序设计》读书笔五 绘图基础
- 《Windows程序设计》读书笔六 键盘
- 《Windows程序设计》读书笔七 鼠标
- 《Windows程序设计》读书笔八 计时器
- 《Windows程序设计》读书笔十一 对话框
- 《Windows程序设计》读书笔十二 剪贴板
- Windows程序设计学习笔记(五)——菜单资源和加速键的使用
- 菜单和其他资源(2)之创建自己的菜单
- Windows程序设计 第十章 菜单资源类文件
- 《Windows程序设计》读书笔二十 多任务和多线程
- 《Windows程序设计》读书笔三 窗口与消息
- 判断单链表是否含环
- Mysql常见sql
- 【usaco 2013 feb Bronze】信息传递
- 以下是C++的不同数据类型值的比较语句,请问这些判断语句中作为条件部分的语句编写有问题的有:
- 什么是html5
- 《Windows程序设计》读书笔十 菜单和其他资源
- 网络框架-volley
- 7.2 相关向量机
- sql中的触发器
- Longest Valid Parentheses
- 句子逆序
- 阿里云反欺诈——风险识别
- 【python学习笔记】函数式编程:返回函数
- Flask总结(二):URL映射