学会看VCL源码(一)
对于初学Delphi的人,一般只知道拖拖控件,写写一些事件代码,但如果要开始学会深
入了解Delphi就要学会看VCL的源码,作为第一篇,我在这里介绍下最简单的TTimer控件的
封装,从最简单的入手,可以让大家对VCL的封装先有个最基础的了解.
下面进入正题,打开Delphi,拖一个TTimer控件,然后切换到代码视图,找到
Timer1:TTimer的定义,按住Ctrl点击TTimer转到ExtCtrls单元TTimer类的定义代码.首先
它是直接从TComponent继承,看private的定义
FInterval: Cardinal; //定时器的触发间隔
FWindowHandle: HWND; //组件的句柄
FOnTimer: TNotifyEvent; //OnTimer的事件函数
FEnabled: Boolean; //定时器的可用与否
procedure UpdateTimer; //更新定时器方法,下面详细介绍
procedure SetEnabled(Value: Boolean); //Enabled属性的Set方法
procedure SetInterval(Value: Cardinal); //Interval属性的Set方法
procedure SetOnTimer(Value: TNotifyEvent); //OnTimer事件的Set方法
procedure WndProc(var Msg: TMessage); //消息处理函数
protected的定义就一个Timer方法,protected定义的大多是为了子类继承时使用的,这里
是一个动态的方法(关于dynamic和virtual的区别,简单点就只是在程序的存储空间和运
行速度上的不同考虑,这里先不罗嗦,只要知道和虚方法一样就ok了)
public里的构造和析构方法就不多说了,只要知道AllocateHWnd函数和DeallocateHWnd分
别是为了得到一个句柄和释放这个句柄资源.
published的2个属性和一个事件大家肯定清楚,这里不多说.下面主要介绍下面2个函数
WndProc函数处理TTimer的消息循环,此控件只有一个WM_TIMER消息,收到此消息后也只是
运行了Timer动态函数的代码,而Timer就是调用了用户写的OnTimer事件处理代码
procedure TTimer.WndProc(var Msg: TMessage);
begin
with Msg do
if Msg = WM_TIMER then
try
Timer;
except
Application.HandleException(Self);
end
else
Result := DefWindowProc(FWindowHandle, Msg, wParam, lParam);
end;
UpdateTimer函数里用到了2个API函数SetTimer和KillTimer,SetTimer函数共有4个参数,
从MSDN上可以查到分别是句柄,ID值,触发时间间隔及处理函数的指针.SetTimer函数成功
后,如果最后一个参数的函数指针为空,则每隔Interval毫秒的间隔就发送一个WM_TIMER
消息到第一隔参数指定的窗口句柄,第二个参数只是为了当同一个窗口句柄需要多个定时
器的时候而使用,因为TTimer类创建的时候都重新分配了一个HWND,所以这里直接使用了
常数1.当SetTimer最后参数不为空时,Windows会先回调该函数.KillTimer则是销毁指定
的定时器.
procedure TTimer.UpdateTimer;
begin
KillTimer(FWindowHandle, 1);
if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then
if SetTimer(FWindowHandle, 1, FInterval, nil) = 0 then
raise EOutOfResources.Create(SNoTimers);
end;
从代码中我们可以看到无论是修改TTimer的哪个属性或事件(其实就2属性1个事件),都会
先KillTimer再SetTimer重新生成一个新的定时器.