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

深入C++ Builder元件開發(二):DYNAMIC虛擬函數與滑鼠鍵盤事件處理實戰

     編輯:關於C++

DYNAMIC 關鍵字:Delphi 與 C++ 的橋樑

VCL 來源為 Delphi,其虛擬函數有兩種宣告:virtual(標準虛擬函數表)與 dynamic(動態虛擬函數表,節省記憶體,呼叫稍慢)。C++ 無 dynamic 關鍵字,BCB 提供 DYNAMIC 宏 實現相同語意。

// VCL 原始碼 (Delphi)
procedure KeyDown(var Key: Word; Shift: TShiftState); dynamic;
procedure KeyUp(var Key: Word; Shift: TShiftState); dynamic;
procedure KeyPress(var Key: Char); dynamic;

// C++ 衍生類別重寫
DYNAMIC void __fastcall MouseMove(Classes::TShiftState Shift, int X, int Y);
DYNAMIC void __fastcall KeyDown(Word &Key, Classes::TShiftState Shift);

滑鼠與鍵盤事件虛擬函數總表

事件類別虛擬函數備註
滑鼠MouseDown按下
MouseUp釋放
MouseMove移動
Click單擊(含雙擊邏輯)
鍵盤KeyDown按下(含虛擬鍵碼)
KeyUp釋放
KeyPress字元輸入(ANSI 字元)

注意:鍵盤虛擬函數要求類別直接或間接繼承自 TCustomControl(擁有輸入焦點能力)。

實戰範例:TVecCanvas 向量繪圖元件

繼承自 TCustomControl,支援直線繪製、選取、拖曳調整,展示事件處理與自訂事件觸發。

標頭檔 關鍵結構

class PACKAGE TVecCanvas : public TCustomControl {
private:
  TList* ShapeList;
  CShape* CurrentShape;
  bool Down;
  TPoint LastPos, NewPos;
  THoverShapeEvent FOnHoverShape;
  ToolType FTool;
  TShapeSelectedEvent FOnShapeSelected;

  DYNAMIC void __fastcall MouseDown(TMouseButton Button, Classes::TShiftState Shift, int X, int Y);
  DYNAMIC void __fastcall MouseUp(TMouseButton Button, Classes::TShiftState Shift, int X, int Y);
  DYNAMIC void __fastcall MouseMove(Classes::TShiftState Shift, int X, int Y);
  void __fastcall DoHoverShape(int index);
  void __fastcall SetTool(ToolType value);
  void __fastcall DoShapeSelected(int index);

protected:
  void __fastcall Paint();  // 重繪核心

public:
  __fastcall TVecCanvas(TComponent* Owner);
  __fastcall ~TVecCanvas();
  int __fastcall ShapeAtPos(int x, int y);

__published:
  __property Color;
  __property OnClick;          // 繼承自祖先,僅暴露
  __property THoverShapeEvent OnHoverShape = { read=FOnHoverShape, write=FOnHoverShape };
  __property Align;
  __property OnMouseMove;
  __property OnMouseDown;
  __property OnMouseUp;
  __property ToolType Tool = { read=FTool, write=SetTool };
  __property TShapeSelectedEvent OnShapeSelected = { read=FOnShapeSelected, write=FOnShapeSelected };
};

實作檔 核心邏輯

__fastcall TVecCanvas::TVecCanvas(TComponent* Owner)
  : TCustomControl(Owner) {
  ShapeList = new TList();
  CurrentShape = NULL;
  Down = false;
  FTool = ttLine;
}

void __fastcall TVecCanvas::MouseDown(TMouseButton Button, Classes::TShiftState Shift, int X, int Y) {
  if (Button != mbLeft) return;
  switch (FTool) {
    case ttLine:
      LastPos = NewPos = Point(X, Y);
      Down = true;
      break;
    case ttSelect:
      if (int sh = ShapeAtPos(X, Y); sh != -1) DoShapeSelected(sh);
      break;
  }
}

void __fastcall TVecCanvas::MouseUp(TMouseButton Button, Classes::TShiftState Shift, int X, int Y) {
  Down = false;
  if (Button == mbLeft && FTool == ttLine) {
    CShape* sh = new CLine();
    sh->Start = LastPos;
    sh->End = Point(X, Y);
    sh->Type = stLine;
    ShapeList->Add(sh);
    Canvas->MoveTo(LastPos.x, LastPos.y);
    Canvas->LineTo(X, Y);
  }
}

void __fastcall TVecCanvas::MouseMove(Classes::TShiftState Shift, int X, int Y) {
  if (!Down) {
    if (int sh = ShapeAtPos(X, Y); sh != -1) DoHoverShape(sh);
    return;
  }
  if (FTool == ttLine) {
    // XOR 模式繪製橡皮筋效果
    Canvas->Pen->Mode = pmNotXor;
    Canvas->MoveTo(LastPos.x, LastPos.y);
    Canvas->LineTo(NewPos.x, NewPos.y);
    NewPos = Point(X, Y);
    Canvas->MoveTo(LastPos.x, LastPos.y);
    Canvas->LineTo(NewPos.x, NewPos.y);
    Canvas->Pen->Mode = pmCopy;
  }
}

void __fastcall TVecCanvas::Paint() {
  for (int n = 0; n < ShapeList->Count; n++) {
    CShape* sh = (CShape*)ShapeList->Items[n];
    sh->Draw(Canvas);
  }
}

關鍵設計點解析

  1. 事件暴露:__property OnClick 僅將祖先已實作的事件發布至物件檢視器,無需重寫邏輯。
  2. 繼承策略:若需完整功能繼承 TButton;若需精簡屬性集繼承 TCustomButton——VCL 推薦後者,建構子/解構子為虛擬,利於擴展。
  3. 自訂事件型別:使用 __closure 讓使用者可指派任意表單方法為事件處理器。
  4. 橡皮筋繪圖:pmNotXor 模式下重複繪製同一線段即可擦除,無需 Invalidate 整個控制項,效能極佳。

下一篇預告

將深入探討 CM_XXXX 訊息處理(如 CM_FONTCHANGED)、屬性編輯器整合、設計時行為客製化。

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