(接上文)
通過上面的努力我們的組件似乎已經(jīng)比較完美了,可我們也忽略了一些重要的細(xì)節(jié)和一些有趣的事情,這一篇我們將研究兩個(gè)很有用的組件特性:
在之前開發(fā)組件核心功能時(shí)我們曾設(shè)置了兩個(gè)屬性BeginTime和WakeTime,他們都是字符串型的屬性,然而他們所要表示的卻是時(shí)間類型,這樣就很有可能使組件使用者錯(cuò)誤的編輯屬性并導(dǎo)致轉(zhuǎn)化字符串到時(shí)間時(shí)出錯(cuò)(當(dāng)然這里只是為了文章的講解,我們故意把它設(shè)置為了字符串類型),雖然通過瀏覽原代碼你知道我們也做了一些代碼級別的防出錯(cuò)處理,使當(dāng)輸入錯(cuò)誤時(shí)屬性自動變成‘00:00:00’,然而這對組件使用者來講仍然顯的很不友好,所以我們需要為這兩個(gè)屬性定制編輯器,我們的編輯器將彈出一個(gè)窗口里面有一個(gè)TdateTimePicker用來選擇時(shí)間。在delphi中有許多這樣的例子,例如大家都知道的lines屬性,當(dāng)你單擊它右放的省略號時(shí)為自動彈出一個(gè)文本編輯器來編輯lines,這大大降低了組件使用者范錯(cuò)誤的可能性。
在定制完屬性編輯器以后,我們將為組件本身加入一寫有趣的元素——組件編輯器,這也是在delphi中經(jīng)常出現(xiàn)的,例如有些組件當(dāng)你雙擊它時(shí),它并不會進(jìn)入代碼編寫狀態(tài),而是彈出它自己的編輯器。雖然我們的組件似乎并不需要這種特性,但為了演示它,我們也將它考慮近來,我們給我們的組件編寫了一個(gè)版權(quán)信息和一個(gè)關(guān)于對話框,當(dāng)組件使用者雙擊它時(shí)彈出關(guān)于信息(當(dāng)然,這僅僅是種演示)。上面提到的兩種特性由于它們只是會在設(shè)計(jì)時(shí)起作用,所以你完全可以在新的組件包中編寫并注冊它們,并將這個(gè)組件包設(shè)置為Designtime Only,為了方便起見我們就直接把它們和組件的單元編寫在一起。注意:以下出現(xiàn)的一些類和方法都需要引用單元DesignEditors(delphi7)或DsgnIntf(delphi5),與前面說的一樣,它們都屬于delphi的open tools api所以,如果你沒有這寫單元請按照前文的方法安裝它們。
首先來編寫屬性編輯器,由于BeginTime和WakeTime是字符串類型,所以我們必須從默認(rèn)的字符串屬性編輯器類Tstring
PRoperty繼承并覆蓋它的一寫方法(這里只介紹幾個(gè)重要的方法,事實(shí)上所有的屬性編輯器都從TpropertyEditor繼承而來,然而我們不用直接繼承這個(gè)基類)。其中一個(gè)重要的方法是GetAttributes,他將返回一些代表編輯器功能的值,這些值將會在代碼的注釋中說明(如果你的屬性編輯器還需要一個(gè)下拉列表,你還需要另外一個(gè)重要的方法GetValues具體請查看delphi幫助)另外為了使屬性編輯器為彈出的對話框我們需要覆蓋Edit方法。為了可以以可視化的方式設(shè)計(jì)對話框,我們可以建立一個(gè)普通工程,在設(shè)計(jì)好后將窗體的類聲明復(fù)制到我們的組件單元,并將窗體的dfm文件拷貝到我們的組件包目錄,并在代碼中加入編譯器開關(guān){$R *.dfm}。以下是窗體的類聲明,這個(gè)窗體沒有任何的代碼需要編寫:
TTimeEditFrm = class(TForm)
DateTimePicker1: TDateTimePicker;
Button1: TButton;
Button2: TButton;
private
{ Private declarations }
public
{ Public declarations }
end;
以下是屬性編輯器的代碼:
TClockProperty=class(TStringProperty)
public
function GetAttributes:TPropertyAttributes;override;
procedure Edit;override;
end;
實(shí)現(xiàn)部分:
procedure TClockProperty.Edit;
var
TimeEditFrm:TTimeEditFrm;
begin
try
TimeEditFrm.DateTimePicker1.Time:=StrToTime(GetValue);
if TimeEditFrm.ShowModal=mrOK then
SetValue(TimeToStr(TimeEditFrm.DateTimePicker1.Time));
//GetValue和SetValue是TStringProperty的基類方法,他直接讀取和設(shè)置字符串的值
finally
TimeEditFrm.Free;
end;
end;
function TClockProperty.GetAttributes: TPropertyAttributes;
begin
result:=[paDialog,paMultiselect];
//paDialog表示屬性編輯器將顯示一個(gè)對話框,paMulitiselect允許多個(gè)組件選擇屬性
//除此之外如果你想讓屬性編輯器顯示下拉列表,你還需要paValueList具體請查看幫助
end;
最后我們用RegisterPropertyEditor方法注冊屬性編輯器:
procedure Register;
begin
……
RegisterPropertyEditor(TypeInfo(string),TClock,'BeginTime',TClockProperty);
RegisterPropertyEditor(TypeInfo(string),TClock,'WakeTime',TClockProperty);
end;
重新編譯更新組件后我們就可以測試了,可以看到組件編輯器工作的很好:
接下來我們來實(shí)現(xiàn)組件編輯器:
組件編輯器需要繼承TcomponentEditor并覆蓋一些重要的方法,GetVerbCount返回設(shè)計(jì)時(shí)組件右鍵自定義菜單的數(shù)目,GetVerb為每一個(gè)自定義菜單添加文字,ExecuteVerb為每一個(gè)菜單項(xiàng)添加事件,Edit為組件的缺省操作指定事件(即在設(shè)計(jì)時(shí)雙擊組件),以下是代碼:
TClockEditor=class(TComponentEditor)
public
function GetVerbCount:integer;override;
function GetVerb(index:integer):string;override;
procedure ExecuteVerb(index:integer);override;
procedure Edit;override;
end;
實(shí)現(xiàn)部分:
procedure TClockEditor.Edit;
begin
ExecuteVerb(1); //默認(rèn)顯示關(guān)于
end;
procedure TClockEditor.ExecuteVerb(index: integer);
begin
case index of
//第一個(gè)顯示名字的菜單什么都不做顯示
1:showmessage('hk.barton@2003');
end;
end;
function TClockEditor.GetVerb(index: integer): string;
begin
case index of
0:result:='hk.barton';
1:result:='About Clock';
end;
end;
function TClockEditor.GetVerbCount: integer;
begin
result:=2;//我們顯示兩條菜單,一個(gè)我的名字,一個(gè)關(guān)于
end;
同樣最后我們注冊組件編輯器:
procedure Register;
begin
……
RegisterComponentEditor(TClock,TClockEditor);
end;
同樣可以看到組件編輯器的測試情況:
文章寫到這里也該結(jié)束了,雖然寫了那么多,然而在組件開發(fā)中這仍是一小部分內(nèi)容,本文只是拋磚引玉的作用,希望對正要進(jìn)入組件開發(fā)的朋友一些啟示。