日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

delphi VCL研究之消息分发机制(转)

發布時間:2024/6/18 c/c++ 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 delphi VCL研究之消息分发机制(转) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文來源,http://blog.csdn.net/sushengmiyan/article/details/8635550

1.VCL 概貌

先看一下VCL類圖的主要分支,如圖4.1所示。
在圖中可以看到,TObject是VCL的祖先類,這也是Object Pascal語言所規定的。但實際上,TObject以及TObject聲明所在的system.pas整個單元,包括在“編譯器魔法”話題中提到的_ClassCreate等函數,都是編譯器內置支持的。因此,無法修改、刪除system.pas中的任何東西,也無法將system.pas加入你的project,否則會得到“Identifier redeclared ‘system’”的錯誤提示,因project中已經被編譯器自動包含了system單元。
意思是,TObject是Object Pascal語言/編譯器本身的一個性質!

TObject封裝了Object Pascal類/對象的最基本行為。
TPersistent派生自TObject,TPersistent使得自身及其派生類對象具有自我保存、持久存在的能力。
TComponent派生自TPersistent,這條分支之下所有的類都可以被稱為“組件”。組件的一般特性是:
(1)可出現在開發環境的“組件板”上。

(2)能夠擁有和管理其他組件。

(3)能夠存取自身(這是因為TComponent派生自TPersistent)。
TControl派生自TComponent,其分支之下所有的類,都是在運行時可見的組件。
TWinControl派生自TControl,這個分支封裝了Windows系統的屏幕對象,也就是一個真正的Windows窗口(擁有窗口句柄)。
TCustomControl派生自TwinControl。從TCustomControl開始,組件擁有了Canvas(畫布)屬性。

2.TObject與消息分發

首先來看一下TObject這個“萬物之源”究竟長得何等模樣。它的聲明如下:

1 TObject = class 2 constructor Create; 3 procedure Free; 4 class function InitInstance(Instance: Pointer): TObject; 5 procedure CleanupInstance; 6 function ClassType: TClass; 7 class function ClassName: ShortString; 8 class function ClassNameIs(const Name: string): Boolean; 9 class function ClassParent: TClass; 10 class function ClassInfo: Pointer; 11 class function InstanceSize: Longint; 12 class function InheritsFrom(AClass: TClass): Boolean; 13 class function MethodAddress(const Name: ShortString): Pointer; 14 class function MethodName(Address: Pointer): ShortString; 15 function FieldAddress(const Name: ShortString): Pointer; 16 function GetInterface(const IID: TGUID; out Obj): Boolean; 17 class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry; 18 class function GetInterfaceTable: PInterfaceTable; 19 function SafeCallException(ExceptObject: TObject; 20 ExceptAddr: Pointer): HResult; virtual; 21 procedure AfterConstruction; virtual; 22 procedure BeforeDestruction; virtual; 23 procedure Dispatch(var Message); virtual; 24 procedure DefaultHandler(var Message); virtual; 25 class function NewInstance: TObject; virtual; 26 procedure FreeInstance; virtual; 27 destructor Destroy; virtual; 28 end; Delphi Code

? ? ? ?從TObject的聲明中可以看到,TObject包含了諸如實例初始化、實例析構、RTTI、消息分發等相關實現的方法。現在就來研究一下TObject與消息分發,這也是VCL對Windows消息封裝的模型基礎。
? ? ? 在TObject類中,有一個Dispatch()方法和一個DefaultHandler()方法,它們都是與消息分發機制相關的。
Dispatch()負責將特定的消息分發給合適的消息處理函數。首先它會在對象本身類型的類中尋找該消息的處理函數,如果找到,則調用它;如果沒有找到而該類覆蓋了TObject的DefaultHandler(),則調用該類的DefaultHandler();如果兩者都不存在,則繼續在其基類中尋找,直至尋找到TObject這一層,而TObject已經提供了默認的DefaultHandler()方法。
? ? ? 先來看一個示例程序,它演示了消息分發及處理的過程。
首先自定義一個消息結構TMyMsg,它是我們自定義的消息記錄類型。對于自定義的消息類型,VCL只規定它的首4字節必須是消息編號,其后的數據類型任意。同時,VCL也提供了一個TMessage類型用于傳遞消息。在此程序中,不使用TMessage,而用TMyMsg代替:

1 type 2 TMyMsg = record // 自定義消息結構 3 Msg : Cardinal; // 首4字節必須是消息編號 4 MsgText : ShortString; // 消息的文字描述 5 end;

TMyMsg記錄類型的第2個域我們定義為MsgText,由該域的字符串來給出對這個消息的具體描述信息。當然,這些信息都是由消息分發者給出的。
然后,定義一個類,由它接受外界發送給它的消息。這個類可以說明這個演示程序的核心問題。

TMsgAccepter = class // 消息接收器類 private// 編號為2000的消息處理函數procedure AcceptMsg2000(var msg : TMyMsg); message 2000;// 編號為2002的消息處理函數procedure AcceptMsg2002(var msg : TMyMsg); message 2002;publicprocedure DefaultHandler(var Message); override; //默認處理方法 end;

在Object Pascal中,指明類的某個方法為某一特定消息的處理函數,則在其后面添加message關鍵字與消息值,以此來通知編譯器。正如上面類定義中的

procedure AcceptMsg2000(var msg : TMyMsg); message 2000;

