19.2.2 Delphi部件編程
19.2.2.1 創建屬性
屬性(Property)是部件中最特殊的部分,主要因為部件用戶在設計時可以看見和操作它們,並且在交互過程中能立即得到返回結果。屬性也很重要,因為如果將它們設計好後,將使用戶更容易地使用,自己維護起來也很容易。
為了使你在部件中更好地使用屬性,本部分將介紹下列內容:
● 為什麼要創建屬性
● 屬性的種類
● 公布(publishing)繼承的屬性
● 定義部件屬性
● 編寫屬性編輯器
1. 為什麼要創建屬性
屬性提供非常重要的好處,最明顯的好處是屬性在設計時能出現在Object Inspector窗口中,這將簡化編程工作,因為你只需讀用戶所賦的值,而不要處理構造對象的參數。
從部件使用者的觀點看,屬性象變量。用戶可以給屬性賦值或讀值,就好象屬性是對象的域。
從部件編寫者的觀點看屬性比對象的域有更強的功能;
⑴ 用戶可以在設計時設置屬性
這是非常重要的,因為不象方法,只能在運行時訪問。屬性使用戶在運行程序之前就能定制部件,通常你的部件不應包含很多的方法,它們的功能可以通過屬性來實現。
⑵ 屬性能隱藏詳細的實現細節
⑶ 屬性能引起簡單地賦值之外的響應,如觸發事件
⑷ 用於屬性的實現方法可以是虛擬方法,這樣看似簡單的屬性在不同的部件中,將實現不同的功能。
2. 屬性的類型
屬性可以是函數能返回的任何類型,因為屬性的實現可以使用函數。所有的Pascal類型,兼容性規則都適用屬性。為屬性選擇類型的最重要的方面是不同的類型出現在Object Inspector窗口中的方式不同。Object Inspector將按不同的類型決定其出現的方式。
你也能在注冊部件時描述不同的屬性編輯器。
下表列出屬性出現在Object Inspector窗口中的方式
表19.3 屬性出現在Object Inspector窗口中的方式
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
屬性類型 處 理 方 式
───────────────────────────────────────
簡單類型 Numeric、Character和 String屬性出現在Object Inspector中,用戶可
以直接編輯
枚舉類型 枚舉類型的屬性顯示值的方式定義在代碼中。選擇時將出現下拉
式列表框,顯示所有的可能取值。
集合類型 集合類型出現在Object Inspector窗口中時正如一個集合,展開後,用
戶通過將集合元素設為True或False來選擇。
對象類型 作為對象的屬性本身有屬性編輯器,如果對象有自己的published屬
性,用戶在Object Inspector中通過展開對象屬性列,可以獨立編輯它們,
對象類型的屬性必須從TPersistent繼承。
數組類型 數組屬性必須有它們自己的屬性編輯器,Object Inspector沒有內嵌對數
組屬性編輯的支持。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3. 公布繼承的屬性
所有部件都從祖先類型繼承屬性。當你從已有部件繼承時,新部件將繼承祖先類型的所有屬性。如果你繼承的是抽象類,則繼承的屬性是protected或public,但不是published。如想使用戶訪問protected或public屬性,可以將該屬性重定義為published。如果你使用TWinControl繼承,它繼承了Ctl3D屬性,但是protected的,因此用戶在設計和運行時不能訪問Ctl3D,通過在新部件中將Ctl3D重聲明為published,就改變了Ctl3D的訪問級別。下面的代碼演示如何將Ctl3D聲明為published,使之在設計時可被訪問。
type
TSampleComponent=class(TWinControl)
published
property Ctl3D;
end;
4. 定義部件屬性
⑴ 屬性的聲明
聲明部件的屬性,你要描述:
● 屬性名
● 屬性的類型
● 讀和設置屬性值的方法
至少,部件屬性應當定義在部件對象聲明的public部分,這樣可以在運行時很方便地從外部訪問;為了能在設計時編輯屬性,應當將屬性在published部分聲明,這樣屬性能自動顯示在Object Inspector窗口中。下面是典型的屬性聲明:
type
TYourComponent=class(TComponent)
…
private
FCount: Integer { 內部存儲域 }
function GetCount: Integer; { 讀方法 }
procedure SetCount(ACount: Integer); { 寫方法 }
pubilic
property Count: Integer read GetCount write SetCount;
end;
⑵ 內部數據存儲
關於如何存儲屬性的數據值,Delphi沒有特別的規定,通常Delphi部件遵循下列規定:
● 屬性數據存儲在對象的數據域處
● 屬性對象域的標識符以F開頭,例如定義在TControl中的屬性FWidth
● 屬性數據的對象域應聲明在private部分
後代部件只應使用繼承的屬性自身,而不能直接訪問內部的數據存儲。
⑶ 直接訪問
使屬性數據可用的最簡單的辦法是直接訪問。屬性聲明的read 和write部分描述了怎樣不通過調用訪問方法來給內部數據域賦值。但一般都用read進行直接訪問,而用write進行方法訪問,以改變部件的狀態。
下面的部件聲明演示了怎樣在屬性定義的read 和write部分都采用直接訪問:
type
TYourComponent=class(TComponent)
…
private { 內部存儲是私有 }
FReadOnly: Boolean; { 聲明保存屬性值的域 }
published { 使屬性在設計時可用 }
property ReadOnly: Boolean read FReadOnly write FReadOnly;
end;
⑷ 訪問方法
屬性的聲明語法允許屬性聲明的read和write部分用訪問方法取代對象私有數據域。不管屬性是如何實現它的read 和write部分,方法實現應當是private,後代部件只能使用繼承的屬性訪問。
① 讀方法
屬性的讀方法是不帶參數的函數,並且返回同屬性相同類型的值。通常讀函數的名字是“Get”後加屬性名,例如,屬性Count的讀方法是GetCount。不帶參數的唯一例外是數組屬性。如果你不定義read方法,則屬性是只寫的。
② 寫方法
屬性的寫方法總是只帶一個參數的過程。參數可以是引用或值。通常過程名是"Set"加屬性名。例如,屬性Count的寫方法名是SetCount。參數的值采用設置屬性的新值,因此,寫方法需要執行在內部存儲數據中寫的操作。
如果沒有聲明寫方法,那麼屬性是只讀的。
通常在設置新值前要檢測新值是否與當前值不同。
下面是一個簡單的整數屬性Count的寫方法:
procedure TMyComponent.SetCount( value: Integer);
begin
if value <>FCount then
begin
FCount := Value;
update;
end;
end;