您的位置:首页 > 编程语言 > Delphi

深入理解Delphi的消息机制 2 (转载)

2009-05-08 23:40 411 查看
2004-08-20 17:31作者:NoteXPad出处:天极论坛 责任编辑:方舟

三、VCL 完整的消息分派流程

  1. TButton

  新建一个 Application,在 Form1 上放一个 Button (缺省名为Button1),在其 OnClick 事件中随便写点代码,加上断点,在调试之前,请打开 DCU 调试开关(Project->Options->Compiler->Use Debug DCUs), 这个开关如果不打开,是没法调试 VCL 的,然后 F9 运行,当停留在断点上时,打开Call Stack 窗口(View->Debug Window->Call Stack)可看到调用顺序如下(从底往上看):

TForm1.Button1Click($9637C0)

TControl.Click

TButton.Click

TButton.CNCommand((48401, 660, 0, 524948, 0))

TControl.WndProc((48401, 660, 524948, 0, 660, 0, 660, 8, 0, 0))

TWinControl.WndProc((48401, 660, 524948, 0, 660, 0, 660, 8, 0, 0))

TButtonControl.WndProc((48401, 660, 524948, 0, 660, 0, 660, 8, 0, 0))

TControl.Perform(48401,660,524948)

DoControlMsg(524948,(no value))

TWinControl.WMCommand((273, 660, 0, 524948, 0))

TCustomForm.WMCommand((273, 660, 0, 524948, 0))

TControl.WndProc((273, 660, 524948, 0, 660, 0, 660, 8, 0, 0))

TWinControl.WndProc((273, 660, 524948, 0, 660, 0, 660, 8, 0, 0))

TCustomForm.WndProc((273, 660, 524948, 0, 660, 0, 660, 8, 0, 0))

TWinControl.MainWndProc((273, 660, 524948, 0, 660, 0, 660, 8, 0, 0))

StdWndProc(918056,273,660,524948)

TWinControl.DefaultHandler((no value))

TControl.WMLButtonUp((514, 0, 48, 13, (48, 13), 0))

TControl.WndProc((514, 0, 852016, 0, 0, 0, 48, 13, 0, 0))

TWinControl.WndProc((514, 0, 852016, 0, 0, 0, 48, 13, 0, 0))

TButtonControl.WndProc((514, 0, 852016, 0, 0, 0, 48, 13, 0, 0))

TWinControl.MainWndProc((514, 0, 852016, 0, 0, 0, 48, 13, 0, 0))

StdWndProc(524948,514,0,852016)

TApplication.HandleMessage

TApplication.Run

Project1
  一个 Button 被点击,在 TButton 内部会发生两个消息:WM_LBUTTONDOWN/WM_LBUTTONUP, TButton 没有处理 WM_LBUTTONUP(问题:为什么只响应 WM_LBUTTONUP,这两个消息只应该发生在 Windows 原生控件内,除非 TButton subclass 了 "Button",这部分代码我没看),只是交给 TWinControl.DefaultHandler,随后 TButton 又将生成的 WM_COMMAND 消息发送给它的 Parent,即 TForm,经过一系列消息传递, WM_COMMAND 在 TWinControl.WMCommand 中被处理,通过 DoControlMsg 将 WM_COMMAND 加工成 CN_COMMAND,再利用 TControl.Perform 将 CN_COMMAND 传回 TButton,又通过一系列的消息传递到 TButton 中的 Dispatch,通过查询动态方法表找到 Handler -- TButton.CNCommand,它又调用虚方法 TButton.Click,继而调用 TControl.Click,在这个方法中会调用 FOnClick,而 FOnClick 特性值的内容就是当程序员使用对象查看器撰写 TButton 的 OnClick 事件处理函数时 Delphi 便会自动指定给 TButton 的 OnClick 特性,例子中 OnClick 被指定为 TForm1.Button1Click,因此 TForm1.Button1Click 最终被调用。

  2. TForm

  新建一个 Application,为 Form1 的 OnMouseDown 事件随便写一点代码,在这个方法上设断点,F9 运行,看看 Call Stack

TForm1.FormMouseDown(???,???,[ssLeft],346,212)

TControl.MouseDown(mbLeft,[ssLeft],346,212)

TControl.DoMouseDown((513, 1, 346, 212, (346, 212), 0),mbLeft,[])

TControl.WMLButtonDown((513, 1, 346, 212, (346, 212), 0))

TControl.WndProc((513, 1, 13893978, 0, 1, 0, 346, 212, 0, 0))

TWinControl.WndProc((513, 1, 13893978, 0, 1, 0, 346, 212, 0, 0))

TCustomForm.WndProc((513, 1, 13893978, 0, 1, 0, 346, 212, 0, 0))

TWinControl.MainWndProc((513, 1, 13893978, 0, 1, 0, 346, 212, 0, 0))

StdWndProc(2687598,513,1,13893978)

TApplication.HandleMessage

TApplication.Run

Project1
  鼠标在 Form 上点击,产生两个消息 WM_LBUTTONDOWN/WM_LBUTTONUP,但我们只截获 WM_LBUTTONDOWN。产生的 WM_LBUTTONDOWN 经过一系列的消息传递到达 TObject.Dispatch,通过查询动态方法表在 TForm 的父类 TControl 中找到了 Handler -- TControl.WMLButtonDown,在 TControl.WMLButtonDown 中又经过 TControl.DoMouseDown、TControl.MouseDown 一系列方法调用,最终调用到 FOnMouseDown,FOnMouseDown 被赋值为 TForm1.FormMouseDown,调用 FOnMouseDown 即调用 TForm1.FormMouseDown。

讲了一大堆消息实现过程,那么在实际中到底有哪些应用?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