TTimer内部工作原理

如果使用传统的SDK开发方式,那么,创建和销毁一个定时器有两个API可以使用:
UINT_PTR SetTimer(
  HWND hWnd,              // handle to window, 用来接收WM_TIMER消息的窗体句柄
  UINT_PTR nIDEvent,      // timer identifier, 定时器的ID
  UINT uElapse,           // time-out value, 定时器的超时值
  TIMERPROC lpTimerFunc   // timer procedure,定时器的处理函数
);

BOOL KillTimer(
  HWND hWnd,          // handle to window,窗体句柄
  UINT_PTR uIDEvent   // timer identifier,定时器的标示
);

       但是,这种方式的定时并不能达到很精确的定时。因为当有到达了设置的时间时,windows仅仅是将一条WM_TIMER消息放入应用程序的消息队列,如果应用程序没有及时的处理,定时将可能更长。需要注意的是:WM_TIMER消息在应用程序的队列中不会同时出现两次,如果上次的WM_TIMER没有被处理,windows会将其合并成一条新的消息。

       再看看Delphi中TTimer组件的继承关系:
      TObject
       |
       |-- TPersist
         |
         |-- TComponent
           |
           |-- TTimer

   进入TTimer的实现单元,我们可以看到,在TTimer中,有一个窗体句柄:FWindowHandle: HWND;
   在TTimer的Create时:
       FWindowHandle := Classes.AllocateHWnd(WndProc);
    AllocateHWnd过程创建了一个类名为TPutilWindow的窗口:

  UtilWindowClass: TWndClass = (
    style: 0;
    lpfnWndProc: @DefWindowProc;
    cbClsExtra: 0;
    cbWndExtra: 0;
    hInstance: 0;
    hIcon: 0;
    hCursor: 0;
    hbrBackground: 0;
    lpszMenuName: nil;
    lpszClassName: 'TPUtilWindow');

  Result := CreateWindowEx(WS_EX_TOOLWINDOW, UtilWindowClass.lpszClassName,
                            '', WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil);
然后设置窗体过程为WndProc.
     使用Spy++察看,果然可以看到一个大小为0的窗体。不仅仅在TTimer中使用了该类窗体,而且,所有的弹出菜单(TPopupMenu)的管理窗体都是TPutilWindow。

再看看TTimer的窗口回调函数:WndProc中只处理了WM_TIMER:
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;

Timer为动态方法(dynamic):
procedure TTimer.Timer;
begin
  //如果用户自定义了FOnTimer事件,则调用该事件
  if Assigned(FOnTimer) then FOnTimer(Self);
end;

在设置Interval的中,调用UpdateTimer:
该方法调用Windows API SetTimer设置一个定时器:
procedure TTimer.UpdateTimer;
begin
  //如果已经存在,则销毁之前的timer
  KillTimer(FWindowHandle, 1);
  //重新设置Timer
  if (FInterval <> 0) and FEnabled and Assigned(FOnTimer) then
    if SetTimer(FWindowHandle, 1, FInterval, nil) = 0 then
      raise EOutOfResources.Create(SNoTimers);
end;

这时我们了解了定时器的工作原理,系统首先创造了一个非可以视化的窗口,并定时向这个窗口发送WM_TIMER消息,而我们一直在定时器下写的代码(即定时器响应代码)其本质就是一个窗口响应函数!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值