事件連結系統發生的動作與回應代碼(事件處理程序)。透過事件,應用程式開發者無需修改元件源碼即可客製化行為。
Delphi 以方法指標實現事件——指向特定物件實例特定方法的指標。元件編寫者將其作為容器,事件觸發時呼叫使用者定義的方法:
procedure TControl.Click;
begin
if Assigned(OnClick) then OnClick(Self);
end;
事件以屬性形式實現,使用私有欄位儲存方法指標(慣例加 F 前綴),屬性型別為方法指標型別:
type
TControl = class(TComponent)
private
FOnClick: TNotifyEvent;
protected
property OnClick: TNotifyEvent read FOnClick write FOnClick;
end;
所有事件皆為程序。Delphi 定義標準型別(如 TNotifyEvent、TKeyPressEvent),自訂事件可復用或自行定義。若需回傳資訊,僅能透過 var 參數。典型範例 TKeyPressEvent 允許修改 Key 以改變字元或抑制預設處理。
元件不得依賴使用者撰寫處理程序。空處理程序應與無處理程序產生相同結果。正確呼叫模式:
if Assigned(OnClick) then OnClick(Self);
{ 執行預設處理 }
錯誤模式:在 else 中執行預設處理,將導致使用者無法透過空處理程序抑制行為。
若需支援使用者覆寫預設行為(如 OnKeyPress 設 Key := #0 抑制字元),應在呼叫事件後檢查 var 參數:
if Assigned(OnKeyPress) then OnKeyPress(Self, Key);
if Key <> #0 then { 執行預設處理 };
所有控制項繼承自 TControl 的標準事件(OnClick、OnMouseDown 等)及 TWinControl 的鍵盤/焦點事件。這些事件在祖先類別中為 protected 動態方法,若需公開,只需在子類別 published 區重新宣告屬性名稱即可繼承實作:
type
TMyControl = class(TCustomControl)
published
property OnClick; { 使其出現在物件檢視器 }
end;
修改標準事件行為:覆寫對應動態方法(如 Click),呼叫 inherited 保留標準流程(含使用者事件處理),再加入自訂邏輯。
僅當行為截然不同於現有事件時才需定義新事件。步驟:觸發條件 → 定義處理程序型別 → 宣告事件屬性 → 呼叫事件。觸發來源可能為 Windows 訊息、屬性變更或內部邏輯。範例展示 TControl 如何將 WM_LBUTTONDOWN 轉為 OnMouseDown 事件。
Delphi 以訊息分派系統將 Windows 訊息轉為物件方法呼叫。核心三層:MainWndProc(靜態、含例外處理)→ WndProc(虛擬、可覆寫過濾)→ Dispatch(靜態、依 Msg 欄位分派至對應處理方法或 DefaultHandler)。
包含訊息 ID、wParam (16-bit)、lParam (32-bit) 及結果值。Delphi 為各類訊息定義專屬記錄型別(如滑鼠訊息的 XPos/YPos),避免手動拆解位元。
每個元件類型註冊 MainWndProc 為視窗程序,轉交給 WndProc,再由 Dispatch 依訊息 ID 尋找處理方法。若無對應方法則呼叫 DefaultHandler(通常忽略)。此機制保證向任何元件發送任意訊息皆安全。
原則:優先修改事件行為而非訊息行為。若必須修改,覆寫對應處理方法(使用 message 指令而非 override):
type
TMyComponent = class(...)
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
end;
處理方法中可讀寫訊息記錄所有欄位(var 參數),常修改 Result 以改變回傳值。若需攔截訊息防止分派,覆寫 WndProc 於呼叫 inherited 前過濾:
procedure TMyControl.WndProc(var Message: TMessage);
begin
if ShouldProcess(Message) then inherited WndProc(Message);
end;
TControl.WndProc 即示範拖曳時過濾滑鼠訊息的實作。