Delphi编程中资源文件的应用

Delphi编程中资源文件的应用
/转自 http://chamlly.spaces.live.com/blog/cns!548f73d8734d3acb!236.entry
一、引子:

现在的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,'资源标识符'); 
Screen.Cursors[2] :=LoadCursor(hInstance,'资源标识符2'); 
Image1.Cursor :=1; 
screen.cursor:=2;
end;
同样定义两套鼠标

Screen.Cursors[1] :=LoadCursor(hInstance,'资源标识符');

Screen.Cursors[2] :=LoadCursor(hInstance,'资源标识符2');

在这使用的话需要在rc文件种定义两次鼠标资源文件

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编译工程会自动创建一个和工程名相同的资源文件(如果没有其他的资源,主窗口的图标会放在这个资源文件中)。但是建议最好不要改变这个资源文件。

第二篇文章: 
《谈Delphi编程中资源文件的应用》 
[来源:陈经韬] 
(一)初级应用篇: 
资源文件一般为扩展名为res的文件.在VC中资源文件用得非常普遍,但Delphi在其联机帮助中对资源文件没作什么介绍,其实利用其自带的资源编译工具BRCC32.EXE(一般位于/Delphi/BIN目录下),我们完全可以做出跟VC一样效果的文件来。 
资源文件最大的好处是能将一些在必要时才调用的文件跟可执行文件一起编译,生成一个文件.这样做最大的好处就是使外部文件免遭破坏.例如在一条程序中你要临时调用一幅图片,一般作法是把图片放在某一路径下(通常是主程序所在路径),但如果用户路径误删你的图片文件,则可能使程序找不到相应文件而出错崩溃.另外,如果你想自己的程序界面美观,想用一些自定义光标,也要用到资源文件。 
资源文件的使用步骤为: 
1.编写rc脚本文本 
用记事本或其它文本编辑器编写一个扩展名为rc的文件。例如:

mycur cursor move.cur //加入光标 
mypic Bitmap Water.BMP //加入位图 
mywav WAVE happy.wav //加入声音 
myAVI AVI EPOEN.AVI //加入视频 
myIco ICON CJT.ICO //加入图标

