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发出了对应的消息,则通过事件(方法指针)指向的实际过程来使得对应的消息得到响应。