浅墨浓香

想要天亮进城,就得天黑赶路。

导航

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

Posted on 2015-07-22 20:12  浅墨浓香  阅读(430)  评论(0编辑  收藏  举报
10.3.1 为什么要使用键盘加速键?——发送WM_COMMAND\WM_SYSCOMMAND消息。

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

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

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

10.3.2 加速键表

(1)加速键

ID

击键组合

1、可自定义ID

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

①虚拟键+Shift\Ctrl\Alt组合

②ASCII字符+Shift\Ctrl\Alt组合如^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_COMMAND\WM_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);

  ③Cut\Copy\Delete只有在文本被选中时,才启用

    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\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
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\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
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