格式分别为在资源文件中的名称->类型->实际文件名称,例如上面第一行定义一个名为mycur的光标,实际名称为加入光标move.cur. 
2.将rc文件编译成res资源文件 
将脚本文件和实际文件拷到Brcc32.EXE所在目录,执行DOS命令。格式为:Brcc32 脚本文件(回车),例如有一名为myfirst.rc的脚本文件,则执行 Brcc32 myfirst.rc(回车)即可。如果你是懒人,也可新建一批处理文件,内容只有一行:Brcc32 mufist.rc.(因为Delphi安装后一般会在自动批处理文件中指明搜索路径的。)如果编译成功,则会生成一个结尾为res的文件,这个文件就是我们需要的资源文件。 
3.在Delphi单元中加入资源文件 
将生成的res资源文件拷贝到你所编程序的路径下,在单元文件{$R *DFM}后加上一句{$R mufirst.res},则将res文件加入去,编译后资 源文件即已包含在可执行文件中了。若你有多个资源文件,也按上法依次加入。 
4.在Delphi程序中调用资源文件 
资源文件在Delphi中的关键字为hinstance.下面给出具体用法. 
<1>光标的调用 
首先在程序中定义一个值大于0的常量,因为Delphi本身用0-负16来索引默认的光标,所以我们制定的光标应从表面上1开始索引。然后在窗口的Oncreat事件中添加以下代码: 
screen.cursor[35]:=Loadcursor (hinstance,'mycur'); 
其中35为大于1的常量,mycur为光标在资源文件中的名字。如果希望在其他控件上使用定制光标,例如Panel控件,只需在程序的适当处加入以下代码: 
Panel1.cursor:=35; 
<2>位图的调用 
新建一项工程,添加一Timage控件,在需要显示的地方写以下代码: 
Var mymap:Hbitmap; 
begin 
mymap:=LoadBitmap(hinstance,'mypic'); 
Image1.picture.Bitmap.Handle:=mymap; 
end; 
其中"mypic"为位图资源文件中的名称。 
〈3〉AVI文件的调用 
新建一工程,添加一Animate控件,在需要的地方加入: 
animater1.resname:='myAVI'; 
animater1.Active:=true; 
其中myAVI为视频文件在资源文件中的名称。 
〈4〉调用WAV文件 
在uses中加入mmsystm单元,以便在程序中播放WAV文件。播放时Playsound(pchar('mywav'),hinstance,sndsync or snd_resource);其中mywav为声音文件在资源中的名称。 
〈5〉加入光标 
加入光标比较容易,只要将res文件加入单元文件中即可。但需注意,名称最好取"W"."WW"等,使第一个字母尽量靠后,以免与主程序的图标顺序颠倒。这样一来,别人在使用你的程序时如果想选择其它图标就有很多选择了。 
补充: 
1.资源类型除上述类型外,还可以字体文件,字符串文件等。 
2.资源文件不但可以在标准图形界面下使用还可在控制台下使用。 
下面我们来试验一下: 
新建一工程,将唯一的一个Form删除,然后修改工程文件。增加一句{$Apptype console},在uses子句中加入mmsystem,并将其它引用单元删掉。将Begin和end之间语句删掉。至此,我们就可和Turbo PASCAL下编程序一样,且还可以调用windows的API和资源。将资源文件----{$R myfist.res}加入。在Begin和end之间写下: 
writeln('演示程序,按任意键开始!'); 
readln; 
playsound(pchar('mywav'),hinstance,snd_sync or snd_resource); 
writeln('演示结束!'); 
运行程序,将弹出一个标准DOS窗口,按任意键播放声音文件。是不是很COOL呢!我曾下载过一个播放器,在其安装目录下我发现有一"DOS程序",用鼠标双击它便弹出一个DOS窗口,显示DOS时代特有的画图,并有背景音乐!可能就是用这个方法做的。 
3.Delphi本身自带了一个叫Image Editor的工具,同样可以编辑资源文本,但和本文的方法比较,可得出下表:

************************************** 
Image Editor Brcc32

BMP 只支持16位色 任意色

光标 黑白两色 任意色

ICO 只支持16位色 任意色

AVI 不支持 支持

WAV 不支持 支持

字体 
字符串 不支持 支持 
其他 
****************************************

上面说的是直接在程序本身的调用。其实资源文件还有其它用法。比如说在你的程序携带其它文件,要用的时候释放出来。 
例如: myexe exefile 'ha1.exe'//脚本文件 
下面是自定义释放函数ExtractRes,本例中使用如下: 
ExtractRes('exefile','myexe','c:/new.exe'); 
就把ha1.exe以new.exe为名字保存到C盘根目录下了.

function TForm1.ExtractRes(ResType, ResName, ResNewName: string): boolean; 
var 
Res: TResourceStream; 
begin 
try 
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType)); 
try 
Res.SavetoFile(ResNewName); 
Result := true; 
finally 
Res.Free; 
end; 
except 
Result := false; 
end; 
end; 
---------------------------------------------------------------------- 
(二)中级应用篇: 
上面我们已经知道如何把一副BMP图像从资源文件里面读出来,但是BMP文件太大了,JPG文件应用的相对较多.那么如何把JPG图像读出来呢?用资源文件加流方式即可。具体方法如下: 
(1)MyJpg JPEG My.JPG 
(2)Var 
   Stream:TStream; 
   MyJpg:TJpegImage; 
  Begin 
   Stream:=TResourceStream.Cceat(HINSTANCE,'MyJpg','JPEG'); 
   Try 
     MyJpg:=TJpegImage.Create; 
    Try 
      MyJpg.LoadfromStream(Stream); 
      Image1.Picture.Assignc(MyJpg); 
    Finally 
      MyJpg.Free; 
    end; 
   Finally 
    Stream.Free; 
   end; 
  end; 
读取其它图片文件也是一样的.比如说gif动画文件,当然前提是你有一个gif.pas,这个单元很多站点都有的,可以自己去找找。实际应用中我还发现用上面的代码可以直接显示资源文件中的ICON和BMP. 
说到图形处理,实际上还可以用Delphi创建、调用纯图标资源的DLL.比如说你可以看看超级解霸目录下的Dll,很多就是纯图标资源而已。具体方法如下: 
(1):创建一个Hicon.RES文件,这里不再重复. 
(2):新建一文本文件Icon.dpr,内容如下: 
library Icon; 
{$R Icon.RES} 
begin 
end. 
用Delphi打开编译即可得到Icon.dll. 
(3):实际调用方法如下: 
...... 
 Private 
  Hinst:THANDLE; 
...... 
 Var Hicon:THANDLE; 
begin 
 Hinst:=Loadlibrary('Icon.dll'); 
 If Hinst=0 Then Exit; 
 Hicon:=Loadicon(Hinst,Pchar(Edit1.Text)); 
If Hicon<>0 Then Image1.Picture.Icon.Handle:=Hicon; 
 FreeLibrary(Hinst); 
end; 
如果你的程序想在国际上供使用不同语言的人使用的话,用Dll来存放字符资源将是一个好方法.因为Dll不象ini文件那样可以被人随便修改,特别是有时侯如果想保存一些版权信息的话用Dll就再好不过了。比如说你准备开发一个"汉字简繁体翻译器"软件,准备提供Gb32,Big5码和英文三种语言菜单给用户,那么你可以试试用Dll来保存字符资源. 
我们需要建立三个Dll.第一步当然是写Rc文件,举Gb32码为例,内容如下: 
/*MySc.rc*/ 
#define IDS_MainForm_Caption 1 
#define IDS_BtnOpen_Caption 2 
#define IDS_BtnSave_Caption 3 
#define IDS_BtnBig5_Caption 4 
#define IDS_BtnGb32_Caption 5 
#define IDS_BtnHelp_Caption 6 
#define IDS_Help_Shelp 7 
Stringtable 

IDS_MainForm_Caption,"汉字简繁体翻译器" 
IDS_BtnOpen_Caption,"打开文件" 
IDS_BtnSave_Caption,"保存文件" 
IDS_BtnBig5_Caption,"转换成Big5" 
IDS_BtnGb32_Caption,"转换成Gb32" 
IDS_BtnHelp_Caption,"帮助" 
IDS_Help_Shelp,"输入文字或打开文件后按需要点击按钮即可转换!" 

第二步是Brcc32编译为Res文件后用上面的方法得到Dll文件,另外两个Dll用同样的方法生成.下面来应用一下: 
新建一个工程,放上五个Button:BtnOpen,BtnSave,BtnBig5,BtnGb32和BtnHelp.还有一个TComboBox:CbSelect用来选择语言种类的. 
具体代码如下: 
unit Unit1; 
interface 
...... 
private 
SHelp: string; 
function SearchLanguagePack: TStrings; 
procedure SetActiveLanguage(LanguageName: string); 
{ Private declarations } 
...... 
implementation 
procedure TForm1.CbSelectChange(Sender: TObject); 
begin 
SetActiveLanguage(CbSelect.Text);//调用相应Dll文件读取相应字符. 
end; 
procedure TForm1.FormCreate(Sender: TObject); 
begin 
CbSelect.Items.AddStrings(SearchLanguagePack);//搜索当前目录下所有的Dll文件名称 
end; 
function TForm1.SearchLanguagePack: TStrings; 
var 
ResultStrings: TStrings; 
DosError: integer; 
SearchRec: TsearchRec; 
begin 
ResultStrings := TStringList.Create; 
DosError := FindFirst(ExtractFilePath(ParamStr(0)) + '*.dll', faAnyFile, SearchRec); 
while DosError = 0 do 
begin 
ResultStrings.Add(ChangeFileExt(SearchRec.Name, '')); 
DosError := FindNext(SearchRec); 
end; 
FindClose(SearchRec); 
Result := ResultStrings; 
end;

procedure TForm1.SetActiveLanguage(LanguageName: string); 
var 
Hdll: Hmodule; 
MyChar: array[0..254] of char; 
DllFileName: string; 
begin 
DllFileName := ExtractFilePath(ParamStr(0)) + LanguageName + '.dll'; 
if not FileExists(DllFileName) then Exit; 
Hdll := loadlibrary(Pchar(DllFileName));

Loadstring(hdll, 1, MyChar, 254); 
Self.Caption := MyChar; 
//读取字符资源,1表示资源文件中定义的1 
Loadstring(hdll, 1, MyChar, 254); 
Self.Caption := MyChar;

Loadstring(hdll, 2, MyChar, 254); 
BtnOpen.Caption := MyChar;

Loadstring(hdll, 3, MyChar, 254); 
BtnSave.Caption := MyChar;

Loadstring(hdll, 4, MyChar, 254); 
BtnBig5.Caption := MyChar;

Loadstring(hdll, 5, MyChar, 254); 
BtnGb32.Caption := MyChar;

Loadstring(hdll, 6, MyChar, 254); 
BtnHelp.Caption := MyChar;

Loadstring(hdll, 7, MyChar, 254); 
SHelp := MyChar;

Freelibrary(hdll); 
Application.Title := Self.Caption; 
//------------------------ 
BtnOpen.Visible := True; 
BtnSave.Visible := True; 
BtnBig5.Visible := True; 
BtnGb32.Visible := True; 
BtnHelp.Visible := True; 
//------------------------ 
end; 
procedure TForm1.BtnHelpClick(Sender: TObject); 
begin 
Application.MessageBox(Pchar(SHelp), 'Http://lovejingtao.126.com', MB_ICONINFORMATION); 
end; 
end. 
可能你会说,这种方法还不如我自己在程序中直接定义三种具体的值来的方便.甚至我自己自定义一个结构好了,用不着用DLL那么麻烦的。但是如果你的程序要用的字符很多呢?比如说Windows操作系统,本身就有简体中文,繁体中文,英文等等版本,用Dll的话只要直接替换DLL即可,而不用每发行一个版本就打开代码来修改一次。这样一来可以大大减少工作量和出错的机会.说到这里,再多说一句:Windows系统本身很多Dll带有了图片等资源,我们可以在程序中直接调用,这样一来我们的EXE也可以减少不少!当然最小的方法是实时生成技术.老外曾经写了一个67KB的程序就是利用了这个方法.感兴趣的朋友可以到http://go4.163.com/lovejingtao/ha1.exe下载. 
---------------------------------------------------------------------- 
(三)高级应用篇: 
Delphi是个很有效率的开发工具,但是它有一个缺点就是生成的EXE文件太大.一个程序就算只有一个空窗口体积也有286KB.如果直接用API来写的话程序体积是小了,但是又太繁琐,无法立即看到界面效果,根本谈不上是可视化开发.其实并非"鱼与熊掌不可兼得",利用资源文件我们就可以轻松达到这个目的. 
在开始之前,我们需要一个可以编辑资源文件的工具.这类工具很多,比如说Resource WorkShop就是非常好的一个.如果一时找不到,利用VC的编辑器来也是可以的.下面我们就以VC的为例示范如何创建一个窗口资源文件.运行VC,打开菜单File-->New,将出现一个多项选择页.我们选择Files-->ResourceTemplate,在右边的File填上Demo,Location选择保存路径,然后点击按钮OK返回VC开发环境. 
选择菜单Insert-->Resource,将出现一个资源类型选择框.我们把鼠标移到Dialog上面.不用展开,点击右边的New即可,这时候返回VC开发环境并出现一个只有关闭按钮和两个Button的窗体.将鼠标选定窗体,击右键选择最后一项Properties,将出现一个设置窗口,将ID改为"MAINFORM"(注意:跟下面添加的其它控件的属性设置方法不同,主窗口的ID必须把双引号写上去,而且名称必须为大写.否则程序将找不到资源.程序会一运行就退出了.)Caption改为"安装程序",这时候可以立刻看到窗口的标题变成了"安装程序",把Styles的Minimize box选上,More Styles的Center勾上使程序运行时的位置居中.当然你也可以设置它的坐标.其它保留默认值即可.回到开发环境,在控件框里面分别选择一个Static Text,一个Edit Box,一个Button和一个Group Box添加到窗体上面.把它们按照自己的爱好排列整齐.然后逐个修改它们的属性.方法就是按照上面说的选定控件后击右键选择最后一项Properties,在出现的属性框里面修改.其中属性如下:Group Box的Caption属性清空,Static Text的Caption属性改为"请选择安装目录:",Edit Box的ID改为10001.第一个Button的ID为10002,Caption属性为"选择",第二个Button的ID为10003,Caption属性为"安装",第三个Button的ID为10004,Caption属性为"退出".为了使程序更加完美,我们为它再添加一个菜单IDR_MENU1.选择Insert-->Resource-->Menu,我们这里只简单添加一项"文件-->退出",其中"退出"的ID为10005.然后在主窗口的属性Menu设定为IDR_MENU1即可. 
为了使程序更加美观,我们再添加一个小图标,同时这也将是我们程序的图标.选择Insert-->Resource-->Icon-->Import,选择一个图标文件.并将它的ID设置为"MAINICON"(注意:必须把双引号写上而且字母为大写),为窗口添加一个Picture控件并设置它的属性Type:Icon,Image下拉选择刚才的图标MainIcon即可. 
如果你想为程序在鼠标添加一些信息也是可以的.选择Insert-->Resource-->Version即可. 
到这里我们已经完成了一个简单的"安装程序"的窗体设计.实际上我们现在就可以在Delphi中调用它了.我们先把"劳动成果"保存起来.选择File-->Save As,在文件类型里选择"32-bit Resource File(.res)"保存为"Demo.res",文件大小大约为2.65KB. 
新建一个扩展名为dpr的文本文件MyDemo.Dpr,键入如下代码: 
Uses Windows,Messages; 
{$R Demo.Res} 
function MainDialogProc(DlgWin:hWnd;DlgMessage:UINT;DlgWParam:WPARAM;DlgLParam:LPARAM):integer;stdcall; 
begin 
Result := 0; 
case DlgMessage of 
WM_Close: 
begin 
PostQuitMessage(0); 
Exit; 
end; 
end; 
end; 
begin 
DialogBox(hInstance, 'MAINFORM', 0, @MainDialogProc); 
end. 
用Delphi打开它编译一次即可产生一个大小为19KB的EXE.是不是很小!实际上,你甚至只用一行代码就把它Show出来,不过程序无法关闭而已. 
Uses Windows; 
{$R Demo.Res} 
function MainDialogProc: integer; 
begin 
Result := 0; 
end; 
begin 
DialogBox(hInstance, 'MAINFORM', 0, @MainDialogProc); 
end. 
上面的程序只不过是一个空窗口而已,现在我们来写代码响应按下相应按钮响应的事件.完整代码如下: 
program MyDemo; 
uses Windows, Messages, shlobj; 
const 
ID_Edit = 10001; 
ID_Selet = 10002; 
ID_Setup = 10003; 
ID_Quit = 10004; 
ID_Exit = 10005; 
{$R Demo.Res} 
var 
MainWin: HWND;

