TObject → TPersistent → TComponent → TControl
TPersistent:提供串流儲存/載入屬性能力(DFM 依賴此機制)。TComponent:所有元件基類,擁有擁有者/被擁有者關係。TControl:所有可視元件基類,定義位置、大小、顯示、滑鼠/鍵盤互動等核心行為。TControl.WndProc 完整源碼逐段解析源碼位置:$(BCB)\Source\Vcl\Controls.pas(或 Controls.hpp)。
if (csDesigning in ComponentState) then begin
Form := GetParentForm(Self);
if (Form <> nil) and (Form.Designer <> nil) and
Form.Designer.IsDesignMsg(Self, Message) then Exit;
end
設計時期將特定訊息(如選取、拖曳)導向表單設計器處理,避免干擾運行邏輯。
else if (Message.Msg >= WM_KEYFIRST) and (Message.Msg <= WM_KEYLAST) then begin
Form := GetParentForm(Self);
if (Form <> nil) and Form.WantChildKey(Self, Message) then Exit;
end
讓表單優先處理快捷鍵、對話框導航鍵(Tab/Enter/Esc)等。
else if (Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST) then begin
// 3.1 雙擊轉單擊(若未啟用 csDoubleClicks)
if not (csDoubleClicks in ControlStyle) then
case Message.Msg of
WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, WM_MBUTTONDBLCLK:
Dec(Message.Msg, WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
end;
// 3.2 具體滑鼠訊息分派
case Message.Msg of
WM_MOUSEMOVE:
Application.HintMouseMessage(Self, Message); // 提示顯示邏輯
WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
begin
if FDragMode = dmAutomatic then begin
BeginAutoDrag; Exit; // 自動拖放模式
end;
Include(FControlState, csLButtonDown); // 記錄左鍵按下狀態
end;
WM_LBUTTONUP:
Exclude(FControlState, csLButtonDown); // 清除狀態
end;
end
CM_VISIBLECHANGEDelse if Message.Msg = CM_VISIBLECHANGED then
with Message do
SendDockNotification(Msg, WParam, LParam);
CM_* 系列為 VCL 內部訊息,不在 Windows SDK 定義中。此處處理停靠/浮動可視狀態變更通知。
Dispatch(Message)將訊息傳遞給 Dispatch 虛擬方法,進入訊息映射表或動態方法查找對應處理器(如 OnClick, OnMouseDown 事件)。
| 機制 | 說明 |
|---|---|
| 訊息優先級 | 設計模式 > 鍵盤轉發 > 滑鼠處理 > CM_* 內部 > Dispatch |
| 滑鼠狀態機 | FControlState 位標記追蹤按下/釋放/雙擊,支援拖放邏輯 |
| Hint 整合 | WM_MOUSEMOVE 直接呼叫 Application.HintMouseMessage |
| 自動拖放 | dmAutomatic 讓 VCL 自動啟動 BeginDrag |
TControl 開發自訂元件時,務必呼叫 inherited 保留上述核心邏輯。WndProc 並在 case WM_*: 處理完後 inherited,而非完全取代。CM_* 訊息可用於元件間解耦通訊(如 CM_ENABLEDCHANGED, CM_FONTCHANGED)。
掌握 TControl.WndProc,即掌握了 VCL 可視元件輸入處理的心臟。