10.3 键盘加速键

来源:互联网 发布:mac漫画软件 编辑:程序博客网 时间:2024/05/16 09:52

摘录于《Windows程序(第5版,珍藏版).CHarles.Petzold 著》P373

        键盘加速键是可以生成 WM_COMMAND(或者有时是 WM_SYSCOMMAND)消息的组合键。通常,程序使用键盘加速键来复制公共菜单选项的动作,但它们也可以执行非菜单功能。例如,某些 Windows 程序有一个含有 Delete 或 Clear 选项的 Edit 菜单;这些程序通常指定 Del 键作为这个选项的键盘加速键。用户可以按 Alt 组合键从菜单中选择 Delete 选项,也可以简单地按 Del 键来使用键盘加速键。当窗口过程接收到 WM_COMMAND 消息时,它不需要检测该命令是来自于键盘加速键。

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

        你可能会问:为什么我应该使用键盘加速键?为什么我不能捕捉 WM_KEYDOWN 或 WM_CHAR 消息并自己复制菜单功能?它有什么优点?对一个单窗口程序,你当然可以捕捉键盘消息。但是使用键盘加速键的一个简单优点是,你不需要重写菜单和键盘加速键处理逻辑

        对有多个窗口和窗口过程的应用程序,键盘加速键变得十分重要。正如我们所见,对拥有当前输入焦点的窗口,Windows 会将键盘消息发送给它的窗口过程。然而,对键盘加速键而言,Windows 会将 WM_COMMAND 消息发送给一个句柄在 Windows 函数 TranslateAccelerator 中指定的窗口过程。通常,这会是你的主窗口,亦即拥有菜单的那个窗口,这意味着响应键盘加速键的逻辑不需要被复制到每一个窗口过程

        如果你使用非模态对话框(在第 11 章讨论)或在主窗口的客户区内使用子窗口,这个优点就变得极其重要。如果给多个窗口定义了同一个键盘加速键,只需在其中一个窗口包含这个逻辑即可。子窗口不会接收到来自键盘加速键的 WM_COMMAND 消息

10.3.2  指定加速键的一些规则

        理论上,你可以使用几乎任何虚拟键或字符键与 Shift 键、Ctrl 键或 Alt 键的组合来定义键盘加速键。然而,你应该试图和其他应用程序保持一致,以避免干扰 Windows 对键盘的使用。你应该避免使用Tab回车键Esc空格键作为键盘加速键,因为它们通常保留给系统功能

        系统加速键最通常的用途是用于程序中 Edit 菜单的菜单项。对这些菜单项推荐使用的键盘加速键在 Windows 3.0 和 Windows 3.1 之间有变化,因此同时支持新旧两种加速键很常见,如下表所示:

功  能旧加速键新加速键 Undo(撤销) Alt+Backspace Ctrl+Z Cut(剪切) Shift+Del Ctrl+X  Copy(复制) Ctrl+Ins Ctrl+C Paste(粘贴) Shift+Ins Ctrl+V Delete 或 Clear(删除) Del Del        另一个很常见的加速键是 F1 功能键,它用来激活帮助。应该避免使用 F4、F5 和 F6 键,因为它们经常被多文档界面(Multiple Document Interface, MDI)程序用作特殊功能,我们会在第 19 章中讨论 MDI。

10.3.3  加速键表

        你可以在 Developer Studio 中定义加速键表。为了方便在你的程序中加载加速键表,可以使它与应用程序同名(这也适用于菜单和图标)。

        每个加速键有一个 ID 和一个击键组合,这些你可以在 Accelerator Properties 对话框中定义。如果你已经定义了菜单,Aidan DI 会存在与组合框中,你不需要重新输入它们。

        加速键可以是虚拟键代码或 ASCII 字符与 Shift、Ctrl 或 Alt 键的组合。你可以在字母前加^来指定 ASCII 字符与 Ctrl 键的组合。你也可以从组合框中选择虚拟键代码。

        在为菜单项定义键盘加速键时,应当在菜单文本中包含相应的键组合。Tab 字符(\t)能将文本和加速键分开,这样加速键会排列在第二列。为了在菜单中标识加速键,可以使用文字 Ctrl、Shift 或 Alt,后面跟着一个加号和键名(例如 Shift+F6 或 Ctrl+F6)。

10.3.4  加载加速键表

        在应用程序中,应使用 LoadAccelerators 函数来把加速键表加载到内存并获得它的句柄。LoadAccelerators 语句和 LoadIcon、LoadCursor 及 LoadMenu 语句很相似。

        首先用类型 HANDLE 定义一个加速键表的句柄:

HANDLE hAccel;
然后加载加速键表:

hAccel = LoadAccelerators (hInstance, TEXT("MyAccelerators"));
和图标、鼠标指针及菜单一样,你也可以用数字来命名加速键表,然后在 LoadAccelerators 中通过 MAKEINTRESOURCE 宏来使用该数字,或者将数字用引号括起来并加上前缀#字符。

10.3.5  翻译按键

        我们现在要改动三行代码,这三行代码是本书迄今为止对所有 Windows 程序都通用的。这三行代码就是标准消息循环:

while (GetMessage (&msg, NULL, 0, 0)){    TranslateMessage (&msg);    DispatchMessage (&msg);}

        下面显示我们如何改变它来使用键盘加速键表:

while (GetMessage (&msg, NULL, 0, 0)){    if (!TranslateAccelerator (hwnd, hAccel, &msg))    {<pre name="code" class="cpp">        TranslateMessage (&msg);        DispatchMessage (&msg);
}}

TranslateAccelerator 函数确定保存在 msg 消息结构中的消息是否是键盘消息。如果是,该函数在加速键表中寻找句柄为 hAccel 的匹配值。如果找到匹配值,它会调用句柄为 hwnd 的窗口过程。如果键盘加速键 ID 对应系统菜单的一个菜单项,则相应消息为 WM_SYSCOMMAND;否则,消息是 WM_COMMAND。

        当 TranslateAccelerator 返回时,如果消息被翻译过(并且已被发送给窗口过程),则返回值为非零值,否则返回值为零。如果 TranslateAccelerator 返回非零值,你就不应该再调用 TranslateMessage 和 DispatchMessage,而是应该返回 GetMessage 循环。

        TranslateAccelerator 中的 hwnd 参数看起来不太合适,因为消息循环中的三个函数都不需要它。并且,消息结构自身(结构变量 msg)有一个名字为 hwnd 的成员,它也是一个窗口句柄。

        这个函数之所以有些不同的原因是:msg 结构的字段是由 GetMessage 调用来填充的。当 GetMessage 的第二个参数是 NULL 时,它检索属于该应用程序的所有窗口的消息。当 GetMessage 返回时,msg 结构的 hwnd 成员是将会得到该消息的窗口句柄。然而,当 TranslateAccelerator 将键盘消息翻译成 WM_COMMAND 或 WM_SYSCOMMAND 消息时,它将 msg.hwnd 窗口句柄替换成该函数的第一个参数所指定的窗口句柄。于是 Windows 会将所有键盘加速键消息发送给同一个窗口,即使程序中另外一个窗口当前拥有输入焦点。模态对话框消息框拥有输入焦点时,TranslateAccelerator 不翻译键盘消息,因为这些窗口的消息不通过程序的消息循环

        某些情况下,当应用程序中另一个窗口(比如非模态对话框)拥有输入焦点时,你并不想翻译键盘消息。如何处理这种情况将在第 11 章介绍。

10.3.6  接收加速键消息

        当一个键盘加速键对应系统菜单的一个菜单项时,TranslateAccelerator 会向窗口过程发送一条 WM_SYSCOMMAND 消息;否则,TranslateAccelerator 向窗口过程发送一条 WM_COMMAND 消息。下表列出了对于键盘加速键、菜单命令和子窗口控件你会接收到的 WM_COMMAND 消息的类型:

 加 速 键菜  单控  件 LOWORD(wParam) 加速键 ID 菜单 ID 控件 ID HIWORD(wParam) 1 0 通知码 lParam 0 0 子窗口句柄        如果键盘加速键对应某个菜单项,那么窗口过程还会接收到 WM_INITMENU,WM_INITMENUPOPU 和 WM_MENUSELECT 消息,就像菜单项被选择了一样。在处理 WM_INITMENUPOPUP 时,程序通常可以启用或禁用弹出菜单的菜单项。使用键盘加速键时,你仍然拥有这种机制。当一个键盘加速键对应一个禁用或变灰的菜单项时,TranslateAccelerator 不会向窗口过程发送 WM_COMMAND 或 WM_SYSCOMMAND 消息。

        如果当前窗口被最小化,对于映射到启用的系统菜单项的键盘加速键,TranslateAccelerator 将向窗口过程发送 WM_SYSCOMMAND 消息而不是 WM_COMMAND 消息。对于没有映射到任何菜单项的加速键,TranslateAccelerator 也会向窗口过程发送 WM_COMMAND 消息。

