接下來要動手來做一個組件了,我想了一個計數器組件,功能方面是比較簡單的,但這不是本章的重點,這一章的重點是說明一個組件的制作全過程。在其中可以學到很多組件制作的技巧,當然這些也是我從書上學得的。
這是一個可以計數的組件,為了簡單,我以秒為單位,當開始時,他就從0開始增加,並顯示出來,到3600時,它又回到0,如此循環。當然它也可以停止,暫停,繼續。另外,他還有一個時間事件,即可以設定每隔多少時間來觸發這個事件,這倒是一個好的功能,我們可以設半個小時觸發事件,在事件處理函數中來一個聲音,然後睡個覺,半個小時後,就由這個聲音來提醒你起床了。
我們一開始不要新建組件單元,而是把它當成一個工程中的一個類來應用,這樣更易於調試,於是我們新建一個工程,又新建一個空白單元用於放置這個類
一、確定父類:
接下來給這個類起名叫TTimeCount,那麼它的父類應該是什麼呢,它要能顯示出來,得有一個容量來讓他顯示,TPanel是個不錯的選擇,我看了一下源碼,發覺TPanel什麼也沒有做,只是把它的父類TCustomPanel的屬性顯化出來(這個等一下講),TCustomPanel把好多的屬性聲明為Protected,為他的子類提供了選擇,他的子類如果要使這些屬性能在對象察看器中看到,可以在Published重新聲明一下,如果不想,則不用去理會他。而我們的計數器組件正好不用那麼多屬性,正好合適。於是我決定用TCusomPanel為父類
類建立如下:
TTimeCount=class(TCustomPanel)
private
protected
public
published
end;
二、確定成員,方法和屬性和事件
FCount; 只讀私有成員,保存計數值
FActive:Boolean; /確定是否發生類的時間間隔事件
FInterval:TInterval; 這個可以設置時間事件觸發間隔,本來用整型值會好一些,但會了學習起見,這裡用了一個枚舉形的,在Type中聲明如下:
TInterval=(TenM,TwentyM,ThirtyM,FortyM,FiftyM,SixtyM);
分別表示十分鐘到六十分鐘。
TimeLen,TimeNum:integer;這兩個用在類的時間事件發生的確定上,與外界隔絕。
FTimeOut:TNotifyEvent;時間間隔事件的方法指針,通過調度方法實現他與外部的處理函數關聯。
我們要它能以秒為單位來計數,則要涉及到時間的應用,所以就有了這個最重要的成員:
FTimer:TTimer;
這個成員對象要在類構造函數中實例化它,並賦與他的屬性值,還要在析構函數在釋放它。
如下:
//構造函數,繼承父類的構造函數,並初始化類中的成員。
constructor TTimeCount.Create(AOwner:TComponent);
//創建時間控件並設置相關的參數
procedure CreateTimer;
begin
FTimer:=TTimer.Create(self);
FTimer.Enabled:=False;
FTimer.Interval:=1000;
FTimer.OnTimer:=FTimerTimer;
end;
begin
inherited Create(AOwner);
CreateTimer;
end;
//析構函數,先釋放時間控件,再繼承父類的析構函數
destructor TTimeCount.Destroy;
begin
FTimer.Free;
inherited Destroy;
end;
構造函數中還要設置該組件的外觀和默認值,這裡把它刪去,到源代碼再貼出來。
其中
FTimerTimer;是很重要的函數,在該類中有聲明:
procedure FTimerTimer(Sender:Tobject);//時間控件的事件處理函數
在這個處理函數中,實現了計數值的遞增並顯示到容器中,此外,還在判斷類的時間事件是否有足夠條件觸發了,如果有則調用DoTimeOut;過程,這個就是事件的調度函數啦:
//事件調度函數,將外部的事件處理函數和該類的事件方法指針聯系起來
procedure TTimeCount.DoTimeOut;
begin
if Assigned(FTimeOut) then
FTimeOut(Self);
end;
而屬性則是根據私有成員來設定了:
public
property Count:Integer read FCount default 0; //計數值的只讀屬性,這個屬性不能聲明在Published中,因為它是只讀的,只在程序運行時通過它來得到計數值。
published
property Interval:TInterval read FInterval write SetInterval Default TenM;
property Active:boolean read FActive write SetActive default false;
property OnTimeOut:TNotifyEvent read FTimeOut write FTimeOut;
此外還有幾個自定義方法即
procedure pause; //暫停計數
procedure Resume;//從暫停的計數開始計數。
procedure stop;//停止
procedure start;//開始計數
都比較簡單。
三、父類屬性的顯化:
TCustomPanel及其父類有好多的屬性設為Protected,使其子類可以有更靈活的選擇,是否把這些屬性顯示到對象察看器中,如果想,則到Published中重新聲明這些屬性就可以,我參考了一下TPanel的源碼,並按需要選擇了其中的一些屬性聲明到Published中,注意哦,事件也是屬性,只要你把它顯化出來,就可以設置處理事件了。
以下是計數組件的源碼,相信有了上面的講解,應該不會很難了:
unit CountUnit;
interface
uses
SysUtils,Classes,Graphics,Controls,ExtCtrls;
type
//用於設置時間事件發生的間隔
TInterval=(TenM,TwentyM,ThirtyM,FortyM,FiftyM,SixtyM);
TTimeCount=class(TCustomPanel)
private
FTimer:TTimer;
FCount:integer; //只讀私有成員,計數值
FInterval:TInterval; //時間事件發生的間隔
FActive:Boolean; //決定是否發生間隔事件
TimeLen:Integer;//發生事件的時間長度,以秒為單位。
TimeNum:integer;//計數值,和TimeLen一起有用,以判斷是否事件該發生了
FTimeOut:TNotifyEvent;//事件的方法指針
procedure SetInterval(I:TInterval);
procedure SetActive(A:boolean);
procedure FTimerTimer(Sender:Tobject);//時間控件的事件處理函數
protected
procedure DoTimeOut;dynamic; //調度方法,用於關聯事件。
public
procedure pause; //暫停計數
procedure Resume;//從暫停的計數開始計數。
procedure stop;//停止
procedure start;//開始計數
constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
property Count:Integer read FCount; //計數值的只讀屬性
published
property Interval:TInterval read FInterval write SetInterval Default TenM;
property Active:boolean read FActive write SetActive default false;
property OnTimeOut:TNotifyEvent read FTimeOut write FTimeOut;
//顯式祖先類的一些屬性在對象察看器中
property BevelInner;
property BevelOuter;
property BevelWidth;
property Color;
property Font;
property PopupMenu;
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
property OnClick;
property OnDblClick;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
end;
implementation
//構造函數,繼承父類的構造函數,並初始化類中的成員。
constructor TTimeCount.Create(AOwner:TComponent);
//創建時間控件並設置相關的參數
procedure CreateTimer;
begin
FTimer:=TTimer.Create(self);
FTimer.Enabled:=False;
FTimer.Interval:=1000;
FTimer.OnTimer:=FTimerTimer;
end;
//以下是設置外觀的
procedure setView;
begin
Width:=100;
Height:=50;
Color:=$000000;
Font.Color:=$FFFFFF;
Font.Size:=14;
Font.Style:=[fsBold,fsUnderline];;
BevelOuter := bvLowered ;
Caption:='0';
end;
begin
inherited Create(AOwner);
FCount:=0;
FInterval:=TenM;
FActive:=False;
TimeLen:=600;//十分鐘,六百秒
TimeNum:=0;
CreateTimer;
setView;
end;
//析構函數,先釋放時間控件,再繼承父類的析構函數
destructor TTimeCount.Destroy;
begin
FTimer.Free;
inherited Destroy;
end;
//設置時間事件發生間隔,財時要賦相應的間隔秒數
procedure TTimeCount.SetInterval(I:TInterval);
begin
if FInterval<>I then
begin
FInterval:=I;
case FInterval of
TenM: TimeLen:=600;
TwentyM:TimeLen:=1200;
ThirtyM: TimeLen:=1800;
FortyM: TimeLen:=2400;
FiftyM:TimeLen:=3000;
SixtyM:TimeLen:=3600;
end;
end;
end;
procedure TTimeCount.SetActive(A:boolean);
begin
if FActive<>A then
begin
FActive:=A;
TimeNum:=0;
end;
end;
procedure TTimeCount.pause;
begin
if FTimer.Enabled then
FTimer.Enabled:=False;
end;
procedure TTimeCount.Resume;
begin
if not FTimer.Enabled then
FTimer.Enabled:=True;
end;
procedure TTimeCount.stop;
begin
FTimer.Enabled:=False;
FCount:=0;
TimeNum:=0;
caption:='0'
end;
procedure TTimeCount.start;
begin
if (not FTimer.Enabled)and(TimeNum=0) then
FTimer.Enabled:=True;
end;
//最重要的時間函數,用於調用該類的事件觸發高度函數。
//以及在容器中顯示計數值
procedure TTimeCount.FTimerTimer(Sender:TObject);
begin
inc(FCount);
if (FCount mod 3600)=0 then FCount:=0;
Caption:=InttoStr(FCount);//這個就是顯示計數值
inc(TimeNum);
if (TimeNum=TimeLen)and(FActive) then
begin
DoTimeOut;
TimeNum:=0;
end;
end;
//事件調度函數,將外部的事件處理函數和該類的事件方法指針聯系起來
procedure TTimeCount.DoTimeOut;
begin
if Assigned(FTimeOut) then
FTimeOut(Self);
end;
end.
五、組件注冊安裝與刪除。
組件類編寫完畢,接著就要測試了,這個從略,可以在剛才的工程中動態創建它,設置相應屬性,指定時間事件,看看是否正確。上面是經過測試的。
到確定正確後,就要來看看裝組件的步驟了:
首先,我們要把組件單元放在一個指定的文件夾中,以便以後管理,和IDE統一指定路徑。
我在Delphi目錄下新建了MyCom文件夾,用來存放組件單元。然後選:
Component—>New Component;
啟動Component Wizard
在Ancestor type(父類):中填TCustomPanel
Class Name(你的組件類名)中填:TimeCount
Palette Page,默認為Samples,我就用這個吧,當然也可以自己創建一個。
Unit File Name(組件類所在的單元名),就寫TimeCount吧。
Search Path(搜索路徑),必須把上面所建的文件夾路徑包含進去,編譯時才能能過。
點擊旁邊的”…”按鈕,出現一個對話框,裡面的編輯框旁邊又有一個”…“按鈕,點擊它出現浏覽文件夾框,在其中選中上面建的文件夾的路徑,點確定,再點OK,回去New Component;。
這時再點下面的OK就行啦,出現代碼如下:
unit TimeCount;
interface
uses
messages, SysUtils,Classes,Graphics,Controls,ExtCtrls;
type
TTimeCount=class(TCustomPanel)
private
published
public
published
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TTimeCount]); //注冊控件用的函數,自動幫你生成
end;
end.
這時再把上面的組件類替換掉這個類就行啦(當然上面的注冊函數可要保留呀)。然後保存到上面所建的文件夾中。
接著就要安裝組件了,點Component->install Component
對話框中第一項Unit file Name,是組件單元.pas文件的路徑名字。其他只要按缺省。
記得第三項的。。\delphi7\Lib\dclusr.dpk,這個就是存放組件的包名,等一下刪除組件時用到的
接下來點OK,就可以了,看看Samples是不是有了一個新組件啦。
不過面板上的組件圖標似乎不好看,應該給他一個新的圖標了:
但之前應該把它先從面板刪除,File->Open…打開dclusr.dpk.
選中其中的Contains下的TimeCount.pas,點上面的Remove。將其刪除
然後再點Compile,重新將包編譯一次。就行啦。Samples上的新組件就消失了。
接下來是做組件圖標:
打開Image Eidtor,新建一個DCR文件,在其中建一個24×24的位圖,畫上你喜歡的圖標,將位圖的名字起為組件類名一樣,而且用大寫,即:TTIMECOUNT
將DCR文件起名為組件類所在單元名一樣,而且大寫,即:TIMECOUNT。
保存文件到單元所在的文件夾中,
最後依上面的方法再裝一次,看是不是有一個漂亮的圖標啦
現在大家應該有一個清楚的概念了吧,其中涉及到了好多的技巧。在以後的篇章中將不再講這些內容了,只把主要精力花在組件實現技術上。因為我們這個組件還是比較簡單,沒有涉及到多少高級的主題。但沒有關系,跟著我慢慢地做下來,你們會了解組件制作的方方面面的。