TCollection 是 VCL 中設計時可視化編輯的核心容器基類,支援同質項目集合的擁有權管理、持久化、Object Inspector 整合。所有標準元件的子項集合(TDBGridColumns、TStatusPanels、TListColumns 等)均繼承自它。本文深度解析其架構、關鍵 API、衍生類模式與自定義集合開發全流程。
TObject
└── TPersistent
└── TCollection
└── [用戶衍生類,如 TDBGridColumns]
TObject
└── TPersistent
└── TCollectionItem
└── [用戶衍生項目類,如 TColumn]
核心契約:
1. TCollection 擁有項目所有權,負責 Create/Free。
2. 項目類必須繼承 TCollectionItem,並實作 Assign(TPersistent*) 以支援集合複製。
3. 集合類構造函數必須傳遞項目元類:new TMyCollection(__classid(TMyItem))。
| 集合類 | 項目類 | 宿主元件 |
|---|---|---|
| TDBGridColumns | TColumn | TDBGrid |
| TStatusPanels | TStatusPanel | TStatusBar |
| TListColumns | TListColumn | TListView |
| THeaderSections | THeaderSection | THeaderControl |
| TFieldDefs | TFieldDef | TDataSet |
| TIndexDefs | TIndexDef | TTable |
| TCoolBands | TCoolBand | TCoolBar |
| TWebActionItems | TWebActionItem | TWebDispatcher |
| 成員 | 類型 | 說明 |
|---|---|---|
Count | 屬性 (r) | 項目數量 |
Items[int Index] | 屬性 (rw) | 下標訪問,返回 TCollectionItem* |
ItemClass | 屬性 (r) | 項目元類 TMetaClass* |
Add() | 方法 | 尾部新增項目,返回項目指標 |
Insert(int Index) | 方法 | 指定位置插入,返回項目指標 |
Delete(int Index) | 方法 | 刪除並釋放項目 |
Clear() | 方法 | 清空並釋放所有項目 |
Assign(TPersistent*) | 方法 | 深度複製另一集合 |
BeginUpdate/EndUpdate | 方法 | 凍結/解凍 UI 刷新,批量操作必用 |
FindItemID(int ID) | 方法 | 按 TCollectionItem.ID 查找 |
class TMyItem : public TCollectionItem {
int FValue;
AnsiString FName;
__published: // 僅 published 成員可在 Object Inspector 編輯
__property int Value = { read=FValue, write=FValue, default=0 };
__property AnsiString Name = { read=FName, write=FName };
public:
virtual void Assign(TPersistent* Source) override {
if (TMyItem* src = dynamic_cast<TMyItem*>(Source)) {
Value = src->Value; Name = src->Name;
} else inherited::Assign(Source);
}
};
class TMyCollection : public TCollection {
public:
__fastcall TMyCollection() : TCollection(__classid(TMyItem)) {}
TMyItem* __fastcall Add() { return static_cast<TMyItem*>(inherited::Add()); }
TMyItem* __fastcall Insert(int Index) { return static_cast<TMyItem*>(inherited::Insert(Index)); }
__property TMyItem* Items[int Index] = { read=GetItem, write=SetItem }; // 強類型索引器
};
class TMyComponent : public TComponent {
TMyCollection* FItems;
__published:
__property TMyCollection* Items = { read=FItems, write=SetItems };
protected:
void __fastcall SetItems(TMyCollection* Value) { FItems->Assign(Value); }
public:
__fastcall TMyComponent(TComponent* Owner) : TComponent(Owner) {
FItems = new TMyCollection();
}
__fastcall ~TMyComponent() { delete FItems; }
};
// 在 Register() 函數中
RegisterPropertyEditor(__typeinfo(TMyCollection), TMyComponent, "Items",
__classid(TCollectionPropertyEditor)); // 內建編輯器通常足夠
// 若需自定義對話框,繼承 TCollectionEditor 並覆寫 ShowCollectionEditor()
TCollectionItem.ID 為運行時唯一遞增整數,不等於 索引位置。插入/刪除不改變既有項目 ID,FindItemID 依賴此特性。WriteComponent 序列化為 DFM,格式為 object Items: TMyCollection ... Items = < item ... > end。項目類 必須 正確實作 Assign 否則設計時複製/黏貼會丟失數據。TCollection 非執行緒安全。多執行緒訪問需外部鎖或改用 TThreadList + 自定義項目類。Add/Insert/Delete 為 O(n) 陣列平移。項目數 > 5000 時建議改用 std::vector<TMyItem*> + 手動管理,或實作鏈表版 TCollection。__classid(TMyItem) → Add() 返回 TCollectionItem* 導致強轉崩潰。Assign → Collection->Assign(other) 僅淺複製指標,雙重釋放崩潰。delete FItems → 內存洩漏(VCL 不自動釋放子物件)。delete Items[i] → 破壞集合擁有權,改用 Delete(i) 或 Clear()。TCollection 是 VCL「設計時可視化」能力的基石。掌握其擁有權模型、持久化協議與編輯器整合,你就能開發出像標準元件一樣在 Object Inspector 中流暢運作的自定義集合屬性。