在這篇文章中我們將建立壹個和時間有關的組件 這個組件通過設置它的不同狀態有以下基本功能 顯示系統的當前時間(包括設置鬧鐘) 跑表 倒計時 這是壹個簡單的例子 然而我們將在這個例子中盡可能多的用到delphi在組件開發中的多種特性 妳可以通過以下列舉出的本文涉及特性有選擇的閱讀
·組件和組件包
·組件的屬性類別
·組件的屬性編輯器
·組件編輯器
壹 組件和組件包 以及壹些妳應該知道的文件類型
組件和組件包的關系就如同普通工程中unit和工程文件的關系壹樣 通常妳所安裝的組件都是以組件包的形式發布的 壹個組件包中可以有很多個組件 在組件開發中 組件包就是項目的工程文件 為了開始開發我們的組件(我們把他叫做TClock)並將它包括在我們自己的組件包(ClockPackage)中 我們選擇Fileànewàother在彈出的窗口中的New頁選擇Package新建壹個組件包 得到壹個組件包窗口 查看這個組件包的原文件( dpk) 得到以下代碼
package ClockPackage;
{$R * res}
{$ALIGN }
{$ASSERTIONS ON}
……
……
{$DESCRIPTION Our Clock Pack }
{$IMPLICITBUILD OFF}
requires
rtl;
end
這個文件其實就是組件開發中的工程文件 requires關鍵字指示了組件包所需組件包的列表 隨著向組件包中加入組件(類似於單元文件) 妳還會看到contains關鍵字 指示了組件包所包含的組件 妳可以通過組件包窗口中的add和remove按紐來添加新的組件和刪除已有的組件 另外這個代碼中所包含的大量的編譯器開關大多都可以在組件包窗體上的Options中設置 這裏需要補充說明的是組件包的 種重要屬性(都在Options中) Designtime Only Runtime Only Designtime and runtime(這 個詞的意思有英語基礎的朋友應該都知道吧) 對於大多數的組件包我們只要選擇最後壹個就可以了 然而有些組件包設計為只運行時(這樣妳用這套組件開發的程序不能脫離組件而單獨運行 組件包也不能被安裝) 有些組件包被設計為只設計時(這將在後文有更詳細的說明)
了解了組件和組件包 我們對組件開發中可能出現的壹些妳沒有見過的文件做壹些說明 dpk文件既組件包的原代碼 bpl文件 組件包編譯後的結果 在沒有發布dpk的情況下可以通過bpl來安裝組件包到delphi(ProjectàOptionsàPackagesàadd) pas在這裏就是組件包中組件的原代碼了 dcu為pas編譯後的結果 在妳選擇將組件包含進組件包時(contains關鍵字) 妳可以選擇發布原代碼或是不發布(dcu文件) dcp如果妳將組件作為運行時組件 連接器將使用該文件
二 開始開發組件
了解了上面的知識後 我們就可以開始開發組件了!在組件窗體中單擊add 選擇NewComponent頁 在第壹個組合框中選擇我們的組件將要繼承自哪個類(通常新的組件是通過繼承已有的組件來開發的) 由於這個組件的主要作用是要顯示時間 跑表 倒計時種的文字信息 所以我們選擇繼承自TCustomLabel(由於我們並不需要Tlabel的全部功能 我們選擇了能夠隱藏Tlabel屬性並有選擇的發布它的屬性的TcustomLabel類) 接下來為我們的新組件取壹個名字Tclock 然後指定我們想把組件安裝到哪壹個頁中 這裏我們自己鍵入壹個ClockAndTime頁 這將出現在RegisterComponents過程中(後面會詳細說明) 選擇好文件保存的路徑後(最好把它和組件dpk包放在同壹目錄)確認 這是組件包窗體中的contains下已經多了我們剛才建立的組件的文件 雙擊它開始編寫代碼
在代碼中我們需要註意在interface部分的壹個新的過程 procedure Register;(註意 delphi規定Register的R必須大寫 這是壹個保留字) 這個過程是作為每壹個組件所必須有的 它完成組件的註冊 包括組件本身以及如屬性編輯器等多種組件特性的註冊)
procedure Register;
begin
RegisterComponents( ClockAndTime [TClock]);
//這個過程註冊組件本身 註意到前面定義的ClockAndTime頁了嗎?
//這裏在後面還會出現壹些新的過程 包括註冊組件的屬性類別等等
end;
組件的代碼由於假設妳已經熟悉delphi開發(它和壹般開發沒什麽不同) 我們就直接貼出來並加上適當的註釋
unit Clock;
interface
uses
SysUtils Classes Controls StdCtrls ExtCtrls;
type
TState=(StClock StRunClock StBackClock);//定義枚舉類表示控件的 種狀態 時鐘 跑表 倒計時鐘
TClock = class(TCustomLabel)
private
fState:TState;
fTimer:TTimer;//為什麽使用這個組件作為我們組件的私有成員就不用說了吧
RCD:array[ ] of integer;//跑表中的各個數位
fBeginTime:string;//到計時時的開始時鐘 之所以沒用TTime類型是為了在後面演示屬性編輯器
fWakeTime:string;//鬧鐘時間 出於和上面同樣的理由
fAllowWake:boolean;//是否開啟鬧鐘功能
fOnWakeUp:TNotifyEvent;//為了使組件更加完美 我們允許組件用戶能夠響應鬧鐘到來時的時件
fOnTimeUp:TNotifyEvent;//同上能夠響應倒計時種完成時的事件 我們將發布這兩個事件
function GetActive:boolean;//控制Timer是否工作以控制 種狀態的鐘是否工作
procedure SetActive(Value:boolean);
procedure SetState(Value:TState);
procedure SetBeginTime(Value:string);
procedure SetWakeTime(Value:string);
protected
procedure WalkClock(sender:TObject);//作為時鐘時走種的事件
procedure RunClock(sender:TObject); //跑表
procedure BackClock(sender:TObject);//倒計時
public
constructor Create(AOwner:TComponent);override;//完成壹些初始化工作
procedure ReSetRunClock; //跑表和倒計時都需要壹個復位方法給組件使用者調用
procedure ReSetBackClock;
published
property State:TState read fState write SetState default StClock;//默認為時鐘狀態
property Active:boolean read GetActive write SetActive;//控制 種狀態的鐘是否工作
property BeginTime:string read fBeginTime write SetBeginTime;
property WakeTime:string read fWakeTime write SetWakeTime;
property AllowWake:boolean read fAllowWake write fAllowWake;
property OnWakeUp:TNotifyEvent read fOnWakeUp write fOnWakeUp;
property OnTimeUp:TNotifyEvent read fOnTimeUp write fOnTimeUp;
//最後我們再發布壹些被TCustomLabel所隱藏而我們又需要的屬性
property Align;
property Alignment;
property Color;
property Font;
property ParentColor;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property Visible;
property Transparent;
property OnClick;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents( ClockAndTime [TClock]);
end;
{ TClock }
constructor TClock Create(AOwner: TComponent);
begin
inherited Create(AOwner);
//設置默認值
fTimer:=TTimer Create(self);
//將它屬於我們的組件 這樣便不用編寫析構函數 而可以自動在釋放本組件時釋放Timer
Active:=false;
AllowWake:=false;
State:=StClock;
BeginTime:= : : ;
WakeTime:= : : ;
end;
function TClock GetActive: boolean;
begin
result:=fTimer Enabled;
end;
procedure TClock SetActive(Value: boolean);
begin
fTimer Enabled:=Value;
end;
procedure TClock SetState(Value: TState);
var
i:integer;
begin
case Value of
StClock:
begin
Active:=false;
fTimer Interval:= ;
fTimer OnTimer:=WalkClock;
Active:=true;
end;
StRunClock://由於Time類型不好處理微秒操作 我們只有手工模仿這個操作 代碼會稍微煩瑣
begin
Active:=false;
for i:= to do RCD[i]:= ;
Caption:=IntToStr(RCD[ ])+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ])+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ]);
Caption:=Caption+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ])+IntToStr(RCD[ ]);
fTimer Interval:= ;
//經過測試 這個秒表的效果很好 然而這只是壹個技術上的演示
//實際上這麽頻繁( / 秒)的不斷執行RunClock會使CPU的占用壹直達到 %
//這並不是壹個好註意 事實上要想在跑表中顯示微秒級別並做到合理的占用CPU
//這需要更加靈活和復雜的編程
fTimer OnTimer:=RunClock;
end;
StBackClock:
begin
Active:=false;
Caption:=BeginTime;
fTimer Interval:= ;
fTimer OnTimer:=BackClock;
end;
end;
fState:=Value;
end;
procedure TClock SetBeginTime(Value: string);
begin
try
StrToTime(Value);
fBeginTime:=Value;
if State=StBackClock then
begin
Active:=false;
Caption:=Value;
end;
except
on Exception do
begin
fBeginTime:= : : ;
if State=StBackClock then Caption:= : : ;
end;
end;
end;
procedure TClock SetWakeTime(Value: string);
begin
try
StrToTime(Value);
fWakeTime:=Value;
except
on Exception do
begin
fWakeTime:= : : ;
end;
end;
end;
procedure TClock WalkClock(sender: TObject);
begin
Caption:=TimeToStr(Time);
if AllowWake and (StrToTime(Caption)=StrToTime(WakeTime)) then
begin
Beep;//蜂鳴器
if Assigned(fOnWakeUp) then
fOnWakeUp(self);
end;
end;
procedure TClock RunClock(sender: TObject);
begin
RCD[ ]:=RCD[ ]+ ;
if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;
if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;
if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;
if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;
if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;
if RCD[ ]= then begin RCD[ ]:=RCD[ ]+ ;RCD[ ]:= ; end;
if RCD[ ]= then RCD[ ]:= ; //我們的跑表最多可計 個小時;
Caption:=IntToStr(RCD[ ])+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ])+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ]);
Caption:=Caption+IntToStr(RCD[ ])+ : +IntToStr(RCD[ ])+IntToStr(RCD[ ]);
end;
procedure TClock BackClock(sender: TObject);//可以在壹天之類的時間倒計時
begin
if StrToTime(Caption)<>StrToTime( : : ) then
Caption:=TimeToStr(StrToTime(Caption) )
else
begin
Active:=false;
Beep;
if Assigned(fOnTimeUp) then
fOnTimeUp(self);
end;
end;
procedure TClock ReSetBackClock;
var
i:integer;
begin
if State=StRunClock then
begin
Active:=false;
for i:= to do RCD[i]:= ;
Caption:= : : : ;
end;
end;
procedure TClock ReSetRunClock;
begin
if State=StBackClock then
begin
Active:=false;Caption:=BeginTime;
end;
end;
end 為了測試我們的組件 現在妳就可以安裝這個組件包並建立壹個應用測試它了 點擊組件包窗體中的install即可(註意 壹但妳安裝了組件包 當妳想對組件修改時 在修改了原代碼以後只用點擊組件窗體的pile就可以了更新組件了) 這時delphi的組件頁的最後多出了我們定義的頁 其中有了我們的組件!
lishixinzhi/Article/program/Delphi/201311/24840