指明AcceptMsg2000()方法用來處理值為2000的消息,該消息以及參數將通過msg參數傳遞給處理函數。
TMsgAccepter類除提供了值為2000和2002的兩個消息的處理函數外,還提供了一個默認的消息處理方法DefaultHandler()。該方法是在TObject中定義的虛方法,而在TMsgAccepter類中覆蓋(override)了該方法,重新給出了新的實現。
TMyMsg結構聲明與TMsgAccepter類的聲明與實現都被定義在MsgDispTest單元中。完整的單元代碼如下,請參看其中的TMsgAccepter類的各方法的實現:

unit MsgDispTest;interfaceuses Dialogs, Messages; typeTMyMsg = recordMsg : Cardinal;MsgText : ShortString;end;TMsgAccepter = class // 消息接收器類privateprocedure AcceptMsg2000(var msg : TMyMsg); message 2000;procedure AcceptMsg2002(var msg : TMyMsg); message 2002;publicprocedure DefaultHandler(var Message); override; //默認處理函數end;implementation { TMsgAccepter }procedure TMsgAccepter.AcceptMsg2000(var msg: TMyMsg); beginShowMessage('嗨,我收到了編號為 2000 的消息,它的描述是:' + msg.MsgText); end; procedure TMsgAccepter.AcceptMsg2002(var msg: TMyMsg); beginShowMessage('嗨,我收到了編號為2002的消息,它的描述是:' + msg.MsgText); end; procedure TMsgAccepter.DefaultHandler(var message); beginShowMessage('嗨,這個消息我不認識,無法接收,它的描述是:' +TMyMsg(message).MsgText); end;end. Delphi Code

接著就是界面代碼,我們在Application的主Form(Form1)上放入3個按鈕,程序界面如圖4.2所示。
界面上的3個按鈕的名字分別是:btnMsg2000、btnMsg2001、btnMsg2002。該3個按鈕用來分發3個消息,將3個消息的值分別定義為2000、2001和2002。
在Form的OnCreate事件中,創建一個TMsgAccepter類的實例。然后,在3個按鈕的OnClick事件中分別加上代碼,將3個不同的消息分發給TMsgAccepter類的實例對象,以觀察TMsgAccepter作出的反應。最后,在Form的OnDestroy事件中,析構TMsgAccepter類的實例對象。完整的界面程序單元代碼如下:

1 unit Unit1; 2 3 interface 4 5 uses 6 Windows, Messages, SysUtils, Variants, Classes, Graphics, 7 Controls,Forms, Dialogs, StdCtrls, MsgDispTest; 8 9 type 10 TForm1 = class(TForm) 11 btnMsg2000: TButton; 12 btnMsg2001: TButton; 13 btnMsg2002: TButton; 14 Label1: TLabel; 15 procedure FormCreate(Sender: TObject); 16 procedure FormDestroy(Sender: TObject); 17 procedure btnMsg2000Click(Sender: TObject); 18 procedure btnMsg2002Click(Sender: TObject); 19 procedure btnMsg2001Click(Sender: TObject); 20 end; 21 22 var 23 Form1: TForm1; 24 MsgAccept : TMsgAccepter; // 自定義的消息接收類 25 26 implementation 27 {$R *.dfm} 28 29 procedure TForm1.FormCreate(Sender: TObject); 30 begin 31 // 創建TMsgAccepter類的實例 32 MsgAccept := TMsgAccepter.Create(); 33 end; 34 procedure TForm1.FormDestroy(Sender: TObject); 35 begin 36 // 析構TMsgAccepter類的實例 37 MsgAccept.Free(); 38 MsgAccept := nil; 39 end; 40 procedure TForm1.btnMsg2000Click(Sender: TObject); 41 var 42 Msg : TMyMsg; 43 begin 44 // 將值為2000的消息分發給MsgAccept對象,觀察其反應 45 Msg.Msg := 2000; 46 Msg.MsgText := 'Message 2000'; // 消息的文字描述 47 MsgAccept.Dispatch(Msg); // 分發消息 48 end; 49 procedure TForm1.btnMsg2002Click(Sender: TObject); 50 var 51 Msg : TMyMsg; 52 begin 53 // 將值為2002的消息分發給MsgAccept對象,觀察其反應 54 Msg.Msg := 2002; 55 Msg.MsgText := 'Message 2002'; // 消息的文字描述 56 MsgAccept.Dispatch(Msg); // 分發消息 57 end; 58 procedure TForm1.btnMsg2001Click(Sender: TObject); 59 var 60 Msg : TMyMsg; 61 begin 62 // 將值為2001的消息分發給MsgAccept對象,觀察其反應 63 Msg.Msg := 2001; 64 Msg.MsgText := 'Message 2001'; // 消息的文字描述 65 MsgAccept.Dispatch(Msg); // 分發消息 66 end; 67 68 end.

在TMsgAccepter類的代碼中可以看到,它只能處理編號為2000和2002的消息,而沒有編號為2001的消息的處理函數,但它覆蓋了TObject的DefaultHandler(),于是就提供了默認的消息處理函數。
運行程序,分別單擊3個按鈕,得到了3句不同的回答。對于消息2000和2002,TMsgAccepter照單全收,正確識別出所接收到的消息。而只有在接收消息2001時,由于沒有提供專門的消息處理函數,導致了對DefaultHandler()的調用。幸運的是,在DefaultHandler中,還可以使用message參數給出的附加信息(TMyMsg記錄類型中的MsgText域)。

轉載于:https://www.cnblogs.com/jiqiwoniu/p/4552289.html

總結

以上是生活随笔為你收集整理的delphi VCL研究之消息分发机制(转)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。