function My_Gettext: string; 
var 
Textlength: Integer; 
Text: PChar; 
s: string; 
begin 
TextLength := GetWindowTextLength(GetDlgItem(MainWin, ID_Edit)); 
GetMem(Text, TextLength + 1); 
GetWindowText(GetDlgItem(MainWin, ID_Edit), Text, TextLength + 1); 
s := text; 
FreeMem(Text, TextLength + 1); 
Result := s; 
end;

function Getmyname: string; 
var 
i, j: integer; 
begin 
J := 3; 
for i := 1 to length(ParamStr(0)) do 
if ParamStr(0)[i] = '/' then J := I; 
Result := copy(ParamStr(0), J + 1, length(ParamStr(0)) - J); 
end;

function SelectDirectory(handle: hwnd; const Caption: string; const Root:WideString;outDirectory:string): Boolean; 
var 
lpbi: _browseinfo; 
buf: array[0..MAX_PATH] of char; 
id: ishellfolder; 
eaten, att: cardinal; 
rt: pitemidlist; 
initdir: pwidechar; 
begin 
result := false; 
lpbi.hwndOwner := handle; 
lpbi.lpfn := nil; 
lpbi.lpszTitle := pchar(caption); 
lpbi.ulFlags := BIF_RETURNONLYFSDIRS + BIF_EDITBOX; 
SHGetDesktopFolder(id); 
initdir := pwchar(root); 
id.ParseDisplayName(0, nil, initdir, eaten, rt, att); 
lpbi.pidlRoot := rt; 
getmem(lpbi.pszDisplayName, MAX_PATH); 
try 
result := shgetpathfromidlist(shbrowseforfolder(lpbi), buf); 
except 
freemem(lpbi.pszDisplayName); 
end; 
if result then 
begin 
directory := buf; 
if length(directory) <> 3 then directory := directory + '/'; 
end; 
end;