10.3.7  带有菜单和加速键的 POPPAD 程序

        在第 9 章,我们创建了 POPPAD1 程序,它使用一个子窗口编辑空间来实现了一个简单的记事本(notepad)。在本章,我们将加入 File 和 Edit 菜单,并相应将程序称为 POPPAD2。Edit 中菜单项都能功能;File 菜单功能我们会在第 11 章实现,Print 功能在第 13 章实现。POPPAD2 程序如图 10-11 所示。

/*--------------------------------------------------------POPPAD2.C --   Popup Editor Version 2 (includes menu)      (c) Charles Petzold, 1998--------------------------------------------------------*/#include <windows.h>#include "resource.h"#define ID_EDIT 1LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);TCHAR szAppName[] = TEXT("PopPad2");int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow){HACCEL hAccel;HWND         hwnd;MSG          msg;WNDCLASS     wndclass;wndclass.style = CS_HREDRAW | CS_VREDRAW;wndclass.lpfnWndProc = WndProc;wndclass.cbClsExtra = 0;wndclass.cbWndExtra = 0;wndclass.hInstance = hInstance;wndclass.hIcon = LoadIcon(hInstance, szAppName);wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);wndclass.lpszMenuName = szAppName;wndclass.lpszClassName = szAppName;if (!RegisterClass(&wndclass)){MessageBox(NULL, TEXT("This program requires Windows NT!"),szAppName, MB_ICONERROR);return 0;}hwnd = CreateWindow(szAppName, szAppName,WS_OVERLAPPEDWINDOW,GetSystemMetrics(SM_CXSCREEN) / 4, GetSystemMetrics(SM_CYSCREEN) / 4,GetSystemMetrics(SM_CXSCREEN) / 2,GetSystemMetrics(SM_CYSCREEN) / 2,NULL, NULL, hInstance, NULL);hAccel = LoadAccelerators(hInstance, szAppName);ShowWindow(hwnd, iCmdShow);UpdateWindow(hwnd);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);}LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){static HWND hwndEidt;intiSelect, iEnable;switch (message){case WM_CREATE:hwndEidt = 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(hwndEidt);return 0;case WM_SIZE:MoveWindow(hwndEidt, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);return 0;case WM_INITMENUPOPUP:if (lParam == 1){EnableMenuItem((HMENU)wParam, IDM_EDIT_UNDO,SendMessage(hwndEidt, EM_CANUNDO, 0, 0) ? MF_ENABLED : MF_GRAYED);EnableMenuItem((HMENU)wParam, IDM_EDIT_PASTE,IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED);iSelect = SendMessage(hwndEidt, 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);return 0;}break;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 space."),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(hwndEidt, WM_UNDO, 0, 0);return 0;case IDM_EDIT_CUT:SendMessage(hwndEidt, WM_CUT, 0, 0);return 0;case IDM_EDIT_COPY:SendMessage(hwndEidt, WM_COPY, 0, 0);return 0;case IDM_EDIT_PASTE:SendMessage(hwndEidt, WM_PASTE, 0, 0);return 0;case IDM_EDIT_CLEAR:SendMessage(hwndEidt, WM_CLEAR, 0, 0);return 0;case IDM_EDIT_SELECT_ALL:SendMessage(hwndEidt, EM_SETSEL, 0, -1);return 0;case IDM_APP_HELP:MessageBox(hwnd, TEXT("Help not yet implemented!"),szAppName, MB_OK | MB_ICONEXCLAMATION);return 0;case IDM_APP_ABOUT:MessageBox(hwnd, TEXT("POPPAD2 (c) Charles Petzold, 1998"),szAppName, MB_OK | MB_ICONINFORMATION);return 0;}break;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);}
POPPAD2.RC (excerpts)// Microsoft Visual C++ generated resource script.//#include "resource.h"///////////////////////////////////////////////////////////////////////////////// Icon//POPPAD2                 ICON                    "POPPAD2.ICO"///////////////////////////////////////////////////////////////////////////////// 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_APP_HELP        MENUITEM "&About PopPad2...",           IDM_APP_ABOUT    ENDEND///////////////////////////////////////////////////////////////////////////////// Accelerator//POPPAD2 ACCELERATORSBEGIN    VK_BACK,        IDM_EDIT_UNDO,          VIRTKEY, ALT, NOINVERT    VK_DELETE,      IDM_EDIT_CLEAR,         VIRTKEY, NOINVERT    VK_DELETE,      IDM_EDIT_CUT,           VIRTKEY, SHIFT, NOINVERT    VK_F1,          IDM_APP_HELP,           VIRTKEY, NOINVERT    VK_INSERT,      IDM_EDIT_PASTE,         VIRTKEY, CONTROL, NOINVERT    VK_INSERT,      IDM_EDIT_PASTE,         VIRTKEY, SHIFT, NOINVERT    "^C",           IDM_EDIT_COPY,          ASCII,  NOINVERT    "^V",           IDM_EDIT_PASTE,         ASCII,  NOINVERT    "^X",           IDM_EDIT_CUT,           ASCII,  NOINVERT    "^Z",           IDM_EDIT_UNDO,          ASCII,  NOINVERTEND
RESOURCE.H (excerpts)// Microsoft Visual C++ 生成的包含文件。// 供 PopPad2.rc 使用//#define IDR_ACCELERATOR1                102#define IDI_ICON1                       104#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_APP_HELP                    40013#define IDM_APP_ABOUT                   40014
POPPAD2.ICO

        POPPAD2.RC 资源脚本文件包含菜单和加速键表。你会注意到,加速键都在 Edit 弹出菜单的字符串中指定,并跟随\t字符之后。

