第十章 菜单和资源
windows通过LoadIcon LoadCursor等函数来加载资源
图标
鼠标指针
字符串
自定义资源
菜单
键盘加速键
对话框
位图
10.1 图标,鼠标指针,字符串和自定义资源
10.1.1 向程序添加图标
Tools->Options->Build->Export makefile when saving project file.
导出mak文件
注:该方法在VS2015中已经不可用。VS2015需要自己写makefile或者使用makefile project来生成mak文件,然后使用nmake编译文件。
nmake的配置方法参考
http://www.cnblogs.com/cvbnm/articles/1954872.html
源代码
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("IconDemo");
HWND hwnd;
MSG msg;
WNDCLASS wndClass; //The window Class
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));//LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szAppName;
//Register the Window Class to the Windows System.
if (!RegisterClass(&wndClass))
{
MessageBox(NULL, TEXT("This program require Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
//This function will generate an WM_CREATE message.
hwnd = CreateWindow(szAppName, //Window class name
TEXT("Icon Demo"), //Window caption
WS_OVERLAPPEDWINDOW, //Window Style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); //This function will generate a WM_PAINT message.
/* The message loop for this program.
if received the WM_QUIT message, the function will return 0.*/
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//define the Window Procedure WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HICON hIcon;
static int cxIcon, cyIcon, cxClient, cyClient;
HDC hdc;
HINSTANCE hInstance;
PAINTSTRUCT ps;
int x, y;
switch (message) //get the message
{
case WM_CREATE:
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
cxIcon = GetSystemMetrics(SM_CXICON);
cyIcon = GetSystemMetrics(SM_CYICON);
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
for (y = 0; y < cyClient; y += cyIcon)
for (x = 0; x < cxClient; x += cxIcon)
DrawIcon(hdc, x, y, hIcon);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
这段代码不能够直接编译
还需要创建资源文件,使用AddItem来增加icondemo.rc文件,VS会自动创建Resource.h头文件。
使用Resource Editor中的Add Resource 添加图标资源
原书中的图标是32x32的,在VS2015和Win7时代已经支持256x256的超大图标了
同时将ICON的ID改为IDI_ICON
然后可以编译程序了
运行结果
SM_CXICON 和SM_CYICON 为32x32
更小的图标是 SM_CXSMSIZE 和 SM_CYSMSIZE
10.1.2 获得图标的句柄
hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
#define MAKEINTRESOURCE (i) (LPTSTR) ((DWORD)((WORD)(i)))
资源ID也可以直接使用字符串
10.3.3 在应用程序中使用图标
RegisterClassEx 使用 WNDCLASSEX结构
有额外字段
ebSize 表示WNDCLASSEX结构大小
hIconSm 应该设定为小图标的句柄。
因此你需要设定两个图标句柄, 一个标准一个是小
在程序运行时改变图标,使用 SetClassLong函数实现。
SetClassLong(hwnd, GCL_HICON, LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ALTICON));
不想保存图标句柄可以使用一下函数
DrawIcon(hdc, x, y, GetClassLong(hwnd, GCL_HICON));
hIcon 是特例 生成的句柄不需要手动销毁,
10.1.4 使用自定义鼠标指针
和图标类似,在资源编辑器中添加指针
然后
wndclass.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_CURSOR));
或者用文本名字来定义鼠标指针
当鼠标在基于此类创建的窗口上,自定义的鼠标指针就会显示出来。
更改子窗口的hCursor字段
SetClassLong(hwndChild, GCL_HCURSOR, LoadCursor(hInstance, TEXT("childcursor"));
也可以使用SetCursor(hCursor); 来设定鼠标指针
应该在WM_MOUSEMOVE时调用SetCursor 否则一旦移动鼠标指针windows会重绘鼠标指针
10.1.5 字符串资源
使用资源管理器新建String Table
使用LoadString 来加载字符串
LoadString(hInstance, id, szBuffer, iMaxLength); 支持c语言的格式设置符号
所有字符串表都是以Unicode格式保持,LoadStringW直接加载Unicode文本, LoadStringA则会进行代码页转换
10.1.6 自定义资源
hResource = LoadResource(hInstance, FindResource(hInstance, MAKEINTRESOURCE(IDR_BINTYPE), TEXT("BINTYPE")));
需要访问文本时
pData = LockResource(hResource);
使用完以后释放
FreeResource(hResource);
一个使用图标,字符串和自定义资源的例子
poepoem.cpp
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //window procedure.
HINSTANCE hInst;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[16], szCaption[64], szErrMsg[64];
HWND hwnd;
MSG msg;
WNDCLASS wndClass; //The window Class
hInst = hInstance;
LoadString(hInstance, IDS_APPNAME, szAppName, sizeof(szAppName) / sizeof(TCHAR));
LoadString(hInstance, IDS_CAPTION, szCaption, sizeof(szCaption) / sizeof(TCHAR));
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;// assign the window procedure to windows class.
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(hInstance, szAppName);//LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szAppName;
//Register the Window Class to the Windows System.
if (!RegisterClass(&wndClass))
{
//Support the ANSI encode.
LoadStringA(hInstance, IDS_APPNAME, (char*)szAppName, sizeof(szAppName));
LoadStringA(hInstance, IDS_ERRMSG, (char*)szErrMsg, sizeof(szErrMsg));
MessageBoxA(NULL, (char *)szErrMsg,
(char *)szAppName, MB_ICONERROR);
return 0;
}
//This function will generate an WM_CREATE message.
hwnd = CreateWindow(szAppName, //Window class name
szCaption, //Window caption
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, //Window Style
CW_USEDEFAULT, //initial x position
CW_USEDEFAULT, //initial y position
CW_USEDEFAULT, //initial x size
CW_USEDEFAULT, //initial y size
NULL, //parent window handle
NULL, //window menu handle
hInstance, //program instance handle
NULL); //creation parameters
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd); //This function will generate a WM_PAINT message.
/* The message loop for this program.
if received the WM_QUIT message, the function will return 0.*/
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
//define the Window Procedure WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static char* pText;
static HGLOBAL hResource;
static HWND hScroll;
static int iPosition, cxChar, cyChar, cyClient, iNumLines, xScroll;
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
TEXTMETRIC tm;
int ilength;
switch (message) //get the message
{
case WM_CREATE:
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC(hwnd, hdc);
xScroll = GetSystemMetrics(SM_CXVSCROLL);
hScroll = CreateWindow(TEXT("scrollbar"), NULL,
WS_CHILD | WS_VISIBLE | SBS_VERT,
0, 0, 0, 0,
hwnd, (HMENU)1, hInst, NULL);
hResource = LoadResource(hInst, FindResource(hInst, TEXT("AnnabelLee"),
TEXT("TEXT")));
pText = (char *)LockResource(hResource);
iNumLines = 0;
while (*pText != TEXT('\\') && *pText != TEXT('\0'))
{
if (*pText == TEXT('\n'))
iNumLines++;
pText = AnsiNext(pText);
}
//*pText = TEXT('\0');
SetScrollRange(hScroll, SB_CTL, 0, iNumLines, FALSE);
SetScrollPos(hScroll, SB_CTL, 0, FALSE);
return 0;
case WM_SIZE:
MoveWindow(hScroll, LOWORD(lParam) - xScroll, 0,
xScroll, cyClient = HIWORD(lParam), TRUE);
SetFocus(hwnd);
return 0;
case WM_SETFOCUS:
SetFocus(hScroll);
return 0;
case WM_VSCROLL:
switch (wParam)
{
case SB_TOP:
iPosition = 0;
break;
case SB_BOTTOM:
iPosition = iNumLines;
break;
case SB_LINEUP:
iPosition -= 1;
break;
case SB_LINEDOWN:
iPosition += 1;
break;
case SB_PAGEUP:
iPosition -= cyClient / cyChar;
break;
case SB_PAGEDOWN:
iPosition += cyClient / cyChar;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
iPosition = LOWORD(lParam);
break;
}
iPosition = max(0, min(iPosition, iNumLines));
if (iPosition != GetScrollPos(hScroll, SB_CTL))
{
SetScrollPos(hScroll, SB_CTL, iPosition, TRUE);
InvalidateRect(hwnd, NULL, TRUE);
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
pText = (char*)LockResource(hResource);
GetClientRect(hwnd, &rect);
rect.left += cxChar;
rect.top += cyChar * (1 - iPosition);
DrawTextA(hdc, pText, -1, &rect, DT_EXTERNALLEADING);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
FreeResource(hResource);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
poepoem.rc
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/
#undef APSTUDIO_READONLY_SYMBOLS
/
// Chinese (Simplified, PRC) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
#ifdef APSTUDIO_INVOKED
/
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3