delphi资源文件制作及使用详解

一、引子:
现在的Windows应用程序几乎都使用图标、图片、光标、声音等,我们称它们为资源(Resource)。最简单的使用资源的办法是把这些资源的源文件打入软件包,以方便程序需要的时候调用。资源是程序的一部分,程序要正常运行就离不了资源文件。但是它是不可执行代码。
为了更好地管理资源,Delphi中提供了一种.RES类型的资源文件。它可以把我们程序中所需要的资源整合到一个资源文件(.RES)下来。在编译应用程序时直接编译进了可执行程序里,成为应用程序的整合体。
这样做的好处是:1。由于定位资源比在磁盘中定位文件花费时间少,所以应用程序执行会更快。2。多种资源可以放在一个文件中,减少了图标、图片、光标、声音等文件数量。不用怕用户在使用过程中的不小心而损坏了资源文件致使程序无法正常运行。
缺点是:因为资源文件的加入从而加大了编译出的可执行程序的字节数,当资源文件较大时会使应用程序变得看起来雍肿。
使用资源文件的优点很显著,其缺点也很突出。所以在实际应用中就要根据情况权衡利弊、灵活使用,这已不在本文的讨论之列。下面仅就Delphi系统编程中对于资源文件的使用方法做一个大致的总结。
二、创建资源文件:
注意事项:创建的资源文件名不要和工程名相同,因为Delphi创建工程时会自动创建一个和工程名相同的资源文件。并且最好将资源文件保存到和工程文件同一个文件夹中。
1.首先创建一个.Rc的纯文本文件。格式如下: 
资源标识符 关键字 资源文件名 
格式说明:
① 资源标识符:程序中调用资源时的特定标号; 
② 关键字:标识资源文件类型;例如:
Wave : 资源文件是声音文件;
RCDATA: JPEG文件;
AVI : AVI动画;
ICON : 图标文件; 
BITMAP: 位图文件; 
CURSOR: 光标文件; 
RMI : RMI音乐文件;
MIDI : MIDI音乐文件
③ 资源文件名:加入的资源文件名(要带扩展名,可以带路径名构成全文件名); 
④ 举例: MyWav WAVE "FileName.Wav" 
MyMID MIDI "C:\My Documents\my music\canyon.MID"
MyAVI AVI "SpeedIs.AVI" 
例中资源文件名可以不加引号。假设我们把上述三行保存成Sample.RC文件。
2。使用Borland资源编译器(BRCC32.EXE)转化.Rc文件成.Res文件。
在DOS命令行下输入下列命令:
C: //转在C:驱
CD\ //退回根目录
CD\Program Files\Borland\Delphi7\Bin //进入BRCC32.EXE的所在目录
Brcc32 Sample.Rc //把Sample.RC转换成资源文件Sample.RES
注意转换前需要把Sample.RC文件中指定的未带全路径名的文件Copy进当前目录C:\Program Files\Borland\Delphi7\Bin中来,才可保证转成.RES文件不出错。如果转换过程没有报错,则成功。
三、引用资源文件
把上一步骤生成的资源文件Sample.RES放到要建立的工程的同一个目录中来。 
为了存取我们的资源文件,必须告诉Delphi链接我们的资源文件到应用程序中。因此要在源代码中加入一条编译指令完成上述功能。这条指令必须紧跟在窗口指令后,如下形式: 
{$R *.DFM} //Delphi自带编译指令 
{$R Sample.RES}  //新加入的编译资源文件的指令
不要删除{$R *.DFM}指令,因为这行代码告诉Delphi链接下面的资源到窗口的资源中。
四、调用资源文件 
1。存取资源文件中的位图(Bitmap) 
程序中如果想存取资源,必须调用一些Windows API函数。保存在资源文件中的位图、光标和图标可以通过调用LoadBitmap、LoadCursor和LoadIcon函数存取。 
现举例说明如何存取资源文件中位图并显示在Timage控件中。 
procedure TfrMain.btnCanvasPic(Sender: TObject); 
begin
Image1.Picture.Bitmap.Handle :=LoadBitmap(hInstance,'资源标识符');
end; 
注:如果位图没有装载成功,程序仍旧执行,但是Image将不再显示图片。可以根据LoadBitmap 函数的返回值判断是否装载成功,如果装载成功返回值是非0,如果装载失败返回值是0。
另外一个存取显示位图的方法如下:
procedure TfrMain.btnLoadPicClick(Sender: TObject); 
begin 
Image1.Picture.Bitmap.LoadfromResourceName(hInstance,'资源标识符'); 
end; 
2。存取资源文件中的光标 
Screen.Cursors[]是一个光标数组,使用光标文件我们可以将定制的光标加入到这个属性中。因为默认的光标在数组中索引值是0,所以除非想取代默认光标,最好将定制的光标索引值设为1。 
procedure TfrMain.btnUseCursorClick(Sender: TObject);
begin
Screen.Cursors[1] :=LoadCursor(hInstance,'资源标识符');
Image1.Cursor :=1;
end;
3。存取资源文件中的图标
将图标放在资源文件中,可以实现动态改变应用程序图标。
procedure TfrMain.LoadIconClick(Sender: TObject);
begin
Application.Icon.Handle := LoadIcon(hInstance,'资源标识符');
End;
4。存取资源文件中的AVI
在工程中添加一TAnimate控件(在Win32控件面板上),在需要的地方加入:
procedure TfrMain.LoadIconClick(Sender: TObject);
begin
Animate1.ResName :='MyAvi' ; //资源标识
Animate1.Active := True ;
End ; 
实 践中的一点总结:并不是所有的AVI资源都可以用TAnimate组件来播放,编定程序时要测试。遇到不能用TAnimate组件来播放的AVI资源,则 可以把它从资源文件里分离出来,再使用相应的播放组件比如TMediaPlayer来播放。使用完再把分离出来的临时文件删除掉。可以参考后面 “7。”的说明。
5。存取资源文件中的JPEG
把jpeg单元加入到Interface的uses中。
procedure TForm1.LoadJPGClick(Sender: TObject);
var
Fjpg : TJpegImage ;
FStream : TResourceStream ;
begin
Fjpg := TJpegImage.Create ;
FStream := TResourceStream.Create(hInstance,'资源标识符',RT_RCDATA) ;
FJpg.LoadfromStream(FStream) ;
Image1.Picture.Bitmap.Assign(FJpg);
end;
6。存取资源文件中的Wave
把MMSystem加入到Interface的uses中
procedure TForm1.LoadWaveClick(Sender: TObject);
begin
PlaySound('MyWav',hInstance,Snd_ASync or Snd_Memory or snd_Resource) ;
end;
实 践中的一点结论:PlaySound()的参数Snd_ASync表示异步播放方式,Snd_Sync表示同步播放方式。(1)当采用异步方式的时 候,WAV资源可以作为背景音乐来应用;但是当有连续多次异步调用的时候,则可能会丢弃最后一次调用之前的所有播放,用户得到的效果只是最后一次调用的声 音。(2)当采用同步方式的时候,WAV资源会独占资源,导致WAV文件未播放完之前用户无法对应用程序进行任何操作,直至它的调用结束。所以如果有大的 同步WAV资源时,会造成应用程序界面的停滞。但是这种方式却可以连续地一个不漏地执行多次调用。
7。其他资源的调用:
可以把资源文件中的源文件分离出来,建立一个临时的物理文件存在于应用程序路径下,然后可以用相应类型的组件来或方法来使用该文件。当程序退出时再不忘把该临时文件删除掉。
例如:
var
tmpDirectory : string;
myres : TResourceStream;
begin
tmpDirectory := ExtractFilePath(paramstr(0));
if not FileExists(tmpDirectory + 'Music1.RMI') then
begin
myres := TResourceStream.Create(hinstance,'music1','RMI');
myres.SaveToFile(tmpDirectory + 'Music1.RMI');//从资源文件中分离出来
myres.Free;
。。。。。。。。。。
end; 
程序退出的时候删除:
if FileExists(tempDirectory + 'music1.RMI') then
DeleteFile(tempDirectory + 'music1.RMI');
五、结束语
位 图、光标和图标、AVI动画、JPEG和Wave文件等可以放到资源文件中。上面我们介绍了如何将资源加入到资源文件中,并介绍了在Delphi中动态存 取资源文件的方法。Delphi编译工程会自动创建一个和工程名相同的资源文件(如果没有其他的资源,主窗口的图标会放在这个资源文件中)。但是建议最好 不要改变这个资源文件。
六、参考资料:
1。http://www.delphiok.com/bcjq/all/114.htm 来自Delphi技巧网;
2。http://www.delphibbs.com/delphibbs/dispq.asp?lid=2358589 ;
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2369429 ;
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2370212 ;来自大富翁论坛
特向以上网站和大富翁Wind8Bell、迷糊、miaofeng、app2001等表示感谢!
 
可以自己做一个RC文件,例如 sample.rc ,RC文件其实就是一个资源文件的描述文本,
通过“记事本”程序创建就行了。然后可以输入一些我们要定义的资源,例如:
MEN BITMAP c:\bitmap\men.bitmap
ARJ EXEFILE c:\arj.exe
MOV AVI c:\mov.avi
然后用BRCC32把这个RC文件编译成sample.res(真正的资源文件)。
在Delphi的工程文件中使用 $R 编译指令让Delphi包括资源到EXE文件里面。
{$R sample.res}
这样我们就可以在这个单一的执行文件中调用资源了。举例如下:
EXEFILE:
procedure ExtractRes(ResType, ResName, ResNewName : String);
var 
Res : TResourceStream; 
begin
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType)); Res.SavetoFile(ResNewName);
Res.Free; 
end;
AVI:
procedure LoadAVI;
begin
{Avi1是一个TAnimate类}

Avi1.ResNam

Delphi中的资源(Resources in Delphi)

传统的Windows程序几乎都至少包含一个对话框和一个图标。但是,Delphi应用程序有所不同。首先,Delphi应用程序中没有真正意义上的对话框,实质上也就是没有对话框资源(Delphi中存储的窗体是资源,但它们是RCDATA资源,而不是对话框资源)。

Delphi应用程序有传统意义的图标资源。创建应用程序时,Delphi负责创建图标资源文件。类似地,在为Speedbutton、Image组件或BitBtn组件选择位图时,Delphi将所选位图文件包含到窗体资源中(作为窗体资源的一部分)。在建立应用程序时,窗体和它的全部资源一起包括到程序文件中。这些都是自动处理的。

有时需要在通常的Delphi处理中以外使用资源。例如,要制作动画,必须有一系列的位图,将它们装载进来作为可以最快速度执行的资源。在这种情况下,就需要知道如何把资源捆绑到Delphi应用程序中。

把资源文件捆绑到可执行文件中是件非常容易的事,实际创建资源却要困难的多。如果有一个好的资源编辑器,创建诸如位图、图标和光标之类的基本资源并不困难,但创建具有专业化品质的3D位图和图标却是一项艺术性的工作。我们肯定遇到过很多不错的程序,但它们的位图按钮实在难看。我们可以利用Delphi自带的Image Editor创建位图、图标和光标。

如果要创建字符串资源、用户数据资源、波形文件资源或其他专用资源,则可能需要第三方资源编辑器。

Note

如果手头有老版本的Borland Pascal,可使用其中的Resource Workshop编辑器编辑专用资源。创建好资源后,会形成一个.rc文件,Delphi中带有Borland Resource Compiler,用Borland Resource Compiler(BRCC32.EXE)将它编译成.res文件。从技术上讲,可以用任何一种文本编辑器创建.rc文件并用资源编译器编译它,但使用资源编辑器创建资源要容易的多。

现在在推荐一个款比较不错的第三方资源编辑器Resource Builder,该软件界面简洁,使用简单,大家可以百度一下。

编译资源文件(Compiling Resource Files)

资源文件创建好后,要用资源编译器来编译它。编译资源文件的方法有两种:

  • 从命令行手工编译资源文件。
  • 添加一个批处理文件工程到工程组。

用其中任意一个方法,编译完后都得到一个.res文件,将它链接到应用程序中。

1、 从命令行编译(Compiling from the Command Line)

从命令行编译资源文件,只需打开Windows中的命令提示框,并输入一行与下面相似的命令:

brcc32 jjres.rc

delphi资源文件制作及使用详解

当然,必须保证当前系统目录为Delphi安装目录的Bin目录下,如果不是,则必须输入BRCC32.EXE的完整路径。这个资源编译器速度非常快,甚至不等察觉,它就把资源脚本文件编译完成了。

2、 使用批处理文件工程(Using a Batch File Project)

添加一个批处理文件到工程组,与从命令行编译一样简单,并且还有一个好处:保证资源文件总是最新的。要搞清楚批处理文件如何工作,可执行下面的步骤:

(1)创建一个新的应用程序;

(2)选择【View | Project Manager】打开“Project Manager”工程管理器,如下图:

delphi资源文件制作及使用详解

(3)点击“Project Manager”工具栏上的“Add New Project”按钮,显示Object Repository对象库,如下:

delphi资源文件制作及使用详解

(4)双击Batch File图标来创建文件工程。将该批处理文件工程以Project2的名称添加到“Project Manager”中,如下:

delphi资源文件制作及使用详解

(5)用鼠标右键点击批处理文件节点并选择Save,将文件保存为test.bat

delphi资源文件制作及使用详解

(6)用鼠标右键再次点击批处理文件节点并选择【Edit/Options】,会弹出“Batch File Options”对话框;

delphi资源文件制作及使用详解

(7)在Command文本框内输入下列正文:

del myfile.res

brcc32 myfile.rc

(8)点击OK关闭“Batch File Options”对话框。

这个练习锁做的就是创建一个批处理文件,当编译工程组时,它就会执行。第(7)步输入的批处理文件命令删除一个名为myfile.res文件,并调用Delphi资源编译器编译myfile.rc文件。用资源编译器编译myfile.rc文件会生成一个名为myfile.res的文件。

工程组中的下一个工程可能要使用myfile.res。呵呵,那为什么要先删除myfile.res文件呢?这是因为,删除该文件后,就能知道资源编译器是重新建立了这个文件。如果资源编译器创建资源失败,则任何要使用这个资源文件的工程都将编译失败,并报告编译错误,提示编程人员,建立资源文件出错。

把资源文件链接到你的可执行文件中(Linking Resource Files to Your Executable)

编译好资源文件后,要把编译后的资源文件链接到程序的可执行文件中,可使用$R编译器指令。例如,要链接包含在myfile.res文件中的二进制资源,可在主窗体单元的开头处插入下面一行:

?
1 {$R myfile.res}

就这么简单!只要指定的文件存在,Delphi就会在链接时把这个编译过的资源添加到可执行文件中。

使用资源的样本程序(A Sample Program Using Resources)

下面的清单中,列出了Jumping Jack的程序的主窗体单元。这个程序显示一个带声音效果的简单动画。主窗体上有两个按钮:一个Image组件和一个Label组件。Jumping Jack程序说说明了资源在Delphi应用程序中的使用。它特别说明了如何加载以资源文件形式存储的位图,如何加载并显示字符串资源,以及如何播放资源文件中的波形音频。清单后面还列出了部分资源文件。先看看清单,然后再分析程序。

JJMain.pas清单

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 unit JmpJackU; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, MMSystem; {$R JJRES.RES} const IDS_UP = 101 ; IDS_DOWN = 102 ; type TMainForm = class (TForm) Image: TImage; Label1: TLabel; Start: TButton; Stop: TButton; procedure FormCreate(Sender: TObject); procedure StartClick(Sender: TObject); procedure StopClick(Sender: TObject); private { Private declarations } Done: Boolean ; procedure DrawImage( var Name: string ); public { Public declarations } end ; var MainForm: TMainForm; implementation {$R *.dfm} procedure TMainForm . DrawImage( var Name: string ); begin { 从资源文件中读取位图,通过资源名称} Image . Picture . Bitmap . LoadFromResourceName(HInstance, Name); { 让Image有机会显示位图} Application . ProcessMessages; { 延缓,让动画变慢} Sleep( 20 ); end ; procedure TMainForm . FormCreate(Sender: TObject); begin Image . Picture . Bitmap . LoadFromResourceName(HInstance, 'ID_BITMAP1' ); end ; procedure TMainForm . StartClick(Sender: TObject); var s: string ; ResName: string ; i: Integer ; Buff: array [ 0..9 ] of Char ; begin s := 'ID_BITMAP' ; Done := False ; while not Done do begin for i := 1 to 5 do begin ResName := s + IntToStr(i); DrawImage(ResName); end ; LoadString(HInstance, IDS_UP, Buff, SizeOf(Buff)); Label1 . Caption := Buff; Label1 . Refresh; PlaySound( 'ID_WAVEUP' , HInstance, SND_ASYNC or SND_RESOURCE); Sleep( 200 ); for i := 5 downto 1 do begin ResName := s + IntToStr(i); DrawImage(ResName); end ; PlaySound( 'ID_WAVEDOWN' , HInstance, SND_ASYNC or SND_RESOURCE); LoadString(HInstance, IDS_DOWN, Buff, SizeOf(Buff)); label1 . Caption := Buff; Label1 . Refresh; Sleep( 200 ); end ; end ; procedure TMainForm . StopClick(Sender: TObject); begin { 当“Stop”按钮按下时,告诉循环停止} Done := True ; end ; end .

