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代替:
TMyMsg記錄類型的第2個域我們定義為MsgText,由該域的字符串來給出對這個消息的具體描述信息。當然,這些信息都是由消息分發者給出的。
然后,定義一個類,由它接受外界發送給它的消息。這個類可以說明這個演示程序的核心問題。
在Object Pascal中,指明類的某個方法為某一特定消息的處理函數,則在其后面添加message關鍵字與消息值,以此來通知編譯器。正如上面類定義中的
procedure AcceptMsg2000(var msg : TMyMsg); message 2000;指明AcceptMsg2000()方法用來處理值為2000的消息,該消息以及參數將通過msg參數傳遞給處理函數。
TMsgAccepter類除提供了值為2000和2002的兩個消息的處理函數外,還提供了一個默認的消息處理方法DefaultHandler()。該方法是在TObject中定義的虛方法,而在TMsgAccepter類中覆蓋(override)了該方法,重新給出了新的實現。
TMyMsg結構聲明與TMsgAccepter類的聲明與實現都被定義在MsgDispTest單元中。完整的單元代碼如下,請參看其中的TMsgAccepter類的各方法的實現:
接著就是界面代碼,我們在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類的實例對象。完整的界面程序單元代碼如下:
在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研究之消息分发机制(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jquery Mobile 百度地图 D
- 下一篇: s3c2440移植MQTT