
本文共 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
//{ {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, 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 则终止操作失败
发表评论
最新留言
关于作者
