摘 要 本文通過一個編程實例介紹了Delphi 7下編寫不可視ActiveX控件的方法,并給出了源代碼。為使用Delphi編寫其他類型ActiveX控件的讀者提供參考和借鑒。
關鍵詞 Delphi,ActiveX控件,定時器,VCL組件
一、前言
Delphi下有大量優(yōu)秀的且提供源碼的VCL組件,如果想在其他開發(fā)環(huán)境(如VB 6.0,VC 6.0,VS.net等)中使用它們,就必須把這些VCL組件轉換成ActiveX控件。目前,關于把可視化VCL組件轉變?yōu)锳ctiveX控件的資料和例子非常多,而把不可視VCL控件轉換成ActiveX控件的資料卻很少。筆者在網上找到了一個優(yōu)秀且開源的高精度定時器VCL組件,經過反復摸索終于成功將其轉換成一個ActiveX控件。該控件能夠代替VB 6.0中自帶的Timer控件,而且精度更高。在Delphi 7中,Actvieform是基于Delphi 窗體的ActiveX控件,可以像創(chuàng)建一個標準的Delphi窗體一樣創(chuàng)建ActiveForm,而不是把單個組件轉換成ActiveX控件。本文中,筆者將詳細介紹如何利用Actvieform來建立一個高精度的定時器Activex控件。
二、實現(xiàn)
1.在Delphi 7中安裝好要使用的VCL組件
本文中要轉換的高精度定時器VCL組件的名稱為THiResTimer,選擇Delphi主菜單中component菜單下的install component子菜單,彈出安裝控件窗體。在Unit file name中瀏覽選擇HIRESTIM.pas文件,并點擊OK即可。安裝成功后,就會看到THiResTimer控件3個重要的屬性Enabled、Interval、Resolution和一個重要的事件Ontimer。在使用Activeform建立ActiveX控件時,可以不必太多關心VCL組件源碼實現(xiàn)方式,只注意要實現(xiàn)的組件屬性和事件即可。
2.創(chuàng)建一個Activeform
(1)選擇Delphi主菜單中File 菜單下的New,然后單擊New菜單的子菜單other,彈出對象庫窗體。
(2)在 ActiveX頁中雙擊ActiveForm圖標,出現(xiàn)Activeform Wizard(如圖1所示)。
圖1 Activeform Wizard 主界面
(3)如果想控制其他開發(fā)人員使用自己編寫的ActiveX控件,選擇Make control Licensed選項。Delphi會自動生成擴展名為.lic的許可文件和ActiveX控件一起發(fā)布使用。
(4)如果想顯示有關ActiveX控件的任何其他信息,請選擇 Include About Box選項?! ?o:p>
(5)在 Project Name中輸入項目名稱,在 New ActiveX Name中輸入控件名稱,并點擊OK。本文中,項目名稱為mytimerprj,控件名稱為mytimer。
(6)在Delphi工具欄中點擊Save project圖標?! ?o:p>
本例中首先創(chuàng)建一個空白窗體,窗體名稱為mytimer。可以在該窗體上添加想要轉換的任何非可視化VCL組件,在這里放置的是一個名為HiResTimer1的THiResTimer類型控件。
3.Activeform文件生成以后,接下來要做的就是編輯ActiveX控件的屬性或事件。選擇Delphi主菜單中View菜單下的type library子菜單,彈出如圖2所示的Type Library editor ??梢灾苯釉谄渖暇庉媽傩曰蚴录?,先把系統(tǒng)默認生成的屬性和事件都刪除,圖2中IMyTimer的所有子項是屬性,IMyTimerEvents的所有子項是事件。然后在IMyTimer后添加下列屬性:
圖2 Type Library 屬性設置窗口
Enabled:VARIANT_BOOL
Interval:long
Resolution:long
當改變上面屬性值時,HiResTimer1控件對應的屬性相應改變。 程序代碼如下:
//在 保護字段聲明三個變量
protected
{ Protected declarations }
FInterval:integer;
FResolution:integer;
FEnabled:boolean;
//改寫DefineProperties虛方法,用以實現(xiàn)控件屬性值的持久化。
procedure DefineProperties(Filer: TFiler); override;
procedure TMyTimer.DefineProperties(Filer: TFiler);
begin
inherited;
filer.DefineProperty('MyProperty',LoadProperty,StoreProperty,true);
//LoadProperty 和StoreProperty 是以函數(shù)為參數(shù)
end;
// 在DefineProperties方法中需要一個寫變量函數(shù)作為參數(shù)。
procedure StoreProperty(Writer:TWriter);
procedure TMyTimer.StoreProperty(Writer:TWriter);
begin
writer.WriteInteger(FInterval);
writer.WriteInteger(FResolution);
writer.WriteBoolean(FEnabled);
//持久化三個保護字段變量
end;
//在DefineProperties方法中需要一個讀變量函數(shù)作為參數(shù)。
procedure LoadProperty(Reader:TReader);
procedure TMyTimer.LoadProperty(Reader:TReader);
begin
FInterval:=reader.ReadInteger;
FResolution:=reader.ReadInteger;
Fenabled:=reader.ReadBoolean;
hirestimer1.Interval:=FInterval;
hirestimer1.Resolution:=FResolution;
hirestimer1.Enabled:=FEnabled;
// 讀取屬性值
end;
// 當屬性值改變時,修改HiResTimer1控件對應的屬性值。
function TMyTimer.Get_Enabled: WordBool;
begin
Result := FEnabled;
end;
procedure TMyTimer.Set_Enabled(Value: WordBool);
begin
FEnabled := Value;
hirestimer1.Enabled :=FEnabled;
//設置hirestimer1.Enabled 決定定時器是否工作。
end;
function TMyTimer.Get_Interval: Integer;
begin
result:=Finterval;
end;
function TMyTimer.Get_Resolution: Integer;
begin
result:=Fresolution;
end;
procedure TMyTimer.Set_Interval(Value: Integer);
begin
Finterval:=value;
hirestimer1.Interval:=Finterval;
// hirestimer1.Interval的作用和VB自帶的Timer定時器Interval屬性功能一致。
end;
procedure TMyTimer.Set_Resolution(Value: Integer);
begin
Fresolution:=value;
hirestimer1.Resolution:=Fresolution;
// hirestimer1.Resolution 屬性保證定時器的精度。數(shù)值越小精度越高。
end;
添加完屬性后,還要在IMyTimerEvents中加入Ontimer事件,首先在私有段中定義一個TimerEvent 函數(shù)。然后在程序Initialize段中讓HiResTimer1.OnTimer = TimerEvent;而在TimerEvent 事件中又調用FEvents.OnTimer,這樣就能在Ontimer事件中捕獲到HiResTimer1.OnTimer事件。程序實現(xiàn)如下所示:
procedure TMyTimer.Initialize;
begin
inherited Initialize;
HiResTimer1.OnTimer:=TimerEvent;
end;
procedure TMyTimer.TimerEvent(Sender: TObject);
begin
if FEvents <> nil then FEvents.OnTimer;
end;
4.因為我們要編寫的是一個非可視Activex 控件,所以控件在用于VB等開發(fā)環(huán)境時還應具有如下特征即:控件在designtime 時尺寸應固定且可見,而在 runtime時不可見。以下代碼即可實現(xiàn)尺寸固定:
constructor Create(AOwner: TComponent); override;
constructor TMyTimer.Create(AOwner: TComponent);
begin
self.AutoSize:=true;
inherited create(aowner);
self.width:=32;
self.height:=32;
self.Constraints.MaxHeight:=32;
self.Constraints.MaxWidth:=32;
self.Constraints.MinHeight:=32;
self.Constraints.MinWidth:=32;
end;
下面這行代碼即可實現(xiàn)ActiveX控件在designtime 時可見而runtime時不可見的功能。
TActiveFormFactory.Create(
ComServer,
TActiveFormControl,
TMyTimer,
Class_MyTimer,
1,
`97B151A-9D6F-4DCC-BAA8-E4B51D2DD68B}`
OLEMISC_INVISIBLEATRUNTIME, //修改后
//OLEMISC_SIMPLEFRAME or OLEMISC_ACTSLIKELABEL, 默認參數(shù)
tmApartment);
5.程序編好后,選擇Delphi主菜單中 Run 菜單下的Register ActiveX Server,編譯并注冊 ActiveX控件。這樣就可以在VB等其他開發(fā)環(huán)境中使用,圖3中就是用VB 6.0調用mytimer控件的例子。用戶可以參考Delphi和VB源代碼并實際運行。
圖 3 調用mytimer控件
三、結語
通過編寫不可視ActiveX控件基本的程序框架,便可以編寫其他類型的非可視化ActiveX控件,如加密解密,數(shù)值計算,系統(tǒng)信息,通用對話框等。使用Activeform編寫ActvieX控件的優(yōu)點之一是可以把那些不提供源代碼的VCL組件也能轉換成ActiveX控件,通過ActiveX控件使Delphi能夠和其他可視化開發(fā)工具一起混合編程。
|