0.前言
我想通过编写一个完整的游戏程序方式引导读者体验程序设计的全过程。我将采用多种方式编写具有相同效果的应用程序,并通过不同方式形成的代码和实现方法的对比来理解程序开发更深层的知识。
了解我编写教程的思路,请参阅体现我最初想法的那篇文章中的“1.编程计划”:
学习编程从游戏开始 - lexyao - 博客园
这是一篇专题文章,这篇文章是用来讲解下面这篇文章用到的知识的,我在这篇文章中讲解程序使用的例子就是在下面这篇文章中创建的aTetris项目:
在CodeBolcks+Windows API下的C++编程教程——用向导创建一个Windows GUI项目(aTetris) - lexyao - 博客园
在这篇文章里,我主要讲述以下几个方面的内容:
- 在Windows GUI应用程序中使用图标
- 给Win32 GUI程序的主窗口界面添加一个图标
- Windows API中使用图标的函数
- 将资源文件中的图标添加到Win32 GUI程序的主窗口界面
- 使用向导新建一个资源文件添加到Win32 GUI程序(aTetris)
- 在资源文件中添加图标资源
- 结束语
1.在Windows GUI应用程序中使用图标
使用智能手机的人对图标都很熟悉,使用电脑的人对图标也很熟悉。
那么,现在提问一个问题:你知道图标是怎么添加上去的吗?
在Windows操作系统中,图标的来源有两种情况:
- 操作系统提供的图标。这种图标在操作系统的资源文件里,任何应用程序都可以使用它。
- 用户自己提供的图标。这种图标保存在用户自己的文件里,由用户自己管理。
现在我们先来看一下我们的应用程序里是怎么使用图标的。
在Code Blocks中打开aTetris项目,在aTetrisMain.cpp文件中找到以下代码:
int WINAPI WinMain (HINSTANCE hThisInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow)
{....../* The class is registered, let's create the program*/hwnd = CreateWindowEx (......
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
......);......
}
这两行代码的作用是:
- wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);设置窗口的大图标
- wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);设置窗口的小图标
其中,LoadIcon是加载图标的Windows API函数,IDI_APPLICATION是用来指定图标的标识符。
2.给Win32 GUI程序的主窗口界面添加一个图标
右键菜单中选择“Find declaration of 'IDI_APPLICATION'”,在winuser.h文件中找到以下代码:
#ifndef NOICONS
#ifdef RC_INVOKED
#define IDI_APPLICATION 32512
#define IDI_HAND 32513
#define IDI_QUESTION 32514
#define IDI_EXCLAMATION 32515
#define IDI_ASTERISK 32516
#define IDI_WINLOGO 32517
#if WINVER >= 0x0600
#define IDI_SHIELD 32518
#endif
#else
#define IDI_APPLICATION MAKEINTRESOURCE(32512)
#define IDI_HAND MAKEINTRESOURCE(32513)
#define IDI_QUESTION MAKEINTRESOURCE(32514)
#define IDI_EXCLAMATION MAKEINTRESOURCE(32515)
#define IDI_ASTERISK MAKEINTRESOURCE(32516)
#define IDI_WINLOGO MAKEINTRESOURCE(32517)
#if WINVER >= 0x0600
#define IDI_SHIELD MAKEINTRESOURCE (32518)
#endif
#endif
#define IDI_WARNING IDI_EXCLAMATION
#define IDI_ERROR IDI_HAND
#define IDI_INFORMATION IDI_ASTERISK
#endif
这就是定义操作系统提供的图标标识符的代码,其中就有IDI_APPLICATION。
- 尝试使用这些代码中定义的以IDI_开头的任何一个标识符代替aTetrisMain.cpp文件中的IDI_APPLICATION,然后编译运行aTetris项目,查看任务栏和主窗口左上角的图标是不是发生变化了?
- 尝试让大图标和小图标使用不同的IDI_标识符,然后编译运行aTetris项目,查看任务栏和主窗口左上角的图标是不是发生变化了?
做了这个测试,是不是就已经明白怎样设置应用程序的图标了?
3.Windows API中使用图标的函数
百度一下“LoadIcon”,你会找到LoadIcon的说明(以下是复制的搜索到的内容):
从与应用程序实例关联的可执行 (.exe) 文件加载指定的图标资源。
备注
此函数已被 LoadImage 函数 (取代,) 设置了 LR_DEFAULTSIZE 和 LR_SHARED 标志。
语法
HICON LoadIconA([in, optional] HINSTANCE hInstance,[in] LPCSTR lpIconName );
参数
[in, optional] hInstance
类型: HINSTANCE
DLL 或可执行文件的模块的句柄, (.exe) 包含要加载的图标的文件。 有关详细信息,请参阅 GetModuleHandle。
若要加载预定义的系统图标,请将此参数设置为 NULL。
[in] lpIconName
类型: LPCTSTR
如果 hInstance 为非 NULL, 则 lpIconName 按名称或序号指定图标资源。 必须使用 MAKEINTRESOURCE 宏打包此序号。
如果 hInstance 为 NULL, 则 lpIconName 将指定标识符 (从要加载的预定义系统图标的 IDI_前缀) 开始 。
返回值
类型: HICON
如果函数成功,则返回值是新加载图标的句柄。
如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。
注解
仅当图标资源尚未加载时,LoadIcon 才会加载该资源;否则,它将检索现有资源的句柄。 函数在图标资源中搜索最适合当前显示的图标。 图标资源可以是颜色或单色位图。
LoadIcon 只能加载大小符合 SM_CXICON 和 SM_CYICON 系统指标值的图标。 使用 LoadImage 函数加载其他大小的图标。
4.将资源文件中的图标添加到Win32 GUI程序的主窗口界面
在CodeBlocks文件列表中右击项目名称aTetris,从弹出菜单中选择[Add files...],选择xTetris.rc,然后[打开]。
这样,aTetris项目就增加了一个资源文件xTetris.rc。我们应该还记得,xTetris.rc是xTetris项目的资源文件,这里我们只是借用一下。
按着上面LoadIcon函数的说明,我们修改aTetrisMain.cpp文件中使用图标的代码:
int WINAPI WinMain (HINSTANCE hThisInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow) {....../* The class is registered, let's create the program*/hwnd = CreateWindowEx (......
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (hThisInstance, _T("aaaa"));//wincl.hIcon = LoadIcon (NULL, );
wincl.hIconSm = LoadIcon (hThisInstance, _T("aaaa"));//wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
......);...... }
代码中可以看到,原来的IDI_APPLICATION标识符换成了资源文件中给图标文件定义的标识符_T("aaaa")。
由于使用的是aTetris的资源文件中的图标而不是操作系统的图标,所以LoadIcon函数的参数中的NULL换成了hThisInstance,这是WinMain的参数中传递来到一个值。
编译运行aTetris项目,发现aTetris项目运行后的图标变成了跟xTetris一样的图标,也就是资源文件xTetris.rc的图标。
是不是说这样就算是完成了呢?
不要高兴得太早,我们被一种假象迷惑了。
为什么这么说呢?
其实aTetris使用的不是xTetris.rc的图标,而是xTetris项目编译时使用xTetris.rc生成的xTetris.res文件中的图标。之所以出现这种现象,是为因为CodeBlocks为了节省时间,发现在上次生成xTetris.res之后xTetris.rc没有再被修改,就直接使用了xTetris.res。
是不是这样的情况呢?看了下面的内容你就会知道原因了。
我们选择先把xTetris.rc从aTetris项目中移除,再开始下面的操作。
5.使用向导新建一个资源文件添加到Win32 GUI程序(aTetris)
要想为自己的应用程序定制一个图标,首先要给自己的应用程序添加一个资源文件。
添加资源文件的操作步骤如下:
第一步、点击主菜单:[File->New->File...],打开[New from template]窗口
第二步、在[New from template]窗口中选择“Files->Empty file->Go”,启动新建文件向导
第三步、输入文件名
点击文件名栏目后面的[...]按钮选择保存文件的位置,输入文件名,然后点击[保存],得到全路径文件名。
我们要添加的资源文件是D:\CodeBlocks\Test\Tetris\aTetris.rc。注意文件扩展名是rc。
这里必须是全路径文件名,否则会因为找不到路径而无法创建文件。
界面中还有几个选项,需要全部选中。
最后点击[Finish]按钮完成操作。
这时你会发现文件列表中增加了一个一个新文件aTetris.rc。打开这个文件,里面是空的。
6.在资源文件中添加图标资源
打开xTetris.rc文件,将其中的内容全部复制到aTetris.rc文件中,aTetris项目就有了与xTetris一样的资源文件。
aaaa ICON "wx/msw/std.ico" #include "wx/msw/wx.rc"
aTetris.rc文件的内容是新添加的,现在还没有生成aTetris.res文件,这样我们编译运行aTetris项目,看结果是怎么样的。
以下是编译失败给出的错误信息:
编译器找不到aTetris.rc中所指的两个文件。
为什么会这样呢?这是因为aTetris项目是Win32 GUI项目,不是wxWidgets项目,所以在编译aTetris项目的时候没有使用变量wxWidgets的配置文件,也就不知道路径wx/msw/在哪里了。
我们找到std.ico文件,将它的全路径加入到aTetris.rc文件中,然后编译运行aTetris项目,结果会怎么样呢?这次是成功了,aTetris的应用程序显示了与xTetris一样的图标。
aaaa ICON "D:/CodeBlocks/wxWidgets-3.2.6/include/wx/msw/std.ico"
如果感兴趣,你可以更换其他的图标文件测试一下,看是不是显示了你的图标。
如果你觉得使用全路径文件名太长,你也可以将图标文件复制到aTetris项目源代码所在的文件夹下,这样在资源文件中你只需要使用文件名,而不需要路径了。
另外还需要说明的是,这里使用的图标的标识符是字符串,我们用LoadIcon (hThisInstance, _T("aaaa"))装入图标。
如果你使用的标识符是数字2222,则需要改成这样的形式装入图标:LoadIcon (hThisInstance, MAKEINTRESOURCE (2222))。
这个数字你可以在头文件中为它定义一个标识符。定义的方法在下一篇文章讲到头文件的时候再进一步说明。
7.结束语
现在流行的各种操作系统已经抛弃了命令行的界面,图标成了必不可少的一个界面元素。有些应用程的的图标成了特有的标志性的元素。有了图标的使用,让用户再使用的时候便于识别,既方便又美观。
在这一篇文章里介绍了给应用程序添加图标的方法。当然,这种介绍并不全面,要了解更多的相关知识,还需要查看官方的资料。
还有一点要说的,CodeBlocks是追求跨平台的,而这篇文章介绍的是使用Windows API的实现方式,适用范围限制在的Windows操作系统,放弃了跨平台的能力。
这篇文章初步介绍了以下内容,看起来每一节都是知识点:
- 在Windows GUI应用程序中使用图标
- 给Win32 GUI程序的主窗口界面添加一个图标
- Windows API中使用图标的函数
- 将资源文件中的图标添加到Win32 GUI程序的主窗口界面
- 使用向导新建一个资源文件添加到Win32 GUI程序(aTetris)
- 在资源文件中添加图标资源