JJRec.rc清单

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 STRINGTABLE BEGIN 101, "Up" 102, "Down" END ID_WAVEUP WAVE "up.wav" ID_WAVEDOWN WAVE "down.wav" ID_BITMAP1 BITMAP MOVEABLE PURE LOADONCALL DISCARDABLE LANGUAGE LANG_NEUTRAL, 0 BEGIN '42 4D 76 02 00 00 00 00 00 00 76 00 00 00 28 00 ' '00 00 20 00 00 00 20 00 00 00 01 00 04 00 00 00 ' '00 00 00 02 00 00 00 00 00 00 00 00 00 00 10 00 ' '00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80 ' '00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80 ' '00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF ' '00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF ' '00 00 FF FF FF 00 BB BB BB BB BB BB BB BB BB BB ' 'BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB ' 'BB BB BB BB BB BB BB BB BB BB BB BB BB B0 B0 BB ' 'BB BB BB BB BB BB BB BB BB BB BB BB BB B0 B0 BB ' 此处省略了部分内容,详细内容请查看示例代码

分析:

主窗体类声明中声明了一个Done的布尔型字段,Done用于确定何时终止动画。DrawImage方法用于在Image组件中显示位图。

注意:上列代码中,使用了两个Windows API函数来加载字符串和波形文件资源。在StartClick方法中,LoadString函数加载一个字符串到到一个字符数组缓冲区内。然后将该字符数组分配给窗体上的Label组件的Caption属性。

PlaySound函数用于播放波形文件资源。PlaySound函数用SND_ASYNC标志通知Windows开始播放音频并立即将控制返回给程序,这使得在播放音频的同时,动画能继续下去。SND_RESOURCE标志通知Windows,声音是一个资源,而不是磁盘上的一个文件。LoadString和PlaySound函数都使用HInstance全局变量通知Windows到可执行文件中去查找资源。装入位图资源,使用VCL方法LoadFromResourceName。

而资源文件JJRec.rc中的前5行说明字符串在资源脚本文件中的格式;使用文本编辑器创建字符串表非常容易。接下去是为两个波形文件创建各自的WAVE资源,这两个波形文件已存在该工程目录中。资源编译器一看到WAVE声明,它就会读声音文件并将它们编译进二进制资源文件。

Note

从上面的清单中看出,使用文本编辑器来创建某些类型的资源是比较容易的事。如果位图和波形音频文件存为了外部文件,可像上面的清单那样将它们包含到.RC文件中,并用资源编译器将它们编译为二进制资源文件。其中二进制资源文件可链接到应用程序的可执行文件中。

上面的资源清单只是部分代码,用传统的资源编辑器创建的位图常常以数字数据的形式包含到资源文件中,位图的资源描述可以很长。Jumping Jack位图资源描述大约有200行,因此未在清单中全部列出。下图给出了Jumping Jack启动后的界面。

delphi资源文件制作及使用详解

为应用程序创建附加资源不是什么高深的学问,但也不是很简单的事情。要搞清楚它们如何协调配合要花一定的事件。

代码下载地址:

上一篇:Delphi 与 DirectX 之 DelphiX(85): TDIB.DrawTo();


下一篇:Cypress web自动化13-viewport设置不同分辨率,适配不同设备,手机型号