元件類聲明標準結構
class PACKAGE TMyComponent : public TComponent // 或 TControl/TCustomControl
{
private: // 內部實作細節
// 1. 儲存屬性真實值的欄位
int FMyProperty;
// 2. 儲存事件處理器的欄位
TNotifyEvent FOnMyEvent;
// 3. 內部輔助方法
void InternalUpdate();
protected: // 衍生類可存取/覆寫
// 1. 虛擬方法:衍生類可擴充行為
virtual void __fastcall DoMyEvent();
// 2. 訊息處理函數
void __fastcall WMPaint(TMessage& Msg);
public: // 執行期/設計期可存取 (非設計期可見)
// 1. 建構/解構
__fastcall TMyComponent(TComponent* Owner);
__fastcall ~TMyComponent();
// 2. 公開方法 (行為)
void __fastcall RefreshData();
// 3. 非發布屬性 (執行期可用,物件檢視器不可見)
__property int RuntimeOnlyProp = {read=FRuntimeProp, write=SetRuntimeProp};
__published: // 設計期可見 (物件檢視器、屬性編輯器、串流)
// 1. 發布屬性
__property int MyProperty = {read=FMyProperty, write=SetMyProperty, default=0, nodefault};
// 2. 發布事件
__property TNotifyEvent OnMyEvent = {read=FOnMyEvent, write=FOnMyEvent};
};
屬性設計模式
| 模式 | 語法 | 適用場景 |
| 直接欄位存取 | __property int Prop = {read=FProp, write=FProp}; | 簡單資料,無副作用 |
| 存取函數 | __property int Prop = {read=GetProp, write=SetProp}; | 需驗證、觸發更新、副作用 (如重繪、通知) |
| 預設值 | default=0 / nodefault | 減少 DFM 檔案體積,設計期顯示粗體 |
| 陣列屬性 | __property int Items[int] = {read=GetItem, write=SetItem}; | 索引式存取 |
| 預設屬性 | __property int Items[int] = {read=GetItem, write=SetItem, default}; | Comp[0] 可簡寫為 Comp[0] (同樣),主要用於 default 指示器 |
事件設計模式
標準事件 (無參數/僅 Sender)
// 類型定義 (系統已定義)
typedef void __fastcall (__closure *TNotifyEvent)(System::TObject* Sender);
// 成員欄位
TNotifyEvent FOnClick;
// 發布
__property TNotifyEvent OnClick = {read=FOnClick, write=FOnClick};
// 觸發方法 (protected virtual 允許衍生類擴充)
virtual void __fastcall DoClick() {
if (FOnClick) FOnClick(this); // 呼叫使用者處理器
}
自訂參數事件
// 1. 定義事件類型 (函數指標)
typedef void __fastcall (__closure *TMyKeyEvent)(System::TObject* Sender, WORD& Key, TShiftState Shift);
// 2. 成員欄位
TMyKeyEvent FOnMyKey;
// 3. 觸發方法
virtual void __fastcall DoMyKey(WORD& Key, TShiftState Shift) {
if (FOnMyKey) FOnMyKey(this, Key, Shift);
}
// 4. 發布
__property TMyKeyEvent OnMyKey = {read=FOnMyKey, write=FOnMyKey};
元件註冊與設計期安裝
// 同名命名空間 (慣例:檔名 MyComp.cpp → namespace Mycomp)
namespace Mycomp {
// 設計期驗證 (防止抽象類被放入調色盤)
static inline void ValidCtrCheck(TMyComponent*) {
new TMyComponent(NULL); // 若有純虛函數會編譯錯誤
}
void __fastcall PACKAGE Register() {
TComponentClass classes[1] = { __classid(TMyComponent) };
RegisterComponents("My Components", classes, 0); // 調色盤分頁名
}
}
進階技巧
- 屬性編輯器:
RegisterPropertyEditor(__typeinfo(AnsiString), TMyComponent, "MyProperty", __classid(TMyStringPropertyEditor)) 自訂下拉/對話框編輯。
- 元件編輯器:
RegisterComponentEditor(__classid(TMyComponent), __classid(TMyComponentEditor)) 加入右鍵選單動詞 (如「設定精靈」)。
- 串流處理:覆寫
DefineProperties 儲存非發布資料;Loaded 讀取後初始化。
- 包裝 ActiveX:
TActiveXControl 基類,DECLARE_OLECONTROL 巨集。
常見錯誤
- 發布區塊放入方法 (僅屬性/事件)。
write 指定非 __fastcall 函數。
- 事件類型未加
__closure (BCB 關鍵字,表示成員函數指標)。
- 忘記
PACKAGE 關鍵字 (動態套件導出/導入修飾)。
- 設計期驗證
ValidCtrCheck 缺失導致抽象類被實例化 Crash。