元件製作之一(概念)

作為元件製作的開始,應該瞭解一些概念,我以為這些概念是非常重要的,將可以作為以後實踐的理論基礎。
 
一、元件的簡要層次結構。一般情況下,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測試,安裝元件和寫幫助,這個內容比較次要,後面的例子會講怎麼樣安裝,包括單個單元,或用包的形式安裝。而寫幫助,己超出範圍,這裏就不說了。
 
關於元件基本概念就到這裏講完了,接下來就是實踐了,有了上面的知識,實踐起來也不是很難,很多東西都在上面了,而一些高級的特性,會在以後慢慢說的。
 
下一篇是做一個簡單的元件,其實只用到了這裏講到了一些基本原理,而最重要的是給出了一個完整的元件製作過程。到了以後難度更大的組件,則重點會在代碼的實現上,其他則從略了。

posted on 2005-09-07 09:54  Jason Cheng  阅读(540)  评论(0编辑  收藏  举报