New Term
每個Windows應用程序都使用資源。資源(Resources)不是可執行代碼,但它屬於程序的一部分元素。
典型的Windows程序的資源有:
- 加速器(Accelerators)
- 位圖(Bitmaps)
- 光標(Cursors)
- 對話框(Dialog boxes)
- 圖標(Icons)
- 菜單(Menus)
- 數據表(Data tables)
- 字串表(String tables)
- 版本信息(Version information)
- 用戶定義的專用資源(User-defined specialty resources)如聲音和視頻文件
Note
用Project Options對話框的Version Info頁面可輕松地將版本信息加到Delphi工程中。如下圖:
資源一般包括在擴展名為.rc的資源腳本文件中(resource script file),資源文件就是文本文件。資源文件用資源編譯器編譯,並在鏈接時加到應用程序的.exe文件中。
通常大家認為資源要加到可執行文件中,但是有些資源,如位圖、字符串表、波形文件,既可以放到外部文件中(.bmp、.txt、.wav),也可加到.exe文件並包含到應用程序文件中。
把資源放到.exe文件中有兩條主要優點:
- 存取資源的速度更快。因為在一個可執行文件中查找資源花的事件比從磁盤文件中裝入資源花的時間要少。
- 程序和資源可一起包含到單個單元(即.exe文件)中,而不需要一大堆的支持文件。
它的不足之處是:會使.exe文件稍稍增大。其大小不會比外部資源文件加可執行文件大。但是增加大小會使加載該程序的時間加長。
是把資源存為外部資源文件,還是把資源放到.exe文件中,這得由編程人員自己定。但要記住的是:這兩種方式用哪一種都行(甚至可以在同一個程序中使用兩種方式)。
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安裝目錄的Bin目錄下,如果不是,則必須輸入BRCC32.EXE的完整路徑。這個資源編譯器速度非常快,甚至不等察覺,它就把資源腳本文件編譯完成了。
2、 使用批處理文件工程(Using a Batch File Project)
添加一個批處理文件到工程組,與從命令行編譯一樣簡單,並且還有一個好處:保證資源文件總是最新的。要搞清楚批處理文件如何工作,可執行下面的步驟:
(1)創建一個新的應用程序;
(2)選擇【View | Project Manager】打開“Project Manager”工程管理器,如下圖:
(3)點擊“Project Manager”工具欄上的“Add New Project”按鈕,顯示Object Repository對象庫,如下:
(4)雙擊Batch File圖標來創建文件工程。將該批處理文件工程以Project2的名稱添加到“Project Manager”中,如下:
(5)用鼠標右鍵點擊批處理文件節點並選擇Save,將文件保存為test.bat;
(6)用鼠標右鍵再次點擊批處理文件節點並選擇【Edit/Options】,會彈出“Batch File Options”對話框;
(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文件中的二進制資源,可在主窗體單元的開頭處插入下面一行:
{$R myfile.res}
就這么簡單!只要指定的文件存在,Delphi就會在鏈接時把這個編譯過的資源添加到可執行文件中。
使用資源的樣本程序(A Sample Program Using Resources)
下面的清單中,列出了Jumping Jack的程序的主窗體單元。這個程序顯示一個帶聲音效果的簡單動畫。主窗體上有兩個按鈕:一個Image組件和一個Label組件。Jumping Jack程序說說明了資源在Delphi應用程序中的使用。它特別說明了如何加載以資源文件形式存儲的位圖,如何加載並顯示字符串資源,以及如何播放資源文件中的波形音頻。清單后面還列出了部分資源文件。先看看清單,然后再分析程序。
JJMain.pas清單
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清單
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啟動后的界面。
為應用程序創建附加資源不是什么高深的學問,但也不是很簡單的事情。要搞清楚它們如何協調配合要花一定的事件。
以上代碼均在Delphi7中測試通過,示例代碼下載:JumpingJack.rar