作為組件制作的開始,應該了解一些概念,我以為這些概念是非常重要的,將可以作為以後實踐的理論基礎。
?
一,?組件的簡要層次結構。一般情況下,VCL的組件可以從Tcomponent為開始。其最明顯的特征就是它的屬性可以在設計時通過對象察看器來操縱,另外,他還能擁有其他組件。
從Tcomponent下,分出非可視組件和可視組件。
非可視組件如TOPenDialog,TTimer,TTable等,這些組件因為繼承自Tomponent,所以也就繼承了在設計時可以被操縱的特性。
可視化組件始自TControl,是它引入了可視化屬性和方法,使繼承自它的類都有了這些可視化特性。
TControl又分出兩類組件類型:從TWinControl(窗口控件)自下的控件,和從TGraphicControl(圖形控件)自下的控件。繼承自TWinControl的控件將windows控件進行封裝,所以擁有Windows控件的很多特性,比如可以得到焦點,有唯一的句柄,用戶可以通過發送消息與這些控件進行交互等。而繼承自TGraphicControl的控件,也是可見的,但沒有句柄,可以稱之為圖形控件,比如TLabel,TBevel,都是Delphi畫出來的,並不占用系統資源。
二,屬性 先看一個簡單的屬性定義:
TsomeObj=class
??????????Private
????????????FCount:integer;
??????????Protected
????????????Procedure?SetCount(value:Integer);
??????????published
??Property?count:integer?read?FCount?write?SetCount?default?0;//屬性定義
??????????End;
????該屬性從私有成員FCount讀出值,而靠SetCount方法設置值到私有成員FCount。
屬性的優勢在於可以很直觀進行讀寫,而又不同於私有成員。因為屬性可以通過寫訪問方法來保護私有成員:
Procedure?TsomeBoj.SetCount(value:Integer);
??????????Begin
?????????????If?FCount<>value?then
?????????????????FCount:=value;
??????????End;
????其中屬性定義中的Default 0並不是默認值(即對象察看器顯示的值),默認值要在組件類的構造函數中設定。而Default有這樣的作用,決定DFM文件中是否要保存該屬性的值,比如上面為Default?0,即當該屬性值為0時,則該屬性不會被保存到DFM中,如果該屬性值不為0,則該屬性會被保存到DFM中。另外屬性定義還有一個關鍵字為
NoDefault,設置了這個關鍵字,比如
Property?count:integer?read?FCount?write?SetCount?NoDefault;
則無論它的值是什麼,都會被寫到DFM文件中。
?
屬性可以有如下幾種類型,下面只給出簡單介紹,而這些類型的屬性,會在組件制作時詳細的運用:
簡單類型屬性:如上面定義的,加一個例子
Property?text:string?read?Ftext?write?SetText;
枚舉類型屬性:TEnumtype=(Enum1,Enum2,Enum3);
??????????????FEnumtype:TEnumtype;
??????????????Property?Enumtype:TEnumtype?read?FEnumtype?write?FEnumtype;
?? 在對象察看器中看來就是下拉列框選擇值。
集合類型屬性:Tset=(set1,set2,set3);
??????????????Tsets=set?of??Tset;
??????????????Fsets:Tsets;
??????????????Property?sets:Tsets?read?Fsets?write?Fsets;
在對象察看器中看來,就是列出幾個選項分別設置真假。比如TForm的BorderIcons屬性即是。
對象類型屬性:一個屬性是一個對象,而這個對象必須派生自Tpersistent或者他之下的類,才能在對象察看器中可以展開它,並設置它裡面的屬性。
????數組類型屬性:數組屬性如果要在對象察看器中看見,需要有自己的屬性編輯器(如果不想在對象察看器看當然就不用啦),是比較高級的組件,在後來的組件制作再來介紹,會更直觀一些。這裡只給出它的定義形式:
property?Selected[Index:?Integer]:?Boolean?read?GetSelected?write?SetSelected;
三,事件:事件其實是一種特殊的屬性,他是指針類型,指向一個事件方法類型。當有特定的事件發生時,它就會關聯到一段執行代碼。
下面以一個例子來講解事件是怎麼發生的。
??????????我們先定義一個鼠標點下事件的鼠標事件類型,它其實就是方法指針:
type?TMouseEvent?=?procedure?(Sender:?TObject;?Button:?TMouseButton;?Shift:?TShiftState;?X,?Y:?Integer)?of?object;
??????????又定義一個私有成員:鼠標事件類型的,即一個方法指針類型
??????????FonMouseDown:TMouseEvent
??????????最後定義一個屬性:類要通過這個屬性將外部的事件處理函數和FonMouseDown關聯在一起:
??????????onMouseDown:TMouseEvent?read?FonMouseDown?write?FonMouseDown;
當有鼠標左鍵點擊的,系統會向窗口會發送WM_LBUTTONDOWN;消息
Delphi?可以截獲這個消息,如下定義消息函數:
??????????procedure?WMLButtonDown(var?Message:?TWMLButtonDown);?message?WM_LBUTTONDOWN;
??????????在這個消息處理函數中調DOMouseDown,DoMouseDown又調?用了MouseDown
?????????在這個函數裡面才到了最重要的部分
?????????該函數是這樣的:
procedure?TControl.MouseDown(Button:?TMouseButton;Shift:?TShiftState;?X,?Y:?Integer);
begin
? ?if?Assigned(FOnMouseDown)?then?FOnMouseDown(Self,?Button,?Shift,?X,?Y);
end;
而我們先來看看用戶外部是怎麼操作的,
他自己定義一個SomeobjMouseDown;?是一個事件處理函數,必須和TMouseEvent的形式一樣:
Procedure?SomeobjMouseDown(Sender:?TObject;?Button:?TMouseButton;
??Shift:?TShiftState;?X,?Y:?Integer);
然後他這樣賦值:someobj.onMouseDown:=SomeobjMouseDown;
當賦值以後,類內部其實是通過onMouseDown屬性,將SomeobjMouseDown;與FonMouseDwon關聯在一起,也就是說,MouseDown方法中調用了FOnMouseDown(Self,?Button,?Shift,?X,?Y);其實就等於調用了Procedure?SomeobjMouseDown(Sender:?TObject;?Button:?TMouseButton;Shift:?TShiftState;?X,?Y:?Integer);
所以用戶就可以在這個自定義的事件方法中寫自己的代碼,當事件發生時,該類的調度機制就會自動調用這個事件方法啦
也許有人會問,為什麼從消息處理函數要調用DoMouseDown,DoMouseDown又調用MouseDown,然後再調用事件方法呢。為什麼不直接在消息處理函數WMLButtonDown中調用呢,其實它這樣的做的目的是要進行一些保護判斷,以及一些消息附加值的轉換,使這些值看起來更加直觀。
好了,事件就講了這裡,不知道你們明白了沒有,可能是我的表達能力不行,但沒有關系,到真正做的時候,大家應該能明白了。
四,組件制作步驟:有了上面的基本概念,其實制作簡單組件已經不是什麼問題了,而要做真正的組件,還需要有一個正確過程,我們以後學做組件,也會順著這個過程來做。主要如下:
1,?確定一個祖先類。怎麼確定,可以根據上面組件的簡要層次結構來確定。如果你想做非可視化組件,可以從繼承TComponent開始。如果想做可視要可視化組件,可以從TControl的子類開始。
2?創建組件的單元,這個在制作組件時再說,不過是在IDE裡面做幾個操作而已。
3?給組件寫屬性,方法,事件,成員,等。這些在上面己有詳細說明,是寫組件的核心部分,事實上也是後面實踐的主要內容。
4測試,安裝組件和寫幫助,這個內容比較次要,後面的例子會講怎麼樣安裝,包括單個單元,或用包的形式安裝。而寫幫助,己超出范圍,這裡就不說了。
?
關於組件基本概念就到這裡講完了,接下來就是實踐了,有了上面的知識,實踐起來也不是很難,很多東西都在上面了,而一些高級的特性,會在以後慢慢說的。
?
下一篇是做一個簡單的組件,其實只用到了這裡講到了一些基本原理,而最重要的是給出了一個完整的組件制作過程。到了以後難度更大的組件,則重點會在代碼的實現上,其他則從略了