| 需求 | 建議祖先 | 理由 |
|---|---|---|
| 有介面、需處理鍵盤、非容器 | TCustomControl | 擁有視窗控制代碼(HWND)、可獲取焦點、完整訊息循環 |
| 有介面、不需鍵盤、需滑鼠 | TGraphicControl | 無 HWND、輕量、繪圖由父視窗代管、無法獲取焦點 |
| 無介面、非視覺元件 | TComponent | 如 TOpenDialog、TTimer,只參與元件流式儲存 |
| 擴充既有控制項(如 TPanel) | TCustomPanel 而非 TPanel | 可控制屬性可見性;建構子/解構子為虛擬,利於多型銷毀 |
本系列重點講解前兩類;後兩類相對單純略過。
VCL 已在 TGraphicControl.WMPaint 封裝好流程:
procedure TGraphicControl.WMPaint(var Message: TWMPaint);
begin
if Message.DC <> 0 then begin
Canvas.Lock;
try
Canvas.Handle := Message.DC;
try
Paint; // 虛擬函數,衍生類別重寫此處
finally
Canvas.Handle := 0;
end;
finally
Canvas.Unlock;
end;
end;
end;
所有專業級元件皆透過 重寫 Paint() 繪圖,優點:
Canvas 鎖定/解鎖與 HDC 指派。Invalidate() 觸發重繪,VCL 會合併區域、節流重繪。Repaint():立即強制重繪,可能造成閃爍與效能浪費。Invalidate():標記區域失效,讓訊息佇列在適當時機合併重繪,平滑高效。void __fastcall TLine::SetLineWidth(int value) {
if (FLineWidth != value) {
FLineWidth = value;
Invalidate(); // 最佳實務
}
}
下一篇將介紹:
Canvas->CopyRect + 記憶體位圖)消除閃爍。ClipRect)限制繪圖範圍。Paint 內重複建立 GDI 物件。StretchDraw、DrawFocusRect 等優化 API。CKER 的經典文章《VCL 訊息機制深度解析》:
CSDN 連結
元件開發的核心就是「處理訊息、發布事件」。基礎訊息處理(WM_*)前述文章已涵蓋,接下來將深入 CN_/CM_ 內部訊息、自訂事件、屬性編輯器等進階主題。