TCollection 是TCollectionItenm對象一個容器。
類關系TObject→TPersistent
每一個TCollection都擁有一組TCollectionItem對象。
在其Items屬性數組中,TCcllection保存集合項目一個下標。Count 屬性包含了集合項目數量。
使用Add和Clear方法可以向集合中加入項目和從集合中刪除項目。
從TCollection繼承對象能夠包含從TCollectionItem繼承對象。
例如,一個TDBGridColumns對象包含TColumn對象,這兩個類被TDBGrid對象用於表示網格。
下表列出了每一個TCollection對象子類與相應TCollectionltem對象子類以及使用控制組件。
其中,TQuryTableProducer和TWehDispetcher使用控件繼承自TWinContril對象。
TCollection子類 TCollectionItem子類 控件組件
TCheckConstraints TCheckConstraint 使用Tfield對象控件
TCookieCollection TCookie HTTP響應對象
TCoolBands TCoolBand TCoolBar
TDBGridColumns TColumn TDBGrid
TDependencies TDependency TService
TDisplayDims TDisplayDim TDecisionGrid
TFieldDefs TfieldDef TDatsSet 字串6
THeaderSections THeaderSection THeaderControl 字串4
TIndexDefs TIndexDef TTable
THTMLTableColumns THTMLTableColumn TQueryTableProducer
TListColumns TListColumn TListView
TSuatusPanels TSuatuspanel TStatusBar
TWebActionItems TwebActionitem TwebDispatcher
使用TCollection和TCollectionitem子類控件,都有一個擁有一個集合5公開屬性(
例如,TStatusBarPanels屬性擁有一個TStatusPanels)。一個標准屬性編輯器,從種屬上說被認為是集合編輯器,
它被授引自Object Inspector,以編輯集合中項目。
屬性列表
Count 返回集合中項目數量
ItemClass 表示集合項目有種類
Items 提供對集合中項目變址訪問
方法列表
~TCollection 刪除集合及其內每一項目
Add 創建一新對象實例並加 入到Items屬性數組中
Assign 將另一集合有內容復制到執行該方法對象中
Bcginupdate 使屏幕更新暫停
Clear 從集合中刪除所有項目
EndUpdate 使屏幕能夠重新進行更新
FindItemID 返回ID參數指定項目
Insert 創建TCollectionItem對象並加入到Items屬性數組中
TCollection 創建並初始化一個集合 字串9
屬性
TCollection::Count
用於返回集合中項目數量。
__property int Count = {read=getCount,nodefanlt};
Count屬性包含了Items屬性數組中項目數量。因為Items屬性數組下標從0開始,因此,Count屬性數值總是比Items屬性數組最後一個成員下標大1。 字串9
TCollection::ItemClass
表示集合項目類。
__property int count = {read =GetXount,nodefauit};
ItemClass返回屬於集合項目類(繼承自TColliectionItem對象)。
例如,在TCollection對象THeaderSections子類有一個實例中,IetmClass屬性返回THeaderSection .
TCollection::Items
提供對集合中項目變址訪問。
__property TCollectionItem*irems{int Index}={read =GetItem,write=SetItem};
使用Items屬性可以訪問集合中單個項目。Index參數數值對應於TCollectionItem對象Index屬性。它表示項目 在集合中有位置。 字串2
方法
TCollection::~TCollection
刪除集合及其內每一個項目 。
__fastcall virtual~TCollection(void);
不要直接調用~TCollection 用delete會自動調用~TCollection
~TCollection調用Clear方法,釋放在Items屬性數組中每一個被子引用項目,然後刪除集合本身。
TCollection::Add
創建一個新TCollectionItem對象實例,並將其加入到Items屬性數組中。
TCollectionItem* __fasteall Add(void);
調用Add可以在集合中創建一個項目。新項目被放置在Items屬性數組結尾處。Add返回新集合項目。
TCollection::Assign
將另一個集合內容復制到執行該方法對象。
virtual void __fastcall Assign (TPersistemt*Source);
使用Assign,可以將一個TCollection對象實例內容復制至另一個TCollection對象。Assign方法刪除目集合(即執行該方法對象)中所有項目,然後加入由Source參數指定集合Items屬性數組中每一個項目復制。
TCollection::BeginUpdate
使屏幕更新暫停。
void __fastcall BeginUpdate(void);
BeginUpdate使屏幕更新暫停,直至調用了EndUpdate方法。使用BeginUpdate可以加速進行處理,並且當向一個集合中加入項目或從一個集合中刪除項目時,可以避免閃爍。 字串3
TCollection::EndUpdate
從集合中刪除所有項目。
void __fastcall CIear(void);
CIear清空Items屬性數組並刪除每一個TCollectionItem對象。
TCollection::EndUpdate
使屏幕能夠重新進行更新。
void __fastcall EndUpdate(void);
使用EndUpdate,可以使以BeginUpdate方法關閉屏幕能夠重新進行更新。
TCollection::FindItemID
返回ID參數指定項目。 字串1
TCollectionItem* __fastcall FindItemID(int ID);
FindItemID方法返回集合中項目,該項目ID屬性被作為一個參數傳遞。如果沒有ID參數指定項目,則FindItemID返回NULL.
字串8
TCollection::Insert 字串6
創建一個新TCollectionItem對象實例,並將其加入到Items屬性數組中。 字串6
TCollectionItem* __fastcall Insert(int Index);
字串7
調用 Insert,可以在集合中一個指定位置處加入一個新項目。在Items屬性數組中已經存在從指定位置開始項目將向上移動。Insert返回新集合項目。 字串4
TColletion::TCollection 字串6
創建並初始化一個集合。 字串3
__fastcall TCollection (Sysem::TMetaCIass*ItemCIass);
字串5
不要直接調用 TCollection。用new會返回新集合一個間接引用。
字串6
TCollection方法取一個TCollectionItem子類名作為一個參數。該參數確定了由Add方法創建項目類。 字串2
====================================================================================
TCollection類
前面我們提到了Delphi的IDE能夠自動將字符串列表保存在DFM文件中,並能在運行時將設計期編輯的字符串列表加載進內存(也就是我們通常所說的類的可持續性)。TStrings這種特性比較適合於保存一個對象同多個字符串數據之間關聯,比較類似於現實生活中一個人同多個Email賬戶地址之間的關系。但是,TStrings類型的屬性有一個很大的局限那就是,它只能用於設計時保存簡單的字符串列表,而不能保存復雜對象列表。而一個父對象同多個子對象之間的聚合關系可能更為常見,比如一列火車可能有好多節車廂構成,每節車廂都有車廂號,車廂類型(臥鋪,還是硬座),車廂座位數,車廂服務員名稱等屬性構成。如果我們想在設計期實現對火車的車廂定制的功能,並能保存車廂的各個屬性到窗體文件中,則車廂集合屬性定義為TStrings類型的屬性是行不通的。
對於這個問題,Delphi提供了TCollection容器類屬性這樣一個解決方案。TCollection以及它的容器元素TCollectionItem的接口定義如下:
TCollection = class(TPersistent)
…
protected
procedure Added(var Item: TCollectionItem); virtual; deprecated;
procedure Deleting(Item: TCollectionItem); virtual; deprecated;
property NextID: Integer read FNextID;
procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); virtual;
{ Design-time editor support }
function GetAttrCount: Integer; dynamic;
function GetAttr(Index: Integer): string; dynamic;
function GetItemAttr(Index, ItemIndex: Integer): string; dynamic;
procedure Changed;
function GetItem(Index: Integer): TCollectionItem;
procedure SetItem(Index: Integer; Value: TCollectionItem);
procedure SetItemName(Item: TCollectionItem); virtual;
procedure Update(Item: TCollectionItem); virtual;
property PropName: string read GetPropName write FPropName;
property UpdateCount: Integer read FUpdateCount;
public
constructor Create(ItemClass: TCollectionItemClass);
destructor Destroy; override;
function Owner: TPersistent;
function Add: TCollectionItem;
procedure Assign(Source: TPersistent); override;
procedure BeginUpdate; virtual;
procedure Clear;
procedure Delete(Index: Integer);
procedure EndUpdate; virtual;
function FindItemID(ID: Integer): TCollectionItem;
function GetNamePath: string; override;
function Insert(Index: Integer): TCollectionItem;
property Count: Integer read GetCount;
property ItemClass: TCollectionItemClass read FItemClass;
property Items[Index: Integer]: TCollectionItem read GetItem write SetItem;
end;
TCollectionItem = class(TPersistent)
…
protected
procedure Changed(AllItems: Boolean);
function GetOwner: TPersistent; override;
function GetDisplayName: string; virtual;
procedure SetCollection(Value: TCollection); virtual;
procedure SetIndex(Value: Integer); virtual;
procedure SetDisplayName(const Value: string); virtual;
public
constructor Create(Collection: TCollection); virtual;
destructor Destroy; override;
function GetNamePath: string; override;
property Collection: TCollection read FCollection write SetCollection;
property ID: Integer read FID;
property Index: Integer read GetIndex write SetIndex;
property DisplayName: string read GetDisplayName write SetDisplayName;
end;
TCollection類是一個比較復雜特殊的容器類。但是初看上去,它就是一個TCollectionItem對象的容器類,同列表類TList類似,TCollection類也維護一個TCollectionItem對象索引數組,Count屬性表示容器中包含的TCollectionItem的數目,同時也提供了Add和Delete方法來添加和刪除TCollectionItem對象以及通過下標存取TCollectionItem的屬性。看上去和容器類區別不大,但是在VCL內部用於保存和加載組件的TReader和TWriter類提供了兩個特殊的方法WriteCollection和ReadCollection用於加載和保存TCollection類型的集合屬性。IDE就是通過這兩個方法實現對TCollection類型屬性的可持續性。
假設現在需要設計一個火車組件TTrain,TTrain組件有一個TCollection類型的屬性Carriages表示多節車廂構成的集合屬性,每個車廂則對應於集合屬性的元素,從TCollectionItem類繼承,有車廂號,車廂類型(臥鋪,還是硬座),車廂座位數,車廂服務員名稱等屬性,下面是我設計的組件的接口:
type
//車廂類型,硬座、臥鋪
TCarriageType = (ctHard, ctSleeper);
//車廂類
TCarriageCollectionItem = class(TCollectionItem)
…
published
//車廂號碼
property CarriageNum: Integer read FCarriageNum write FCarriageNum;
//座位數
property SeatCount: Integer read FSeatCount write FSeatCount;
//車廂類型
property CarriageType: TCarriageType read FCarriageType write FCarriageType;
//服務員名稱
property ServerName: string read FServerName write FServerName;
end;
TTrain=class;
//車廂容器屬性類
TCarriageCollection = class(TCollection)
private
FTrain:TTrain;
function GetItem(Index: Integer): TCarriageCollectionItem;
procedure SetItem(Index: Integer; const Value: TCarriageCollectionItem);
protected
function GetOwner: TPersistent; override;
public
constructor Create(ATrain: TTrain);
function Add: TCarriageCollectionItem;
property Items[Index: Integer]: TCarriageCollectionItem read GetItem
write SetItem; default;
end;
//火車類
TTrain = class(TComponent)
private
FItems: TCarriageCollection;
procedure SetItems(Value: TCarriageCollection);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Carriages: TCarriageCollection read FItems write SetItems;
end;
其中車廂類的定義非常簡單,只是定義了四個屬性。而車廂集合類重定義了靜態的Add方法以及Items屬性,其返回結果類型改為了TCarriageCollectionItem,下面是車廂集合類的實現代碼:
function TCarriageCollection.Add: TCarriageCollectionItem;
begin
Result:=TCarriageCollectionItem(inherited Add);
end;
constructor TCarriageCollection.Create(ATrain: TTrain);
begin
inherited Create(TCarriageCollectionItem);
FTrain:=ATrain;
end;
function TCarriageCollection.GetItem(
Index: Integer): TCarriageCollectionItem;
begin
Result := TCarriageCollectionItem(inherited GetItem(Index));
end;
function TCarriageCollection.GetOwner: TPersistent;
begin
Result:=FTrain;
end;
procedure TCarriageCollection.SetItem(Index: Integer;
const Value: TCarriageCollectionItem);
begin
inherited SetItem(Index, Value);
end;
其中Add,GetItem和SetItem都非常簡單,就是調用基類的方法,然後將基類的方法的返回結果重新映射為TCollectionItem類型。而構造函數中將TTrain組件作為父組件傳入,並重載GetOwner方法,返回TTrain組件,這樣處理的原因是IDE會在保存集合屬性時調用集合類的GetOwner確認屬性的父控件是誰,這樣才能把集合屬性寫到DFM文件中時,才能存放到正確的位置下面,建立正確的聚合關系。
而火車組件的實現也非常簡單,只要定義一個Published Carriages屬性就可以了,方法實現代碼如下:
constructor TTrain.Create(AOwner: TComponent);
begin
inherited;
FItems := TCarriageCollection.Create(Self);
end;
destructor TTrain.Destroy;
begin
FItems.Free;
inherited;
end;
procedure TTrain.SetItems(Value: TCarriageCollection);
begin
FItems.Assign(Value);
end;
下面將我們的組件注冊到系統面板上之後,就可以在窗體上放上一個TTrain組件,然後然後選中Object Inspector,然後雙擊Carriages屬性,會顯示系統默認的集合屬性編輯器,使用Add按鈕向列表中添加兩個車廂,修改一下屬性,如下圖所示意:
從上面的屬性編輯器我們,可以看到默認情況下,屬性編輯器列表框是按項目索引加上一個橫槓來顯示車廂的名稱,看起來不是很自然。要想修改顯示字符串,需要重載TCarriageCollectionItem的GetDisplayName方法。修改後的GetDisplayName方法顯示車廂加車廂號碼:
function TCarriageCollectionItem.GetDisplayName: string;
begin
Result:='車廂'+IntToStr(CarriageNum);
end;
示意圖:
保存一下文件,使用View As Text右鍵菜單命令察看一下DFM文件,我們會看到我們設計的車廂類的屬性確實都被寫到了DFM文件中,並且Carriages屬性的父親就是Train1:
object Train1: TTrain
Carriages = <
item
CarriageNum = 1
SeatCount = 100
CarriageType = ctHard
ServerName = '陳省'
end
item
CarriageNum = 2
SeatCount = 200
CarriageType = ctHard
ServerName = 'hubdog'
end>
Left = 16
Top = 8
End
TOwnedCollection
從Delphi4開始,VCL增加了一個TOwnedCollection類,它是TCollection類的子類,如果我們的TCarriageCollection類是從TOwnedCollection類繼承的,這時我們就不再需要向上面重載GetOwner方法並返回父控件給IDE,以便TCarriageCollection屬性能出現在Object Inspector中了。
總結
本章中我介紹了幾乎所有VCL中重要的容器類,其中TList及其子類相當於通用的容器類,雖然不如C++和Java功能那麼強大,但是用好了已經足以滿足我們90%的開發需要,而TStrings及其子類,還有TCollection則是實現所見即所得設計的關鍵類,對於開發靈活強大的自定義組件來說是必不可少的。