本节讲述图标、鼠标指针位图、字符串资源表、自定义资源的添加和应用。
本节必须掌握的知识点:
图标
第56练:ICON图标资源
鼠标指针位图
字符串资源表
自定义资源
第57练:字符串资源表和自定义资源
9.1.1 图标
在 Windows 窗口编程中,图标(Icon)是用于表示应用程序、窗口或文件的小图像。Windows 提供了几种不同尺寸和颜色深度的图标,用于在窗口标题栏、任务栏、文件资源管理器等地方显示。
■以下是一些与图标相关的常见任务和概念:
●创建图标文件:
1.图标文件通常使用 .ico 扩展名,可以包含多个图标资源。
2.可以使用图标编辑器(如 Visual Studio、Visual Studio Code、GIMP 等)创建或编辑图标文件。
●加载和显示图标:
1.使用 LoadIcon 函数从 .ico 文件或资源中加载图标。
2.使用 DrawIcon 函数将图标绘制到设备上下文(DC)中的指定位置。
●获得图标的大小:
cxIcon = GetSystemMetrics (SM_CXICON) ;
cyIcon = GetSystemMetrics (SM_CYICON) ;
●设置窗口图标:
1.使用 WM_SETICON 消息或 SetClassLongPtr 函数设置窗口的大图标和小图标。
2.大图标通常在窗口的标题栏和任务栏中显示,小图标显示在窗口的任务栏按钮中。
●资源文件中的图标:
1.可以将图标资源添加到应用程序的资源文件(.rc)中。
2.在应用程序启动时,可以使用 LoadIcon 或 LoadIconEx 函数加载资源文件中的图标。
■在应用程序中使用图标
Windows程序可以在定义一个带有WNDCLASS结构并使用RegisterClass注册的窗口类中指定图标。当图标文件同时包含标准大小和小号图像时。在需要显示图标图像时,Windows会在图标文件中选择大小最合适的图像。
RegisterClass有一个增强版本,名为RegisterClassEx,它使用一个名为WNDCLASSEX 的结构。WNDCLASSEX结构有两个额外的字段:cbSize和blconSm。cbSize字段表示 WNDCLASSEX结构的大小,而hlconSm应该被设为小图标的句柄。因此,在WNDCLASSEX结构中你需要设定与两个图标文件相关联的两个图标句柄—— 一个是标准图标而另一个是小图标。
因为Windows可以从单个图标文件中提取了正确尺寸的图标图像。RegisterClassEx似乎没有必要。如果hlconSm字段引用的是一个包含多个图像的图标文件,那么只有第一个会被使用。这可以是一个标准尺寸的图标,只不过之后会被缩小。RegisterClassEx似乎是为使用多个图标图像设计的,这些图像每个只包含一个图标尺寸。因为可以在同一个文件中包含多个图标尺寸,所以使用 WNDCLASS 和 RegisterClass也是可以的。
如果想在程序运行时动态改变程序的图标,可以通过调用SetClassLong函数来实现。 比如,如果有另一个和标识符IDI_ALTICON 相关联的图标文件,便可以使用下面的语句 切换到那个图标:
SetClassLong (hwnd, GCL_HICON,
LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ALTICON))) ;
如果不想保存程序图标的句柄,而是使用Drawlcon函数来在某处显示它,那么你可以 调用GetClassLong函数来获得句柄。比如:
DrawIcon (hdc, x, y, GetClassLong (hwnd, GCL_HICON)) ;
在Windows文档的某些地方,LoadIcon被描述为“已过时”,而Loadlmage被推荐使 用。LoadImage当然更灵活,但它目前还无法代替Loadlcon的简洁性。你会注意到在 ICONDEMO中Loadlcon对同一图标被调用了两次。这不是个问题,不会因此有更多内存被使用。Loadlcon是少有的这样几个函数之一:它获得一个句柄,但不要求该句柄被销毁。 实际上确实存在一个DestroyIcon函数,但它是和Createlcon、Createlconlndirect以及 CreateIconFromResource配套使用的。这些函数允许程序用算法动态生成图标。
■下面是一个示例代码片段,展示了如何加载和设置窗口图标:
HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); //加载图标资源
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); //设置大图标
SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); //设置小图标
在上述示例中,hInstance 是应用程序的实例句柄,IDI_ICON1 是图标资源的 ID。可以使用资源编辑器将图标资源添加到应用程序的资源文件中,并分配一个唯一的 ID 给它。
■VS添加资源步骤:
1.选中资源文件,鼠标右键>添加>资源
图9-1 添加资源
2.点击添加后,自动生成ICONDEMO.rc和resource.h文件。选择Icon,点击新建或导入现有的Icon图标资源。
图9-2 新建或导入图标资源
3.资源视图窗口,选中已添加的资源ID_ICON1,鼠标右键选择属性或者ALT+ENTER键打开图标编辑器修改ID。
图9-3 定义图标资源属性
4.修改ico文件名和ID并保存,或者按下ALT+ENTER键修改资源属性。
图9-4 修改图标文件名和ID
9.1.2 第56练:ICON图标资源
/*------------------------------------------------------------------------
056 WIN32 API 每日一练
第56个例子ICONDEMO.C:ICON图标资源
LoadIcon 函数
MAKEINTRESOURCE宏
DrawIcon函数
按下ALT+ENTER键修改资源属性
(c) www.bcdaren.com 编程达人
-----------------------------------------------------------------------*/
#include <windows.h>
#include "resource.h" //编译器添加资源时自动创建的头文件
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName[] = TEXT("IconDemo");//程序名
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
//TCHAR szAppName[] = TEXT("IconDemo");
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(WNDCLASSEX); //新增
wndclass.hIconSm = NULL; //新增
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
//szAppName为字符串ID,对应资源中的位图ID需要修改为字符串ID"IconDemo"
// wndclass.hIcon = LoadIcon(hInstance, szAppName);
wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));//数字ID
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClassEx(&wndclass)) //RegisterClassEx
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName,
MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("Icon Demo"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
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)
{
case WM_CREATE:
hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
//hIcon = LoadIcon(hInstance,szAppName);//字符串ID
hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));//数字ID
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);
}
/******************************************************************************
LoadIcon 函数:从与应用程序实例关联的可执行(.exe)文件中加载指定的图标资源。
HICON LoadIconA(
HINSTANCE hInstance,//模块实例的句柄,其可执行文件包含要加载的图标。加载标准图标时,此参数必须为NULL。
LPCSTR lpIconName//要加载的图标资源的名称。或者,此参数可以在低位字中包含资源标识符,在高位字中包含零。
//使用MAKEINTRESOURCE宏来创建此值。
);
返回值
类型:HICON
如果函数成功,则返回值是新加载的图标的句柄。
*******************************************************************************
MAKEINTRESOURCEA宏:将整数值转换为与资源管理功能兼容的资源类型。使用此宏代替包含资源名称的字符串。
void MAKEINTRESOURCEA(
i //要转换的整数值。
);
*******************************************************************************
DrawIcon函数:将图标或光标绘制到指定的设备上下文中。若要指定其他绘图选项,请使用DrawIconEx函数。
BOOL DrawIcon(
HDC hDC, //设备上下文的句柄,将在其中绘制图标或光标。
int X, //图标左上角的逻辑x坐标。
int Y, //图标左上角的逻辑y坐标。
HICON hIcon //要绘制的图标的句柄。
);
*/
●Resource文件:
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 056_ICONDEMO.rc 使用
//
#define IDI_ICON1 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
●056_ICONDEMO.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
/
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "icon1.ico"
#endif // 中文(简体,中国) resources
/
#ifndef APSTUDIO_INVOKED
/
//
// Generated from the TEXTINCLUDE 3 resource.
//
/
#endif // not APSTUDIO_INVOKED
运行结果:
图9-5 图标资源
总结
实例ICONDEMO.C添加了一个图标资源,并且在窗口客户区内填充图标位图。图标位图文件icon1.ico位于当前编译目录。
添加图标资源的方法在上一小节中已经讲述,在解决方案的“资源文件”目录下点击鼠标右键,选择添加>资源>ICON,导入icon1.ico位图文件。然后VS自动创建re’source资源头文件和056_ICONDEMO.rc资源脚本文件。re’source资源头文件中包含图标资源的数字ID 101,056_ICONDEMO.rc资源脚本文件的资源类型为ICON,将图标资源ID绑定图标位图文件:
IDI_ICON1 ICON "icon1.ico"
实例的WinMain主程序中,定义了一个扩展窗口类WNDCLASSEX,对比WNDCLASS结构新增了“cbSize”结构大小字段和“hIconSm”小图标字段。在hIcon字段添加图标:
wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));//数字ID
【注意】由于添加图标资源时使用的是数字ID,所以这里需要使用MAKEINTRESOURCE宏将IDI_ICON1转换为字符串ID。
请读者测试:如果我们将资源中的图标位图ID修改为字符串ID"IconDemo",则不需要转换:
wndclass.hIcon = LoadIcon(hInstance, szAppName);
窗口过程:
处理WM_CREATE消息:调用LoadIcon函数加载图标资源,获取图标资源句柄。然后调用GetSystemMetrics函数获取图标资源尺寸。
处理WM_SIZE消息:获取窗口客户区宽和高。
处理WM_PAINT消息:调用DrawIcon函数在窗口客户区内填充图标。