關於把設計時程式碼從執行時程式碼中分離出來的問題-Proxies.pas- |
|
qoo1234
版主 發表:256 回覆:1167 積分:659 註冊:2003-02-24 發送簡訊給我 |
自從Delphi6出來以後,一個經常被提到的問題是Proxies.pas檔案從源檔案中消失了。
這個改變是大趨勢的一個部分。Borland在Delphi 5中沒有裝載DsgnIntf.dcu,這顯然是要強迫迎合Delphi和C++Builder的許可協議。執行時程式碼在很多元件中常被不經意地用到。在某些方面Borland鼓勵:如果你運用新的元件嚮導,你將發現這個嚮導只創建了一個單元,它把元件執行時的框架程式碼和註冊函數放在同一個單元中。 在Delphi6中Borland更進一步,不僅用DesignIntf替換了DsgnIntf,而且屬性編輯器也被放進了DesignEditors,DesignMenus,DesignWindows和其它的一些設計檔案裡。特別是DesignEditors使用了其它的一個名叫Proxies的IDE檔案。(Proxies程式碼放在DesignIDE.bpl檔案中。)不用說這些改變將會產生編譯時的錯誤。 如果你的執行時程式碼已經與設計時程式碼分開了,那麼就很容易修改。打開設計時包,然後選擇一個目錄,點擊Add按鈕。填寫designide.dcp和點擊確定。重新編譯你的包,這時錯誤已經沒有了。 如果你的設計時程式碼和執行時程式碼已經混合在一起了,那應該怎麼解決呢?在Delphi裡DesignIDE.bpl不是一個可以再分發的包。因此,即使是只是設計時包使用了元件的執行時程式碼或是只是元件dcu用了都將產生問題。 99.99%的情況事實上很容易解決。你的執行時程式碼事實上沒有使用設計時程式碼;問題是沒有合適的分開。 設計時包應該包括: 1、所有的註冊宣告。
2、所有的屬性編輯器。
3、所有的元件編輯器。
4、將需要DesignIDE和每一個保存元件自己的執行時包。 執行時包應該包括: 1、元件自己。
2、任何編輯器也許會用到的元件可能自己在執行時調用的表單。 維一有點混惑的地方是:屬或元件是否使用了一個表單。假如這個表單在執行時對於元件是可用的,那麼它應該包含在執行時包裡。如果它只是在設計時可使用,那它就應該包含在設計時包裡。一個常見的錯誤是誤認這個表單本身是一個編輯器,但事實上它不是。而是元件編輯器調用了這個表單,它是設計時編輯器。 你應該養成一個把元件分開成兩個包的習慣,即使是你只在程式中靜態地進行鏈接,因為混合執行時和設計時程式碼將使你的程式碼膨脹。你的設計時程式碼在執行時不會被執行,但是鏈接器不會知道,所以把它也一起鏈接進去了。(這就是為什麼DsgnIntf要設法鏈接進去的原因。) 讓我們看一個簡單的例子,瞭解如何把設計時程式碼從執行時程式碼中分離出去:
{ TMixedComponent } TMixedComponent = class(TComponent) private FFileName: String; published property FileName : String read FFileName write FFileName; { Published declarations } end; { TMixedFileNameProperty } TMixedFileNameProperty = class(TPropertyEditor) function AllEqual: boolean; override; procedure Edit; override; function GetAttributes: TPropertyAttributes; override; function GetValue: string; override; procedure SetValue (const Value: string); override; end; procedure Register; implementation procedure Register; begin RegisterPropertyEditor(TypeInfo(string), TMixedComponent, 'FileName', TMixedFileNameProperty); RegisterComponents('Samples', [TMixedComponent]); end; function TMixedFileNameProperty.AllEqual: boolean; var FirstVal: string; i: Integer; begin FirstVal := GetStrValue; Result := True; i := 1; while Result and (i < PropCount) do begin Result := Result and (GetStrValueAt(i) = FirstVal); Inc(i); end; end; procedure TMixedFileNameProperty.Edit; var Dlg: TOpenDialog; begin Dlg := TOpenDialog.Create(Application); try with Dlg do begin Title := 'File for ' TComponent(GetComponent(0)).Name; FileName:= Value; if Execute then Value := FileName; end; finally FreeAndNil(Dlg); end end; function TMixedFileNameProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog] end; function TMixedFileNameProperty.GetValue: string; begin Result := GetStrValue; end; procedure TMixedFileNameProperty.SetValue(const Value: string); begin SetStrValue(Value); end; end.把設計時程式碼從執行時程式碼中分離出去的最簡單方法是,把所有需要DesignIntf 和DesignEditors 程式碼放入它們自己的單元中去,那個單元將要添加使用元件單元的宣告。元件自己不需要知道那個自己運作的IDE編輯器。首先,把DesignIntf 和 DesignEditors 單元從元件單元的Uses部分刪除掉,然後讓編譯/鏈接器告訴你哪些類需要移到它們自己的單元中去: [Error] MixedComponent.pas(23): Undeclared identifier: 'TPropertyEditor' [Error] MixedComponent.pas(23): Class type required [Error] MixedComponent.pas(24): Method 'AllEqual' not found in base class [Error] MixedComponent.pas(25): Method 'Edit' not found in base class [Error] MixedComponent.pas(26): Undeclared identifier: 'TPropertyAttributes' [Error] MixedComponent.pas(27): Method 'GetValue' not found in base class [Error] MixedComponent.pas(28): Method 'SetValue' not found in base class [Error] MixedComponent.pas(35): Undeclared identifier: 'RegisterPropertyEditor' [Error] MixedComponent.pas(35): Undeclared identifier: 'TMixedFile' [Error] MixedComponent.pas(46): Undeclared identifier: 'GetStrValue' [Error] MixedComponent.pas(49): Undeclared identifier: 'PropCount' [Error] MixedComponent.pas(51): Undeclared identifier: 'GetStrValueAt' [Error] MixedComponent.pas(51): Operator not applicable to this operand type [Error] MixedComponent.pas(64): Undeclared identifier: 'GetComponent' [Error] MixedComponent.pas(65): Undeclared identifier: 'Value' [Error] MixedComponent.pas(75): Undeclared identifier: 'paDialog' [Error] MixedComponent.pas(80): Undeclared identifier: 'GetStrValue' [Error] MixedComponent.pas(85): Undeclared identifier: 'SetStrValue' [Fatal Error] JOComponents.dpk(33): Could not compile used unit 'MixedComponent.pas' 下一步是創建一個新的單元存放這些程式碼。可以命名為類似MixedComponentReg的名子。把Register函數也移到那個單元中去。下面我們可以從錯誤信息中得知哪些需要移走。第一個錯誤信息是[Error] MixedComponent.pas(23): Undeclared identifier: 'TPropertyEditor',這個信息指出了一個繼承自那個設計時單元的類。這是個很清楚的指示,它指明了它是設計時程式碼和這個類要被移到一個新創建的單元。 到此,執行時包將會被成功編譯(如果還不行,繼續把設計時程式碼從單元中移去,直到沒有錯誤產生)。現在元件在你的應用程式執行時已不再需要Proxies.pas和其它設計時單元了。這個執行時元件非常簡單,如下: unit MixedComponent; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs; type { TMixedComponent } TMixedComponent = class(TComponent) private FFileName: String; published property FileName : String read FFileName write FFileName; { Published declarations } end; implementation end.這最後一步就是把你的元件和它的屬性編輯器編譯到一個設計時包中,然後安裝到IDE中去。 通過File | New | Other 選擇 package創建一個新的包。調出包選項,選擇design-time only,給Description 項填一個描述文字。選擇Requires folder,點擊Add按鈕。在Requires Package 編輯對話框填寫Designide.dcp,點擊OK。同樣,為你的元件執行時包添加dcp。在這種情況下,它放在了JOComponents.dpk,因此JOComponents.dcp被添加到requires項。在requires裡有:JOComponents, designide 和 rtl。最後,選擇包含目錄,添加MixedComponentReg.pas 到包裡。 到現在我們已經基本完成了!打開MixedComponentReg.pas 添加一對單元到uses部分,這要看你的元件或屬性編輯器是否要在宣告中使用這個元件(一些複雜的編輯器有時需要知道這個元件的存在)。如果是這樣,把它加到Interface的uses部分。否則,加到implementation的uses部分。DesignIntf和DesignEditors就放到Interface的uses裡。SysUtils, Forms, Dialogs, 和 Classes 在內部的屬性編輯器的不同地方使用,因此就放到implementation部分。最後的MixedComponentReg應該像下面這樣: unit MixedComponentReg; interface uses DesignIntf, DesignEditors; type { TMixedFileNameProperty } TMixedFileNameProperty = class(TPropertyEditor) function AllEqual: boolean; override; procedure Edit; override; function GetAttributes: TPropertyAttributes; override; function GetValue: string; override; procedure SetValue (const Value: string); override; end; procedure Register; implementation uses MixedComponent, SysUtils, Forms, Dialogs, Classes; procedure Register; begin RegisterPropertyEditor(TypeInfo(string), TMixedComponent, 'FileName', TMixedFileNameProperty); RegisterComponents('Samples', [TMixedComponent]); end; function TMixedFileNameProperty.AllEqual: boolean; var FirstVal: string; i: Integer; begin FirstVal := GetStrValue; Result := True; i := 1; while Result and (i < PropCount) do begin Result := Result and (GetStrValueAt(i) = FirstVal); Inc(i); end; end; procedure TMixedFileNameProperty.Edit; var Dlg: TOpenDialog; begin Dlg := TOpenDialog.Create(Application); try with Dlg do begin Title := 'File for ' TComponent(GetComponent(0)).Name; FileName:= Value; if Execute then Value := FileName; end; finally FreeAndNil(Dlg); end end; function TMixedFileNameProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog] end; function TMixedFileNameProperty.GetValue: string; begin Result := GetStrValue; end; procedure TMixedFileNameProperty.SetValue(const Value: string); begin SetStrValue(Value); end; end.剩下的就是編譯和安裝設計時包了。現在執行時程式碼已經完全從設計時程式碼中分了出來。這是一個簡單的例子,它唯一有點複雜的是屬性編輯器使用一個表單獲得資料,而且那個表單在執行時也可以利用。在這種情況下,表單被保留在執行時包裡,設計時屬性編輯器會從執行時包裡調用這個表單。 網海無涯,學無止境! |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |