• 第10章 菜单及其它资源_10.3 键盘加速键


    10.3.1 为什么要使用键盘加速键?——发送WM_COMMANDWM_SYSCOMMAND消息。

      ①对于单个窗口应用程序可以直接捕获WM_KEYDOWN或WM_SYSKEYDOWN消息。

    ②对于多窗口的应用程序,因为键盘消息只能发给具有输入焦点的窗口。但使用键盘加速键却可以让Windows通过TranslateAccelerator函数将WM_COMMANDWM_SYSCOMMAND消息发送给特定的窗口过程。

    ③如果多窗口定义了同一个键盘加速键,可以在主窗口处理这个逻辑,可以不必复制到每个子窗口过程中去。

    10.3.2 加速键表

    (1)加速键

    ID

    击键组合

    1、可自定义ID

    2、与菜单绑定——输入菜单ID

    ①虚拟键+ShiftCtrlAlt组合

    ②ASCII字符+ShiftCtrlAlt组合如^C与Ctrl组合。

               

    (2)加载加速键表

      ①HANDLE hAccel =LoadAccelerators(hInstance,TEXT(“MyAccelerators”));

    ②HANDLE hAccel =LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1));

    ③HANDLE hAccel = LoadAccelerators(hInstance,TEXT(“#40001”));

    (3)翻译加速键

    标准消息循环

    使用键盘加速键表

    while (GetMessage (&msg, NULL, 0, 0))

    {

    TranslateMessage (&msg) ;

    DispatchMessage (&msg) ;

    }

    while (GetMessage (&msg, NULL, 0, 0))

    {

    if(!TranslateAccelerator(hwnd,hAccel,&msg)

    {

    TranslateMessage (&msg) ;

    DispatchMessage (&msg) ;

    }

    }

    ①TranslateAccelerator检查msg是否是键盘消息,如果是在hAccel中去进行加速键的匹配。找到匹配后会向窗口hwnd发送WM_COMMAND或WM_SYSCOMMAND消息。

    ②为什么消息结构中有个hwnd字段,TranslateAccelerator的参数中也有hwnd?理由如下:

    A、msg是由GetMessage填充的,当第2个参数为NULL时,检索所有窗口的消息,GetMessage返回时,msg.hwnd是得到该消息的窗口句柄(焦点窗口)。

    B、经过TranslateAccelerator将键盘消息翻译成WM_COMMANDWM_SYSCOMMAND消息后,消息并不一定要在焦点窗口(msg.hwnd)中处理。如在多窗口程序中,加速键的处理可能会放在同一个主窗口过程处理。所以可以将消息重新发送到参数hwnd指定的窗口进行处理。

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

    (4)接收加速键消息:WM_COMMAND、WM_SYSCOMMAND(加速键对应系统菜单项时发送)

    参数

    加速键

    菜单

    控件

    LOWORD(wParam)

    加速键ID

    菜单ID

    控件ID

    HIWORD(wParam)

    1

    0

    通知码

    lParam

    0

    0

    子窗口句柄

    说明:

    ①如果键盘加速键对应某菜单项时,会发送WM_INITMENU、WM_INITMENUPOPUP、WM_MENUSELECT消息。可以处理启用或禁用弹出菜单的菜单项逻辑。同时,如果该菜单项禁用或变灰,则不会发送WM_COMMAND或WM_SYSCOMMAND消息

    ②对没有映射到任何菜单项的加速键,TranslateAccelerator也会发送WM_COMMAND消息。

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

    (1)启用菜单项——处理WM_INITMENUPOPUP消息

    参数

    说明

    wParam

    下拉菜单或弹出菜单句柄

    lParam

    LOWORD(lParam):菜单位置相对索引值

    HIWORD(lParam):系统菜单标记

    (2)菜单属性设置

    ①撤消(UNDO)菜单设置——向编控件查询EM_CANUNDO是否可以撤消

       EnableMenuItem(wParam,IDM_UNDO,

                     SendMessage(hwndEdit,EM_CANUNDO,0,0)?MF_ENABLED:MF_GRAYED);

    ②粘贴(Paste)设置——当剪贴板包含文本,才被启用。检测剪贴板是否CF_TEXT格式

       EnableMenuItem(wParam,IDM_PASTE,

    IsClipboardFormatAvailable(CF_TEXT)?MF_ENABLED:MF_GRAYED);

      ③CutCopyDelete只有在文本被选中时,才启用

        iSelect = SendMessage(hwndEdit,EM_GETSEL,0,0); //向编辑框发送EM_GETSEL查询

           LOWORD(iSelect):第1个被选中的字符

           HIWORD(iSelect):结束位置,选中文本后面的第一个字符。

        if(LOWORD(iSelect) == HIWORD(iSelect)) //说明文本没被选中

      

    (2)处理菜单项——WM_CLOSE和WM_QUERYENDSESSION

     ①WM_CLOSE:用户选择关闭窗口里,发送的

     ②WM_QUERYENDSESSION消息

    Windows在关机的时候会想(向)所有顶层窗口广播一个消息WM_QUERYENDSESSION,其lParam参数可以区分是关机还是注销用户(注销用 户时lParam是ENDSESSION_LOGOFF)。然后Windows会等到所有的应用程序都对这个消息返回TRUE才会关机,因此,只要我们的应用程序对这个消息的处理返回FALSE,Windows就不会关机了。

    【PopPad2程序】

     

    /*------------------------------------------------------------
    POPPAD2.C -- Popup Editor Version2 (includes menu)
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    #include <windows.h>
    #include "resource.h"
    #define ID_EDIT 1
    static TCHAR szAppName[] = TEXT("PopPad2");
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    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(NULL, 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,                  // window class name
            TEXT("edit"), // 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);
    
        hAccel = LoadAccelerators(hInstance, szAppName);
        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 hwndEdit;
        int iSelect, iEnable;
        switch (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_INITMENUPOPUP: //lParam:item position and indicator
            if (lParam == 1) //Edit菜单
            {
                //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;
                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))//加速键ID或菜单ID,这里两个ID相等
                {
                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 implement!"),
                        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_SIZE:
            MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
            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;
            return 0;
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    //resource.h

    //{{NO_DEPENDENCIES}}
    // Microsoft Visual C++ 生成的包含文件。
    // 供 PopPad2.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         40043
    #define _APS_NEXT_CONTROL_VALUE         1001
    #define _APS_NEXT_SYMED_VALUE           101
    #endif
    #endif

    //PopPad2.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
    /////////////////////////////////////////////////////////////////////////////
    // 中文(简体,中国) 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"
    END
    2 TEXTINCLUDE
    BEGIN
    "#include ""winres.h""
    "
    ""
    END
    3 TEXTINCLUDE
    BEGIN
    "
    "
    ""
    END
    #endif    // APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Menu
    //
    POPPAD2 MENU
    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 "&Print", IDM_FILE_PRINT
    MENUITEM SEPARATOR
    MENUITEM "E&xit", IDM_APP_EXIT
    END
    POPUP "&Edit"
    BEGIN
    MENUITEM "&Undo	Ctrl+Z", IDM_EDIT_UNDO
    MENUITEM SEPARATOR
    MENUITEM "Cu&t	Ctrl+X", IDM_EDIT_CUT
    MENUITEM "&Copy	Ctrl+C", IDM_EDIT_COPY
    MENUITEM "&Paste	Ctrl+V", IDM_EDIT_PASTE
    MENUITEM "De&lete	Del", 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
    END
    END
    /////////////////////////////////////////////////////////////////////////////
    //
    // Icon
    //
    // Icon with lowest ID value placed first to ensure application icon
    // remains consistent on all systems.
    POPPAD2                 ICON                    "POPPAD2.ICO"
    /////////////////////////////////////////////////////////////////////////////
    //
    // Accelerator
    //
    POPPAD2 ACCELERATORS
    BEGIN
    VK_DELETE, IDM_EDIT_CLEAR, VIRTKEY, NOINVERT
    VK_INSERT, IDM_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
    VK_DELETE, IDM_EDIT_CUT, VIRTKEY, SHIFT, NOINVERT
    VK_INSERT, IDM_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT
    VK_BACK, IDM_EDIT_UNDO, VIRTKEY, ALT, NOINVERT
    VK_F1, IDM_HELP_HELP, VIRTKEY, NOINVERT
    "^C", IDM_EDIT_COPY, ASCII, NOINVERT
    "^V", IDM_EDIT_PASTE, ASCII, NOINVERT
    "^X", IDM_EDIT_CUT, ASCII, NOINVERT
    "^Z", IDM_EDIT_UNDO, ASCII, NOINVERT
    END
    #endif    // 中文(简体,中国) resources
    /////////////////////////////////////////////////////////////////////////////
    #ifndef APSTUDIO_INVOKED
    /////////////////////////////////////////////////////////////////////////////
    //
    // Generated from the TEXTINCLUDE 3 resource.
    //
    /////////////////////////////////////////////////////////////////////////////
    #endif    // not APSTUDIO_INVOKED
  • 相关阅读:
    LeetCode12: 整数转罗马数字
    LeetCode11:盛最多水的容器
    LeetCode09:判断回文数
    LeetCode08:字符串转换成整数
    LeetCode04:寻找中位数
    LeetCode03:无重复字符的最长子串
    《JAVA编程思想》第四版 PDF 下载 中文版和英文版 高清PDF扫描带书签
    XML
    异常
    委托和匿名方法和Lambda表达式
  • 原文地址:https://www.cnblogs.com/5iedu/p/4668498.html
Copyright © 2020-2023  润新知