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

深入C++ Builder元件開發(三):VCL訊息機制進階與__closure關鍵字詳解

     編輯:關於C++

前言:尋找學習資源的最佳路徑

許多讀者詢問元件開發的入門資源。誠實說,網路上系統性教材極少。最有效的途徑只有兩條:研讀 VCL 原始碼與參與 Borland 新聞群討論(forums.borland.com)。本系列末尾將贈送兩篇實戰文章:專業級元件原始碼解析、完整元件開發流程實作。

超越 WM_XXXX:CN_ 與 CM_ 訊息

傳統 Windows 訊息(WM_*)不足以應對設計時期屬性變更(如修改 Font 後需重繪)。VCL 內部定義了兩類特殊訊息:

  • CN_XXXX:源自 WM_COMMAND、WM_NOTIFY 等父視窗轉發的子控制項通知。父視窗收到後加上 CN_BASE 再分發給真正的子控制項處理。
  • CM_XXXX:VCL 內部自訂訊息,如 CM_FONTCHANGED(字體變更)、CM_ENABLEDCHANGED 等,定義於 Controls.pas。

實例:TBitBtn 處理 CN_DRAWITEM

procedure TBitBtn.CNDrawItem(var Message: TWMDrawItem);
var
  R: TRect;
begin
  FCanvas.Handle := Message.DrawItemStruct.hDC;
  R := ClientRect;
  // ... 繪製圖文、按下偏移、焦點框 ...
  if IsDown then OffsetRect(R, 1, 1);
  TButtonGlyph(FGlyph).Draw(FCanvas, R, Point(0,0), Caption, FLayout, FMargin,
    FSpacing, State, False, DrawTextBiDiModeFlags(0));
  if IsFocused and IsDefault then begin
    R := ClientRect; InflateRect(R, -4, -4);
    FCanvas.Pen.Color := clWindowFrame;
    FCanvas.Brush.Color := clBtnFace;
    DrawFocusRect(FCanvas.Handle, R);
  end;
  FCanvas.Handle := 0;
end;

本質上仍是在 HDC 上繪圖,與 WM_PAINT 邏輯相似。

訊息映射宏:處理無虛擬函數的 CN/CM 訊息

CN/CM 訊息無對應虛擬函數,需用訊息映射宏:

BEGIN_MESSAGE_MAP
  VCL_MESSAGE_HANDLER(CN_DRAWITEM, TWMDrawItem, CNDrawItem)
END_MESSAGE_MAP(TCustomControl)

void __fastcall CNDrawItem(TWMDrawItem &Msg);

自訂事件與 __closure 關鍵字深度解析

上一篇出現的事件型別宣告:

typedef void __fastcall (__closure *THoverShapeEvent)(TObject* Sender, int Index);
typedef void __fastcall (__closure *TShapeSelectedEvent)(TObject* Sender, int Index);

語法拆解

  • THoverShapeEvent:函數指標型別名稱。
  • void __fastcall:回傳型別與呼叫慣例。
  • (__closure * ...):關鍵字,標記這是「閉包」指標,包含物件實例指標與成員函數位址。
  • (TObject* Sender, int Index):參數列表。

為什麼需要 __closure?

傳統 C++ 成員函數指標語法繁瑣且受限於特定類別:

// 傳統寫法:綁定特定類別 base
typedef void __fastcall (base::* BDCallBack)(String path, int type);
BDCallBack m = &base::func;  // 只能指向 base::func

若多個類別都要當回呼,需為每類別宣告不同指標型別——極不靈活。

__closure 的威力

// 統一型別,任何類別的相容成員函數皆可指派
typedef void __fastcall (__closure *BDCallBack)(String path, int type);

class A {
  BDCallBack func;
  void DoSomething() { /* ... */ func("Found it", 0); }
};

class B {
  void FuncB() {
    A a;
    a.func = this->callback;  // 直接指派 B::callback
  }
  void __fastcall callback(String path, int type) { /* ... */ }
};

__closure 讓事件系統能「綁定任意物件的任意相容成員函數」,這正是 VCL 事件模型的基石。

Borland 官方文件的說明

The keyword __closure was added to support the VCL and is used when declaring event handler functions.

雖然官方說明極簡略,但實作上它解決了「成員函數指標跨類別通用」的核心難題。

下一步預告

下一篇將實作完整元件,示範自訂事件觸發、屬性編輯器整合、設計時/執行時行為差異處理等完整流程。

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