Win32SDK应用程序→窗口标题栏上显示自定义图标

本篇想通过手动直接编辑代码的方式(而不是可视化的方式)来操作使用自定义的图标。(以在窗口标题栏上显示自定义图标为例)

     通过本篇,你将知道如何使用图标资源及实质,并有助于你理解在可视化方式编辑使用图标资源过程中的代码实质。

     另外,可以触类旁通,明白VC中的Window应用程序对各种类似资源(如光标资源、位图资源、声音资源等)操作的一般机制。

一 开始我们的思考:程序所要用到的各类图像、声音等资源应放在什么地方为好?

     一个程序可能需要使用各种图像、声音。那么,你认为应把这些东西放在什么地方呢?

     一种很显然的做法:就是让这些图形、图像、声音仍以文件形式(如.bmp .jpg .ico .cur .wav等等扩展名的文件,)保存在磁盘中,不包含在应用程序(.exe)中。当我的.exe程序执行时需要这些文件时再把它们从磁盘中加载到内存里并对它们操作。

     如果你是想写一个看图软件或播放音乐之类的软件,这当然是一种最佳的做法啦。但是,有时候你的程序可能要显示一个代表你程序的图像等等的情况。由于前述的方法中,图形、图像、声音是以独立的文件形式,所以软件的使用者是很容易就改动及删除它们的,唉!我可不希望这样啊!

     那么,还有什么办法呢?

     还有一种可以想到的做法:就是让这些图形、图像、声音等数据在编译时就把它们编译进.exe文件中。

     显然,由于程序要用到的各种图像、声音等的数据已经包含在.exe里面了,这样,软件使用者只要拥有这个.exe文件就可以。同时使用者要想改动程序所用的这些图形、图像、声音也就不是那么容易。

     啊!exe程序文件里居然也能存储各种类型图像、声音!嗯,这可是Windows的一个设计目标:可执行程序里不仅只含有程序代码,还可以存储各种图像、声音等的数据呢!也可能第一次让你有了这个念头!但不管怎么说,程序是可以这样设计的!

     好了,那么又如何创建一个包含有图标资源并使用这个图标的.exe文件呢?

二 图像、声音资源操作的一般步骤。

1 显然,你得先创建一个自己想要的图标(提示:这里我以图标为例)

     但具体应如何做呢?

     这个问题好解决也好理解:我们只要用一个能编辑图标的图形图像软件就可以啦。制做完图标后,把它们以.ico文件的形式(.ico 是图标文件的扩展名)保存在磁盘的某个文件夹中。

     当然啦,VC本身也提供了一个图标编辑器。

2 然后你要给这个图标定义一个字符串ID或者整数ID

     为什么要给它定义一个字符串ID或整数ID呢?

     那是因为这个图标是要被编译链接进可执行程序中(即.exe文件,当然也可能是.dll文件),这样程序就不能通过文件名来访问该图标了。

     所以,我们就得给这个图标定义一个字符串ID或整数ID了,用以代表这个图标。(你可以选择使用字符串ID,也可以使用整数ID。)

     这个定义是写在一个叫资源脚本文件(扩展名为 .rc)里的。

     当然,还要记住把.rc文件加入工程。
3 使用图标第一步:通过ID号加载图标

     请先想想前面两部做了什么?前面两步产生了一个图标并定义了一个图标ID。这样我们的程序就可以使用这个图标了:程序首先通过以下这个API函数:

     HICON   LoadIcon ( HINSTANCE hInstance,   LPCSTR lpIconName);

     来加载图标。

     暂略第一个参数,先来说一下第二个参数LPCSTR lpIconName。该参数是代表要加载图标的字符串ID。

     加载成功后,返回系统分配给该图标的一个句柄值(类型是HICON)。

     (该函数具体的使用,后面还会有介绍。)

4 加载后,程序都是通过图标句柄来操作该图标

     有了图标句柄值,就可以通过这个值来操作相应的图标了。(还记得“句柄”这个概念及作用吗?Window系统总是通过句柄来操作已加载到内存的某个对象。)

5 最后,我们的程序都编好后,只要把资源与程序代码一起编译到.exe文件中

     VC会自动用一个专门的资源编译器会把.rc文件及相关的资源文件(*.ico、*.bmp、*.wav等)编译生成一个扩展名为.res的二进制中间文件。然后再用连接程序与程序代码的二进制中间文件一同连接成可执行程序了。

     这看上去比较复杂。不用害怕啊!其实你只要按原来的方式编译连接就行了。


     到此,最好重新浏览一下上述1~5的步骤,并多加体会这个操作流程。

     现在头脑有了概念没有啊?有,那就开始动手吧!(注意:本篇中我是用手动编辑代码的方式来完成的。)

三 具体实现范例:本例为图标定义一个字符串ID(注意:不是整数ID)

     任务:在窗口标题栏上显示一个自定义的图标。

     (提醒:务必请先对前一篇所完成工程做一个备份。因为以后我还要从上一篇的工程状态开始新的内容呢!)

1 首先我们要有一个自定义图标(文件名以myicon.ico为例)

     在我们的工程文件夹(即D:MyApp)下创建一个myResLib文件夹(用以集中存放各种资源文件)。

     然后,你可用一个.ico编辑器创建一个图标文件myicon.ico,把它放在D:MyAppmyResLib文件夹下。

     不过,也可能你并不懂得使用任何一款.ico编辑器,那也没关系,随便找一个.ico(16*16或32*32的)文件(这不应成为问题吧?)。把它复制到D:MyAppmyResLib文件夹下,并改名为myicon.ico。

     好了,现在我们有一个图标文件,请你记住它的路径和名称。

2    之所以用记事本来创建而不用VC本身来创建,是因为我不希望让VC生成一些无关码,以便于解说和理解。

     另外一点要提醒:如果你的工程里已经包含有一个.rc的资源脚本文件,那么在下面的操作会出现一些不同的情况。但如果从第一篇就按我所述的来操作,本工程是没有.rc文件的。

    操作:

     =>开始->程序->附件->记事本

     =>在记事本中输入如下一行:

     IDI_MYICON     ICON   DISCARDABLE   ” myResLib myicon.ico”

     看,在ICON   DISCARDABLE的左边写上ID名,右边写上图标所在的相对路径字符串。这样也就将myResLibmyicon.ico图标定义ID号为IDI_MYICON,并且这样定义的ID就是字符串ID。(等一下你就会知道如何使用字符串ID了!)

     =>点击“记事本”程序菜单“文件”->另存为->在“保存在”框中选D:   ->双击打开MyApp文件夹->在“保存类型”框中选“所有文件(*.*)->在“文件名”框中输入:myRes.rc->点“保存”(操作完成)

     现在我们已经为myicon.ico定义了一个字符串ID:IDI_MYICON 。接下来,要干什么呢?哦,你要知道,这样方式创建脚本文件是不会自动加到我们的工程中,所以你要记得自己把myRes.rc加到你的工程中。

3 将myRec.rc加入到工程中。

     =>在工作区(Workspace)视图中选FileView选项卡->在其中右击Source Files -> 单击“添加文件到目录… ->双击“myRes.rc”

     本操作的目的:将资源脚本文件myRes.rc加入到该工程中。下面我们就可以通过代码来访问这个图标了。

4 要使用图标资源,得先用LoadIcon函数加载图标资源。

     LoadIcon原型:
     HICON   LoadIcon ( HINSTANCE hInstance,   LPCSTR lpIconName);

    参数:

    HINSTANCE hInstance:
要加载图标是存在那个应用程序里,就代入这个应用程序实例的句柄。

    LPCSTAR lpIconName:是你要加载的图标的字符串ID,就是我们在第3步中定义的。

    返回值:加载成功后会返回一个图标句柄值,其类型是HICON。加载后,我们就可以通过这个句柄值来操作对应图标了。

     下面就是原来在窗口类结构体中设置窗口标题栏图标的代码(应该还记得下面一行代码在哪里吧!):