10.3.8  启用菜单项

        窗口过程的主要任务现在包括了启用和变灰 Edit 菜单中的菜单项,这是在处理 WM_INITMENUPOPUP 消息时完成的。首先,程序检查 Edit 弹出菜单是否将要被显示。由于 Edit 在菜单中的位置索引是 1(开始的 File 菜单项为 0),所以如果 Edit 弹出菜单将要被显示,lParam 将等于 1。

        为了检查 Undo 菜单项是否可以被启用,POPPAD2 发送 EM_CANUNDO 消息给编辑控件。如果编辑控件可以执行 Undo 操作,SendMessage 会返回非零值,这时该选项被启用;否则,该选项变灰:

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

        只有当剪贴板当前包含文本时,Paste 菜单项才应该被启用。我们可以调用 IsClipboardFormatAvailable 并传递 CF_TEXT 标识符来检测:

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

        只有在编辑控件中有文本被选中时,Cut、Copy 和 Delete 选项才应该被启用。向编辑控件发送 EM_GETSEL 消息会返回一个包含该信息的整数值:

iSelect = SendMessage(hwndEdit, EM_GETSEL, 0, 0);
iSelect 的低位字是第一个被选中字符的位置,高位字是紧随选中文本后面的第一个字符的位置。如果这两个字相等,则表明没有文本被选中:

if (HIWORD(iSelect) == LOWORD(iSelect))    iEnable = MF_GRAYED;else    iEnable = MF_ENABLED;
iEnable 的值随后可以用于 Cut、Copy 和 Delete 菜单项:

EnableMenuItem((HMENU)wParam, IDM_EDIT_CUT, iEnable);EnableMenuItem((HMENU)wParam, IDM_EDIT_COPY, iEnable);EnableMenuItem((HMENU)wParam, IDM_EDIT_CLEAR, iEnable);

10.3.9  处理菜单项

        当然,如果我们没有在 POPPAD2 中使用子窗口编辑控件,我们将面临一个问题,也就是说要具体实现 Edit 菜单中的 Undo、Cut、Copy、Paste、Clear 和 Select All 菜单。但是编辑控件简化了这个过程,因为我们只需要对应每一个菜单项向编辑控件发送一个消息:

