在 windows 应用程序中有几种不同类型的资源,如加速键,位图,光标,对话框,菜单,工具条和字符串等。在最初的 API 编程阶段,程序员可以用文本编辑器来编写资源脚本,这种方式比较灵活,但代码量很大。
在 Winodws 的可执行文件中,资源是独立于代码的,使用单独的 Resource Compiler 来编译,并嵌入到可执行文件中。在编程过程中,代码是可重用的,资源文件也可重用的,通过资源的“导入”和“导出”功能来实现资源的可复用。此外,程序的国际化也是通过资源来实现的。
术语“资源文件”可以指若干文件类型,包括:
· 程序的资源脚本 (.rc) 文件。
· 资源模板 (.rct) 文件。
· 作为独立文件存在的个别资源,如从 .rc 文件引用的位图、图标或光标文件。
· 由开发环境生成的头文件(如 Resource.h),它从 .rc 文件中引用。
其他类型的文件(如 .exe 、 .dll 和 .res 文件)中也可以作为资源。
资源的操作一般过程为:资源的创建,在资源文件中定义,资源的加载等。
不同类型的资源定义方式不太相同,一般都是使用一种“描述”类的语言来说明该资源的各种属性。资源通过 ID 号来进行标识, ID 是资源名,用以标识特定和资源,应用程序也是通过 ID 来加载指定的资源。一般使用一个 1~65535 之间的整数来表示。
图标资源
一个图标就是代表一个应用程序的特殊最小位图。在图标上双击鼠标就可以执行该应用程序。
1. 图标的创建
用户可以使用系统提供的默认图标也可以自定义扩展名为 ico 的文件。
系统提供的一些图标标识为:
IDI_APPLICATION 默认图标
IDI_QUESTION 问号图标
IDI_EXCLAMATION 惊叹号图标
2. 在资源文件中定义图标
其形式如下: 图标名 ICON 图标文件名( .ico )
3. 加载图标
在应用程序中通过 LoadIcon 函数加载图标 , 此过程常在定义窗口类时进行 , 如:
wndClass.hIcon = LoadIcon(hInst, lpszIconName);
位图资源
对于绘画或照片一类位图数据量一般都较大,因此为了提高显示刷新速度,位图操作必须在内存中进行。因此程序首先要通过 CreateCompatibleDC 向系统申请内在设备环境。
与其它资源的加载类似,位图也可以使用 LoadBitmap 函数来加载,并使用 BitBlt 函数来进行输出。
BOOL BitBlt
(
HDC hdcDest, // 目地设备环境
int nXDest, int nYDest, // 目地设备显示位图的基点
int nWidth, int nHeight, // 显示区域的高宽
HDC hdcSrc, // 源设备环境
int nXSrc, int nYSrc, // 源设备中位图的左上角坐标
DWORD dwRop // 位图的显示方式
)
菜单
1. 定义菜单
定义形式为:
ID MENU [ 载入特性选项 ]
{
菜单项列表
}
其中菜单项列表用于说明菜单的各个组成部分。
2. 加载菜单
一般的 Windows 程序中加载菜单有三种方法:
(1) 在窗口类中加载
(2) 在创建窗口时加载 ( CreateWindow 函数)
(3) 动态加载
获得菜单句柄后通过 SetMenu 动态地加载菜单,以提高程序灵活性。
3. 菜单项操作
(1) 禁止或激活菜单项
(2) 设置或取消选中标志
(3) 增加菜单项
(4) 删除菜单项
(5) 修改菜单项
菜单项里方法较,不一一罗列出来,需要可以参见 MSDN 。
加速键
加速键是经常与菜单一同使用的资源,通过加速键可以使程序使用起来更加方便快捷。
1. 资源定义
加速键格式为:
加速键名 ACCELERATORS ID [ 类型 ] [NOINVERT] [ALT] [SHIFT] [CONTROL]
后面的一些可选项表示加速键的组合方式。
2. 加载
通过 LoadAccelerators 即可加载定义好的加速键
3. 翻译加速键
想要加速键产生效果还必须响应加速键按下后产生的消息,翻译加速键的工作一般在应用程序的消息循环中进行。
TranslateAccelerator 函数是翻译过程的核心,它对照加速键表将 WM_KEYDOWN 和 WM_KEYUP 翻译成 WM_COMMAND 和 WM_SYSCOMMAND 消息。
应用示例
这次使用资源脚本(rc文件)和resource.h头文件来描述程序里的资源,头文件内容如下:
#define IDM_OPEN 1000
#define IDM_CLOSE 1001
#define IDM_EXIT 1002
#define IDM_ABOUT 1003
#define IDM_PIC1 1004
#define IDM_PIC2 1005
资源脚本其实是一个可以用文本编辑器打开的文本文件,不过为了方便一般都使用VS提供的可视化工具。这里为了了解资源定义
加载的原理,使用了手工编写的方式。
VSICON ICON res\vs.ico
PIC1 BITMAP res\pic1.bmp
PIC2 BITMAP res\pic2.bmp
MENUOPEN MENU MOVEABLE
BEGIN
POPUP " 文件(&F) "
BEGIN
MENUITEM " 打开(&O) " , IDM_OPEN // 虽可以直接定义数字ID,但由于数字没有字面意义
MENUITEM " 关闭(&C) " , IDM_CLOSE // 故一般不使用这种方式,而使用define方式
MENUITEM SEPARATOR
MENUITEM " 退出(&X) " , IDM_EXIT
END
POPUP " 关于(&A) "
BEGIN
MENUITEM " 关于程序 " , IDM_ABOUT
END
END
MENUPIC MENU MOVEABLE
BEGIN
POPUP " 位图 "
BEGIN
MENUITEM " 位图一 " , IDM_PIC1
MENUITEM " 位图二 " , IDM_PIC2
END
END
部分是定义了一系列的菜单资源。
在这次的程序里。程序把一个图标资源加载为最后生成程序的图标(不用再使用原来那种恶心的默认图标了),程序加载了一个文件
菜单,里面有“打开”和“关闭”两项。打开按下后,动态产生一个新的菜单组,按下里面的菜单项选择在用户区显示两个位图。
wndClass.hIcon = LoadIcon(NULL, " VSICON " ); // 加载一个程序图标vs.ico
wndClass.lpszMenuName = " MENUOPEN " ; // 加载程序菜单
// 然后是全局定义变量
HDC hdc, hdcMem;
HBITMAP hBmp;
BITMAP bmp;
HMENU hmenu, haddMenu;
HINSTANCE hCurInst; // 当前应用程序句柄
// 最后程序的消息处理函数作为结束
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg,
UINT wParam,
LONG lParam)
{
PAINTSTRUCT ps;
switch(iMsg)
{
case WM_CREATE://获取设备环境
hdc = GetDC(hWnd);
hdcMem = CreateCompatibleDC(hdc);
break;
case WM_COMMAND://处理菜单消息
switch (LOWORD(wParam))
{
case IDM_OPEN://处理打开菜单按下的消息
hmenu = GetMenu(hWnd);//获取主菜单句柄
haddMenu = CreateMenu();//创建动态菜单
//动态增加菜单中项
AppendMenu(haddMenu, MF_ENABLED, IDM_PIC1, "位图一");
AppendMenu(haddMenu, MF_ENABLED, IDM_PIC2, "位图二");
//将创建的菜单插入到主菜单中
InsertMenu(hmenu, 1, MF_POPUP|MF_BYPOSITION
, (UINT)haddMenu, "打开图片");
//相应改变“文件”菜单中相关菜单项属性
EnableMenuItem(hmenu, IDM_OPEN, MF_GRAYED);//打开菜单变灰不可用
EnableMenuItem(hmenu, IDM_CLOSE, MF_ENABLED);//关闭菜单变可用
DrawMenuBar(hWnd);//重新显示窗口菜单
break;
case IDM_CLOSE://关闭菜单消息
DeleteMenu(hmenu, 1, MF_BYPOSITION);//删除加入的菜单项
//相应改变“文件”菜单中相关菜单项属性
EnableMenuItem(hmenu, IDM_OPEN, MF_ENABLED);//打开变可用
EnableMenuItem(hmenu, IDM_CLOSE, MF_GRAYED);//关闭变不可用
DrawMenuBar(hWnd);
break;
case IDM_PIC1://在用户区加入一个位图并进行显示
SelectObject(hdc, (HPEN)GetStockObject(WHITE_PEN));
Rectangle(hdc, 0,0, 1000, 1000);
hBmp = LoadBitmap(hCurInst, "PIC1");
GetObject(hBmp, sizeof(BITMAP), (LPVOID)&bmp);//获取位图尺寸
SelectObject(hdcMem, hBmp);
BitBlt(GetDC(hWnd), 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMem, 0, 0, SRCCOPY);
EnableMenuItem(hmenu, IDM_PIC1, MF_GRAYED);//位图二变不可用
EnableMenuItem(hmenu, IDM_PIC2, MF_ENABLED);
break;
case IDM_PIC2://显示图片二
SelectObject(hdc, (HPEN)GetStockObject(WHITE_PEN));
Rectangle(hdc, 0,0, 1000, 1000);
hBmp = LoadBitmap(hCurInst, "PIC2");
GetObject(hBmp, sizeof(BITMAP), (LPVOID)&bmp);//获取位图尺寸
SelectObject(hdcMem, hBmp);
BitBlt(GetDC(hWnd), 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMem, 0, 0, SRCCOPY);
EnableMenuItem(hmenu, IDM_PIC2, MF_GRAYED);//位图一变不可用
EnableMenuItem(hmenu, IDM_PIC1, MF_ENABLED);
break;
case IDM_EXIT://退出被按下,发送一个WM_DESTROY消息退出程序
SendMessage(hWnd, WM_DESTROY, 0, 0);
break;
default:
break;
}
break;
case WM_DESTROY://在窗口退出后释放所有资源
DeleteObject(hBmp);
ReleaseDC(hWnd, hdc);
DeleteDC(hdcMem);
PostQuitMessage(0);
return 0;
default:
return (DefWindowProc(hWnd, iMsg, wParam, lParam));
}
return 0;
}