首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 控制項 Handle 建立時機:在 CreateWnd 覆寫中執行後續初始化

     編輯:Delphi

VCL 控制項的視窗控制代碼 (Window Handle / HWND) 並非在建構子中建立,而是延遲到 CreateWnd 方法執行時。若需在 Handle 可用後立即執行動作 (如發送訊息、設定子類別化、呼叫需 HWND 的 API),正確做法是覆寫 CreateWnd 並在 inherited 之後撰寫程式碼。

標準覆寫模板


type
  TMyCustomControl = class(TCustomControl)
  protected
    procedure CreateWnd; override;
  end;

procedure TMyCustomControl.CreateWnd;
begin
  // 此時 Handle 尚未建立
  inherited CreateWnd; // 呼叫基類建立 Handle
  // 此時 Handle 已可用 (Self.Handle <> 0)
  // 在此執行需 HWND 的初始化動作
  // 例:SetWindowLong(Handle, GWL_STYLE, ...);
  // 例:SendMessage(Handle, WM_SETFONT, Font.Handle, 0);
end;

為什麼不在建構子做?

  • 建構子執行時,控制項尚未插入父視窗,VCL 尚未呼叫 CreateWindowEx 建立實際 HWND。
  • HandleNeeded 屬性存取會觸發建立,但不保證父視窗鏈結完成。
  • CreateWnd 是 VCL 統一的 Handle 建立進入點,確保父視窗、樣式、字型等前置條件就緒。

對應的銷毀時機:DestroyWnd


procedure TMyCustomControl.DestroyWnd;
begin
  // Handle 即將銷毀,先清理相關資源
  // 例:移除子類別化、釋放 Hook
  inherited DestroyWnd; // 釋放 Handle
end;

常見應用場景

  • 子類別化 (SetWindowLong(Handle, GWL_WNDPROC, ...)) 需在 Handle 建立後、顯示前完成。
  • 呼叫需 HWND 的 API:DragAcceptFiles, RegisterHotKey, SetLayeredWindowAttributes 等。
  • 設定視窗區域 (SetWindowRgn) 建立非矩形視窗。
  • 取得 Canvas.Handle 繪圖初始化 (雖 TCanvas 已封裝此邏輯)。

注意事項

  • 一定要呼叫 inherited CreateWnd,否則 Handle 永不建立,控制項不可見。
  • 若在 CreateWnd 中存取會觸發 HandleNeeded 的屬性 (如 Left, Top),可能導致遞迴或重複建立。
  • 對於 TWinControl 衍生類,CreateParams 可調整建立參數 (樣式、延伸樣式、類別名稱),CreateWnd 負責後續初始化。

小結

「覆寫 CreateWnd,inherited 後執行需 HWND 的邏輯」是 Delphi 元件開發的核心模式之一。掌握 Handle 生命週期 (CreateWnd → 可用 → DestroyWnd → 釋放) 並在此兩點掛鉤初始化/清理,是編寫穩健、相容性好的自訂控制項關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved