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