Windows消息机制和Delphi的事件驱动机制
http://blog.163.com/muhx1981@126/blog/static/81459489200610305170213/
一直以来都弄不清楚Delphi的事件驱动机制,今天看Delphi源代码,似乎有些明白了。
问题:用鼠标单击按钮,为什么能执行我写的代码?
环境:创建一个工程并保存,窗体上放置一个Button,在Button上双击鼠标左键,在Button1Click中写入一行代码,保存,所有控件的名字都保持默认的命名。
现象:
1.在Unit1.dfm中有一行语句
OnClick = Button1Click
2.TButton类中有published限制的属性
property OnClick;
从声明方式可知是继承而来的属性。
3.TButton的父类和祖先类TButtonControl, TWinControl中没有关于OnClick的信息。
4.TWinControl的父类TControl中有Published限制的属性
property OnClick: TNotifyEvent read FOnClick write FOnClick stored IsOnClickStored;
5.TNotifyEvent = procedure(Sender: TObject) of Object;
这是一个方法指针的定义。
6.跟踪FOnClick,发现只有在下面过程中使用到FOnClick:
procedure TControl.Click;
begin
{ Call OnClick if assigned and not equal to associated action's OnExecute.
If associated action's OnExecute assigned then call it, otherwise, call
OnClick. }
if Assigned(FOnClick) and (Action <> nil) and (@FOnClick <> @Action.OnExecute) then
FOnClick(Self)
else if not (csDesigning in ComponentState) and (ActionLink <> nil) then
ActionLink.Execute(Self)
else if Assigned(FOnClick) then
FOnClick(Self);
end;
这段代码有一条注释。
7.跟踪过程Click,发现只存在以下过程:
procedure TControl.WMLButtonUp(var Message: TWMLButtonUp);
begin
inherited;
if csCaptureMouse in ControlStyle then MouseCapture := False;
if csClicked in ControlState then
begin
Exclude(FControlState, csClicked);
if PtInRect(ClientRect, SmallPointToPoint(Message.Pos)) then Click;
end;
DoMouseUp(Message, mbLeft);
end;
即,当鼠标左键送开并且满足一定条件时,执行Click过程。
需要注意的是当执行Click过程之后依然需要执行DoMouseUp过程。
8.找到这个过程的定义处,发现类接口中如下定义:
procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
而消息常量:
{$EXTERNALSYM WM_LBUTTONUP}
WM_LBUTTONUP = $0202;
至此,已经和Wondows消息机制联系起来了。
结论:控件的事件实际上是响应Windows消息的过程。事件用方法指针实现,当将过程赋值给方法指针,而Wondows发出了对应的消息,则通过事件(方法指针)指向的实际过程来使得对应的消息得到响应。