function MainDialogProc( 
DlgWin: hWnd; 
DlgMessage: UINT; 
DlgWParam: WPARAM; 
DlgLParam: LPARAM 

: integer; stdcall; 
var 
MyIcon: HICON; 
Sdir: string; 
begin 
Result := 0; 
case DlgMessage of 
WM_INITDIALOG: 
begin 
MyIcon := LoadIcon(hInstance, 'MainIcon'); 
SetClassLONG(DlgWin, GCL_HICON, MyIcon); 
MainWin := DlgWin; 
end; 
WM_Close: 
begin 
PostQuitMessage(0); 
Exit; 
end; 
WM_COMMAND: 
case LOWORD(DlgWParam) of

ID_Selet: 
begin 
if SelectDirectory(DlgWin, '请选择安装目录', '', Sdir) 
then SendMessage(GetDlgItem(DlgWin, ID_Edit), WM_SETTEXT, 0, lParam(pChar(Sdir))); 
end; 
ID_Setup: 
begin 
if My_Gettext = '' then 
begin 
MessageBox(DlgWin, '请先选择安装文件夹!', '信息', MB_ICONINFORMATION + MB_OK); 
Exit; 
end; 
CopyFile(pchar(ParamStr(0)), pchar(My_Gettext + Getmyname), false); 
MessageBox(DlgWin, '安装完毕!', '信息', MB_ICONINFORMATION + MB_OK); 
PostQuitMessage(0); 
Exit; 
end; 
ID_Quit: 
begin 
PostQuitMessage(0); 
EXIT; 
end; 
ID_Exit: 
begin 
if MessageBox(DlgWin, '你点击了菜单“退出”,你确定退出程序吗?', '信息', MB_ICONQUESTION + MB_OKCANCEL) = IDOK then 
PostQuitMessage(0); 
Exit; 
end; 
end; 
end; 
end; 
begin 
DialogBox(hInstance, 'MAINFORM', 0, @MainDialogProc); 
end. 
其中SelectDirectory函数的作用是返回一个选择的文件路径.然后把自己拷贝到选择的目录下,当然很多处理没有写,读者可以自行添加.文件编译后大小为22KB,如果直接用Delphi的VCL来写的话,将为338KB!完整代码可以在我的主页上下载:http://go4.163.com/lovejingtao/setup2.zip.代码中的消息处理相信大家看的懂.如果不用资源文件而直接用API来写将对它更加理解深刻,.限于篇幅这里不做详细介绍,感兴趣的读者可以自行下载代码来看:http://go4.163.com/lovejingtao/setup1.zip. 
全部代码在Delphi+Pwin2000下通过. 
[全文结束]

六、参考资料: 
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等表示感谢!

2003-12-24 19:28:00

2003-12-27 21:51:00 
查看评语???

2004-1-7 22:05:44 Delphi编程善用资源文件 Delphi编程善用资源文件

  资源是存放在扩展名.RES的文件里的二进制数据结构,在DELPHI中资源文件可以使用图象编辑器来制作(IMAGEEDITOR),或者使用其他的工具。如:BORLAND公司提供的RADPACKFORDELPHI中的RESOURCEWORKSHOP来创建。资源文件中通常存放的是应用程序可以随时存取的一些对象,包括:ICON、CURSOR、BITMAP、FONT等近十种。大部分的资源在通常的情况下可以保留在磁盘当中,直到程序需要使用它们时才将其调入,可以大大的节省内存资源,同样,资源文件也是可以共享的,即:多个程序可以共享一个资源文件,进而减少了在应用程序之间代码重复的现象,使程序的代码得到很大的优化,因此在应用程序中使用资源文件有独立制作、方便、随时修改而不需要对应用程序代码做任何修改的好处。

  一般来说,一个应用程序的所有资源都存放在一个RES文件里,然后在DELPHI进行编译的阶段将资源文件的内容与最终的EXE文件合并在一起,因此编译后的RES文件并没有什么作用,仅仅提供用来查阅使用,在分发应用时不必把RES文件分发给最终用户。当然,不同的资源可以分别放在不同的资源文件当中,而且资源文件越小调入内存的速度越快。在这里还要说明的一点是:在修改了原来的资源文件之后,在原来编译的EXE文件中加入的资源不会随之而更新,只有在重新进行编译以后,才能将新的资源加入到新的EXE文件当中去。

  下面我们通过两个例子来说明在DELPHI中如何使用资源文件(在这里我们不讲述资源文件的制作方法)。

  1、如何在DELPHI中使用定制的光标。

  在使用DELPHI进行编程时,有一个很重要的对象──TSCREEN,它是用来管理和操纵运行时期屏幕的不可视构件。它的CURSOR属性是用来指定各个不同的构件光标形状,声名为:

  PROPERTY CURSORS[INDEX:INTEGER]:HCURSOR;

  这个只读的特性返回应用程序支持的光标组成的一个HCURSOR类型的数组,它存储了屏幕上所有的鼠标光标的身份代码(HCURSOR就是光标的HANDLE句柄),数组下标从0开始,在DELPHI预定义了一些代表不同光标的常量,它的值是从0到-17,您可以直接指定程序使用的光标。如:

  FORM1.CURSOR:=-3表示FORM1采用的光标是CRCROSS(十字)。

  大家可能都会发现构件的CURSOR的属性最多提供十八种常用的CURSOR值,这在很多的情况下是不够的,如:当光标进入一个PANEL面板时光标的形状为一只手,那么PANEL的CURSOR就不能满足这种要求,这时就需要我们自定义一个手的光标并将其赋给PANEL的CURSOR属性。如何实现则可以按以下步骤进行:

  使用资源文件编辑器(IMAGE EDITOR或者RESOURCE WORKSHOP)编写资源文件。

  定义一个光标常量,注意这个常量不能与DELPHI中提供的光标常量相冲突。在FORMCREATE事件中使用WINDOWSAPI当中的LOADCURSOR函数来载入自定义的CURSOR。

  在程序中将自定义的CURSOR分配给PANEL的CURSOR属性。

  下面说明如何将自定义的一只手的鼠标光标赋给PANEL1的CURSOR属性。首先使用IMAGEEDITOR建立一个HAND.RES的文件。之后按如下书写程序代码:

  implementation

  {$R*.DFM}

  const

  Crhand=2;

  procedure TForm1.FormCreate(Sender:TObject);

  begin

  screen.cursors[crhand]:=loadcursor(Hinstance,'hand');

  panel1.cursor:=crhand;

  end;

  除了编写上面的代码以外,我们还需要做的一项工作是将资源文件加入到项目文件当中去,编译指令中的{$Rfilename}伪指令让我们来增加资源文件,让我们来看一看项目文件的代码。

  program PCUR;

  uses Forms,

  HANDin'HAND.pas'{Form1};

  {$R*.RES}

  //这里的*意义为在程序编译以后会产生一个与项目文件同名的资源文件,在这里为PCUR.RES文件,这部分是自动产生的。

  {$Rhand.res}//这部分是我们自己加入的自定义资源文件,这两个资源文件(HAND.RES和//PCUR.RES中的资源都会附加在可执行文件PCUR.EXE的后面。

  begin

  Application.Initialize;

  Application.CreateForm(TForm1,Form1);

  Application.Run;

  end.

  2、资源文件在编写动画程序中的应用

  上面的例子使用的是在资源文件中存储的CURSOR资源,在下面的例子中我们将使用的是在资源文件中提供的ICON资源来编写一个小小的动画程序。在这里动画的产生是利用定时器在一定的时间间隔内产生TIMER事件将存储在资源文件中的ICON依次的绘制在FORM的同一处而产生的。这时要用到画布CANVAS的DRAW方法,其声明如下:

  procedureDraw(X,Y:Integer;Graphic:TGraphic);

  在这个方法当中的参数GRAPHIC可以为:BITMAPS、ICONS、METAFILES。具体的实现方法为:建立DEMO.RES文件,其中含有名为ICON1桰CON6的ICON。并将DEMO.RES加到项目原代码中去(如:上面例子的方法)。

  动画程序的具体代码如下:

  unit donghua;

  interface

  uses Windows,Messages,SysUtils,Classes,Graphics,Controls,Forms,

  Dialogs,ExtCtrls;

  type

  TForm1=class(TForm)

  Image1:TImage;

  Timer1:TTimer;

  procedure FormCreate(Sender:TObject);

  procedure Timer1Timer(Sender:TObject);

  private

  {Privatedeclarations}

  public

  {Publicdeclarations}

  end;

  var

  Form1:TForm1;

  implementation

  var

  wicon:array[0..5] of Ticon;

  //建立TICON类型的数组存储ICON文件

  idx:integer;

  {$R*.DFM}

  procedure TForm1.FormCreate(Sender:TObject);

  var

  iconname:string;

  piconame:pchar;

  begin

  piconame:=stralloc(7);

  //建立PCHAR类型的字符串

  for idx:=0 to 5 do

  begin

  wicon[idx]:=ticon.create;//建立TICON型对象

  iconname:='icon'+inttostr(idx);

  strpcopy(piconame,iconname);

  //将STRING类型转换成PCHAR类型

  wicon[idx].handle:=loadicon(hinstance,piconame);

  //调用WINDOWSAPI中的LOADICON函数

  //载入资源中的ICON

  end;

  strdispose(piconame);//PCHAR类型的删除

  form1.canvas.draw(3,3,wicon[1]);

  //调用DRAW的方法在FORM上画出ICON1

  idx:=1;

  form1.setbounds(0,0,100,100);

  //固定FORM的大小和位置

  end;

  procedure TForm1.Timer1Timer(Sender:TObject);

  //形成动画的定时器事件

  begin

  idx:=idx+1;

  if idx=6 then idx:=1;

  form1.canvas.draw(3,3,wicon[0]);

  form1.canvas.draw(3,3,wicon[idx]);

  end;

  end.

  以上可以作为一个通用的动画程序,我们只需要修改不同的ICON以及增加IDX的大小就可以编出不同的动画应用(同样在资源中可以有其他形式的图形如:BITMAPS这时需要动态创建的是TBITMAPS对象而不是TICON对象)。在两个例子中我们都用到了WINDOWSAPI函数,这些函数在WINDOWS单元中均有说明在这里不加赘述。以上的两个例子只是资源文件的一点点应用,要真正的掌握资源文件在程序设计中的强大作用,还要靠自己在实践中不断的总结。

参考:http://blog.csdn.net/sforiz/article/details/6645110

上一篇:Eclipse中使用Git-让版本管理更简单


下一篇:js日期格式化 扩展Date()