wndclass.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE( IDI_APPLICATION ) ) ;

     你先别理上面LoadIcon中的参数使用,现在我们把它改成如下:

    wndclass.hIconSm = LoadIcon(hinstance,” IDI_MYICON”) ;

     其中,hinstance就是本应用程序实例的句柄。”IDI_MYICON”就是我们要加载的图标。

     现在,我们把WinMain主函数里的代码修改如下:

int APIENTRY WinMain(HINSTANCE hinstance,

                      HINSTANCE hPrevInstance,

                      LPSTR      lpCmdLine,

                      int        nCmdShow)

{

     //……

          wndclass.hInstance = hinstance;

     wndclass.hCursor =LoadCursor(NULL, IDC_ARROW);

     wndclass.hIcon =NULL; 
//wndclass.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE( IDI_APPLICATION ) ) ;
//注释了上句

    wndclass.hIconSm = LoadIcon(hinstance,”IDI_ICON1″) ;     //添加了此句


     wndclass.lpszMenuName =NULL;

     wndclass.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);

     wndclass.lpszClassName =WND_CLS_NAME;


     if (!RegisterClassEx(&wndclass))

         return 0;

//……

}

5 最后Build我们的程序

     直接F5就行了。

     看到了没,程序的窗口已经变成我们想要的图标了。

四 继续上例:将图标资源由使用字符串ID改为使用整数ID

     前面我反复地说到字符串ID和整数ID。你首先要明白,所有资源的ID号可以定义为字符串的,也可以定义为整数型的。我在前例中使用的是一个字符串ID的例子,现在我又要改为使用整数ID。

1 创建一个名为Resource.h头文件,内容如下:
#define IDI_MYICON 100              



     将IDI_MYICON 定义为一个整数型符号常量。这个数值应是以1以上一个数值。

     (注意:头文件最后要有一空行,也是是说 #define IDI_MYICON 100 后要按一个回车键。)

2 修改myRes.rc文件。

//myRes.rc
#include “Resource.h”    //包含头文件resource.h

IDI_MYICON     ICON   DISCARDABLE   ” myResLib myicon.ico”

    

     经过上述两处的添加后,IDI_MYICON就不在是字符串ID了,而是整数ID。因为Resource.h已经将IDI_MYICON定义为一个整数的符号常量。

3 在WinMain( )函数所在的源文件中添加包含Resources.h头文件,并修改LoadIcon()函数。

// MyAppMain.cpp :主函数及回调函数


#include .h>

#include.h>

#include “resource.h”    //包含resource.h


int WINAPI WinMain(HINSTANCE hinstance,

                  HINSTANCE hprevinstance,

                  LPSTR lpcmdline,

                  int ncmdshow)

{

     //……

wndclass.hInstance = hinstance;

     wndclass.hCursor =LoadCursor(NULL, IDC_ARROW);

     wndclass.hIcon =NULL; 

//wndclass.hIconSm = LoadIcon(NULL, MAKEINTRESOURCE( IDI_APPLICATION ) ) ;

//上句注释了
wndclass.hIconSm = LoadIcon(hinstance, (LPCTSTR)IDI_ICON1) ; 

   //第二个参数由” IDI_ICON1”字符串改成(LPCTSTR) IDI_ICON1


     wndclass.lpszMenuName =NULL;

     wndclass.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);

     wndclass.lpszClassName =WND_CLS_NAME;


}

    分析:

     凡是要使用整数ID资源的文件都要包含Resource.h 头文件,这是因为整数ID是由Resource.h定义的。(这个好理解!)

     修改LoadIcon()调用。因为LoadIcon的第二个参数接受的是字符串ID(就是LPCTSTR指针),所以,我们得把整数ID转化成LPCTSTR。(LPCTSTR) IDI_MYICON目的就是将IDI_MYICON强制转化成LPCTSTR。

     我们可是辛辛苦苦地把字符串ID改成整数ID,现在调用LoadIcon()时又要将IDI_MYICON 强制类型转化成LPCTSTR类型。嘻嘻,真有意思,好似我们在瞎折腾似的,到头来又要回到了原来的状态。但不管怎么说,这也是一种方式噢!

     好了,现在你可以编译运行试试了。哈哈,也是相同的作用哟!

你可能感兴趣的:(MFC)