隨筆-17  評論-64  文章-79  trackbacks-1
          一、初級應用篇
            資源文件一般為擴展名為res的文件,在VC中資源文件用得非常普遍,但Delphi在其聯機幫助中對資源文件沒
          作什么介紹。其實利用其自帶的資源編譯工具BRCC32.EXE(一般位于DelphiBIN目錄下),我們完全可以做出跟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控件,在需要顯示的地方寫以下代碼(其中"mypic"為位圖資源文件中的名
          稱):
             Var mymap:Hbitmap;
             begin
             mymap:=LoadBitmap(hinstance,'mypic');
             Image1.picture.Bitmap.Handle:=mymap;
             end;
             〈3〉AVI文件的調用
            新建一工程,添加一Animate控件,在需要的地方加入(其中myAVI為視頻文件在資源文件中的名稱):
             animater1.resname:='myAVI';
             animater1.Active:=true;
             〈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;
            
             二、中級應用篇:
            上面我們已經知道如何把一副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,"輸入文字或打開文件后按需要點擊按鈕即可轉換!"
             }
             另外兩個Dll用同樣的方法生成。
            第二步是Brcc32編譯為Res文件后用上面的方法得到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的程序就是利用了這個方
          法.
           
          三、高級應用篇
             Delphi是個很有效率的開發工具,但是它有一個缺點就是生成的EXE文件太大。一個程序就算只有一個空窗口
          體積也有286KB。如果直接用API來寫的話程序體積是小了,但是又太繁瑣,無法立即看到界面效果,根本談不上是
          可視化開發。其實并非“魚與熊掌不可兼得”,利用資源文件我們就可以輕松達到這個目的。
            在開始之前,我們需要一個可以編輯資源文件的工具。這類工具很多,比如說Resource WorkShop就是非常好
          的一個。如果一時找不到,利用VC的編輯器來也是可以的。下面我們就以VC的為例示范如何創建一個窗口資源文
          件。
            運行VC,打開菜單“File/New”,將出現一個多項選擇頁。我們選擇“Files/Resource Template”,在右邊
          的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/Iconv/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; out
          Directory: 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.
           
          posted on 2007-05-25 22:39 飛鳥 閱讀(691) 評論(0)  編輯  收藏 所屬分類: Delphi
          主站蜘蛛池模板: 威信县| 阿坝| 张掖市| 禹城市| 平罗县| 新田县| 元谋县| 米泉市| 邯郸市| 彭水| 双城市| 赣榆县| 临江市| 和平区| 木里| 双牌县| 杭州市| 军事| 黄大仙区| 南宁市| 五台县| 甘泉县| 年辖:市辖区| 嘉祥县| 丰镇市| 远安县| 镇安县| 肥东县| 义马市| 景谷| 昌平区| 闽清县| 栖霞市| 雅安市| 榕江县| 临洮县| 丹凤县| 湘西| 宽甸| 四子王旗| 唐海县|