《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


resource.h


//{{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, FALSE)  表明系统菜单将要被修改


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 则终止操作失败

0 0
原创粉丝点击