case IDM_EDIT_UNDO:SendMessage(hwndEidt, WM_UNDO, 0, 0);return 0;case IDM_EDIT_CUT:SendMessage(hwndEidt, WM_CUT, 0, 0);return 0;case IDM_EDIT_COPY:SendMessage(hwndEidt, WM_COPY, 0, 0);return 0;case IDM_EDIT_PASTE:SendMessage(hwndEidt, WM_PASTE, 0, 0);return 0;case IDM_EDIT_CLEAR:SendMessage(hwndEidt, WM_CLEAR, 0, 0);return 0;case IDM_EDIT_SELECT_ALL:SendMessage(hwndEidt, EM_SETSEL, 0, -1);return 0;

        请注意,我们可以进一步简化这个过程,即让 IDM_EDIT_UNDO、IDM_EDIT_CUT 等的值等于相对应的窗口消息 WM_UNDO、WM_CUT 等的值,以此类推。

        File 弹出菜单中的 About 菜单项引发一个简单的消息框:

case IDM_APP_ABOUT:MessageBox(hwnd, TEXT("POPPAD2 (c) Charles Petzold, 1998"),szAppName, MB_OK | MB_ICONINFORMATION);return 0;
在第 11 章中,我们会把它变成一个对话框。当你从该菜单中选择 Help 菜单项或按键盘加速键 F1 时,也会引发一个消息框。

        Exit 菜单项向窗口过程发送一条 WM_CLOSE 消息:

case IDM_APP_EXIT:SendMessage(hwnd, WM_CLOSE, 0, 0);return 0;
这正是 DefWindowProc 收到 wParam 为 SC_CLOSE 的 WM_SYSCOMMAND 消息时所作出的反应。

        在以前的程序中,我们没有在窗口过程中处理 WM_CLOSE 消息,而是简单地将它传递给 DefWindowProc。DefWindowProc 对 WM_CLOSE 只简单地做了一件事:调用 DestroyWindow 函数。POPPAD2 则对 WM_CLOSE 消息进行了处理,而不是将它发送给 DefWindowProc。(这个事实现在不是很重要,但在第 11 章中当 POPPAD 能真正地编辑文件时,将变得非常重要。)

case WM_CLOSE:    if (IDYES == AskConfirmation(hwnd))DestroyWindow(hwnd);return 0;
AskConfirmation 是 POPPAD2 中的一个函数,它显示一个消息框,要求用户对关闭程序进行确认:

int AskConfirmation (HWND hwnd){return MessageBox(hwnd, TEXT("Really want to close PopPad2?"),szAppName, MB_YESNO | MB_ICONQUESTION);}
当 Yes 按钮被选中时,消息框(以及 AskConfirmation 函数)返回 IDYES。只有这时 POPPAD2 才调用 DestroyWindow。否则,这个程序不会终止。

        如果想再结束程序前得到确认,还必须处理 WM_QUERYENDSESSION 消息。当用户选择关闭 Windows 时,Windows 开始向每一个窗口过程发送 WM_QUERYENDSESSION 消息。如果有任何一个窗口过程对此消息返回 0,Windows 将不会被终止。下面的代码显示了如何处理 WM_QUERYENDSESSION 消息:

case WM_QUERYENDSESSION:    if (IDYES == AskConfirmation(hwnd))return 1;    elsereturn 0;

        如果想要在结束程序之前获得用户的认可,WM_CLOSE 和 WM_QUERYENDSESSION 消息是唯一两个必须要处理的消息。这就是为什么我们让 POPPAD2 中的 Exit 菜单项向窗口过程发送 WM_CLOSE 的原因。这样,我们避免了在第三处的确认。

        如果要处理 WM_QUERYENDSESSION 消息,那么你可能也会对 WM_ENDSESSION 敢兴趣。Windows 向每一个曾接收过 WM_QUERYENDSESSION 消息的窗口发送此消息。如果由于其他程序从 WM_QUERYENDSESSION 消息返回 0 而导致终止操作失败,wParam 将被设为 0。WM_ENDSESSION 消息本质上回答了这样一个问题:我告诉 Windows 可以终止我,但是我真的被终止了吗

        虽然我在 POPPAD2 的 File 菜单中包含了常见的 New、Open、Save 和 Save As 等菜单项,但它们当前并不坐任何事情。要处理这些命令,我们需要使用对话框。现在你已经准备好了,开始学习第 11 章,研究对话框吧!

0 0
原创粉丝点击