Timerlst.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:16k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1997 Master-Bank                }
  6. {                                                       }
  7. {*******************************************************}
  8. unit TimerLst;
  9. {$I RX.INC}
  10. interface
  11. uses {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  12.   Messages, Classes;
  13. const
  14.   DefaultInterval = 1000;
  15.   HInvalidEvent = -1;
  16. type
  17.   TAllTimersEvent = procedure(Sender: TObject; Handle: Longint) of object;
  18.   TRxTimerEvent = class;
  19.   TRxTimerList = class(TComponent)
  20.   private
  21.     FEvents: TList;
  22.     FWndHandle: hWnd;
  23.     FActive: Boolean;
  24.     FInterval: Longint;
  25.     FSequence: Longint;
  26.     FStartInterval: Longint;
  27.     FOnFinish: TNotifyEvent;
  28.     FOnTimers: TAllTimersEvent;
  29.     procedure CalculateInterval(StartTicks: Longint);
  30.     function CreateNewEvent: TRxTimerEvent;
  31.     function GetCount: Integer;
  32.     function GetEnabledCount: Integer;
  33.     function ProcessEvents: Boolean;
  34.     procedure RemoveItem(Item: TRxTimerEvent);
  35.     procedure SetActive(Value: Boolean);
  36.     procedure SetEvents(StartTicks: Longint);
  37.     procedure Sort;
  38.     procedure TimerWndProc(var Msg: TMessage);
  39.     procedure UpdateTimer;
  40.   protected
  41. {$IFDEF WIN32}
  42.     procedure GetChildren(Proc: TGetChildProc {$IFDEF RX_D3};
  43.       Root: TComponent {$ENDIF}); override;
  44. {$ELSE}
  45.     procedure WriteComponents(Writer: TWriter); override;
  46. {$ENDIF WIN32}
  47.     procedure DoTimer(Event: TRxTimerEvent); dynamic;
  48.     function NextHandle: Longint; virtual;
  49.   public
  50.     constructor Create(AOwner: TComponent); override;
  51.     destructor Destroy; override;
  52.     function Add(AOnTimer: TNotifyEvent; AInterval: Longint;
  53.       ACycled: Boolean): Longint; virtual;
  54.     function AddItem(Item: TRxTimerEvent): Longint;
  55.     procedure Clear;
  56.     procedure Delete(AHandle: Longint); virtual;
  57.     procedure Activate;
  58.     procedure Deactivate;
  59.     function ItemByHandle(AHandle: Longint): TRxTimerEvent;
  60.     function ItemIndexByHandle(AHandle: Longint): Integer;
  61.     property Count: Integer read GetCount;
  62.     property EnabledCount: Integer read GetEnabledCount;
  63.   published
  64.     property Active: Boolean read FActive write SetActive default False;
  65.     property Events: TList read FEvents;
  66.     property OnFinish: TNotifyEvent read FOnFinish write FOnFinish;
  67.     property OnTimers: TAllTimersEvent read FOnTimers write FOnTimers;
  68.   end;
  69.   TRxTimerEvent = class(TComponent)
  70.   private
  71.     FCycled: Boolean;
  72.     FEnabled: Boolean;
  73.     FExecCount: Integer;
  74.     FHandle: Longint;
  75.     FInterval: Longint;
  76.     FLastExecute: Longint;
  77.     FParentList: TRxTimerList;
  78.     FRepeatCount: Integer;
  79.     FOnTimer: TNotifyEvent;
  80.     function GetAsSeconds: Cardinal;
  81.     procedure SetAsSeconds(Value: Cardinal);
  82.     procedure SetRepeatCount(Value: Integer);
  83.     procedure SetEnabled(Value: Boolean);
  84.     procedure SetInterval(Value: Longint);
  85. {$IFNDEF WIN32}
  86.     procedure SetParentList(Value: TRxTimerList);
  87. {$ENDIF WIN32}
  88.   protected
  89. {$IFDEF WIN32}
  90.     procedure SetParentComponent(Value: TComponent); override;
  91. {$ELSE}
  92.     procedure ReadState(Reader: TReader); override;
  93. {$ENDIF}
  94.   public
  95.     constructor Create(AOwner: TComponent); override;
  96.     destructor Destroy; override;
  97.     function HasParent: Boolean; override;
  98. {$IFDEF WIN32}
  99.     function GetParentComponent: TComponent; override;
  100. {$ENDIF}
  101.     property AsSeconds: Cardinal read GetAsSeconds write SetAsSeconds;
  102.     property Handle: Longint read FHandle;
  103.     property ExecCount: Integer read FExecCount;
  104.     property TimerList: TRxTimerList read FParentList;
  105.   published
  106.     property Cycled: Boolean read FCycled write FCycled default True;
  107.     property RepeatCount: Integer read FRepeatCount write SetRepeatCount default 0;
  108.     property Enabled: Boolean read FEnabled write SetEnabled default True;
  109.     property Interval: Longint read FInterval write SetInterval default DefaultInterval;
  110.     property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
  111.   end;
  112. implementation
  113. uses Consts, Controls, Forms, SysUtils, VCLUtils, MaxMin;
  114. const
  115.   MinInterval = 100; { 0.1 sec }
  116. {$IFDEF RX_D4}
  117.   MaxTimerInterval: Longint = High(Longint);
  118. {$ELSE}
  119.   MaxTimerInterval: Longint = High(Cardinal);
  120. {$ENDIF}
  121. {$IFNDEF WIN32}
  122.   INVALID_HANDLE_VALUE = 0;
  123. {$ENDIF}
  124.   Registered: Boolean = False;
  125. { TRxTimerEvent }
  126. constructor TRxTimerEvent.Create(AOwner: TComponent);
  127. begin
  128.   inherited Create(AOwner);
  129.   FParentList := nil;
  130.   FCycled := True;
  131.   FRepeatCount := 0;
  132.   FEnabled := True;
  133.   FExecCount := 0;
  134.   FInterval := DefaultInterval;
  135.   FLastExecute := GetTickCount;
  136.   FHandle := HInvalidEvent;
  137. end;
  138. destructor TRxTimerEvent.Destroy;
  139. begin
  140.   FOnTimer := nil;
  141.   inherited Destroy;
  142. end;
  143. {$IFNDEF WIN32}
  144. procedure TRxTimerEvent.SetParentList(Value: TRxTimerList);
  145. begin
  146.   if FParentList <> nil then FParentList.RemoveItem(Self);
  147.   if Value <> nil then Value.AddItem(Self);
  148. end;
  149. {$ENDIF}
  150. function TRxTimerEvent.HasParent: Boolean;
  151. begin
  152.   Result := True;
  153. end;
  154. {$IFDEF WIN32}
  155. function TRxTimerEvent.GetParentComponent: TComponent;
  156. begin
  157.   Result := FParentList;
  158. end;
  159. procedure TRxTimerEvent.SetParentComponent(Value: TComponent);
  160. begin
  161.   if FParentList <> nil then FParentList.RemoveItem(Self);
  162.   if (Value <> nil) and (Value is TRxTimerList) then
  163.     TRxTimerList(Value).AddItem(Self);
  164. end;
  165. {$ELSE}
  166. procedure TRxTimerEvent.ReadState(Reader: TReader);
  167. begin
  168.   inherited ReadState(Reader);
  169.   if Reader.Parent is TRxTimerList then
  170.     SetParentList(TRxTimerList(Reader.Parent));
  171. end;
  172. {$ENDIF WIN32}
  173. procedure TRxTimerEvent.SetEnabled(Value: Boolean);
  174. begin
  175.   if Value <> FEnabled then begin
  176.     FEnabled := Value;
  177.     if FEnabled then begin
  178.       FExecCount := 0;
  179.       FLastExecute := GetTickCount;
  180.       if FParentList <> nil then
  181.         with FParentList do begin
  182.           CalculateInterval(GetTickCount);
  183.           UpdateTimer;
  184.         end;
  185.     end;
  186.   end;
  187. end;
  188. procedure TRxTimerEvent.SetInterval(Value: Longint);
  189. begin
  190.   if Value <> FInterval then begin
  191.     FInterval := Value;
  192.     if FParentList <> nil then
  193.       with FParentList do begin
  194.         CalculateInterval(GetTickCount);
  195.         UpdateTimer;
  196.       end;
  197.   end;
  198. end;
  199. procedure TRxTimerEvent.SetRepeatCount(Value: Integer);
  200. begin
  201.   if FRepeatCount <> Value then begin
  202.     Value := Max(Value, Integer(not FCycled));
  203.     if not (csDesigning in ComponentState) then
  204.       if FEnabled and (Value <= FExecCount) then Enabled := False;
  205.     FRepeatCount := Value;
  206.   end;
  207. end;
  208. function TRxTimerEvent.GetAsSeconds: Cardinal;
  209. begin
  210.   Result := Interval div 1000;
  211. end;
  212. procedure TRxTimerEvent.SetAsSeconds(Value: Cardinal);
  213. begin
  214.   Interval := Value * 1000;
  215. end;
  216. { TRxTimerList }
  217. constructor TRxTimerList.Create(AOwner: TComponent);
  218. begin
  219.   inherited Create(AOwner);
  220.   FEvents := TList.Create;
  221.   FWndHandle := INVALID_HANDLE_VALUE;
  222.   FSequence := 0;
  223.   FStartInterval := 0;
  224.   Deactivate;
  225.   if not Registered then begin
  226.     RegisterClasses([TRxTimerEvent]);
  227.     Registered := True;
  228.   end;
  229. end;
  230. destructor TRxTimerList.Destroy;
  231. begin
  232.   OnFinish := nil;
  233.   OnTimers := nil;
  234.   Deactivate;
  235.   Clear;
  236.   FEvents.Free;
  237.   inherited Destroy;
  238. end;
  239. procedure TRxTimerList.Activate;
  240. begin
  241.   Active := True;
  242. end;
  243. procedure TRxTimerList.Deactivate;
  244. begin
  245.   if not (csLoading in ComponentState) then Active := False;
  246. end;
  247. procedure TRxTimerList.SetEvents(StartTicks: Longint);
  248. var
  249.   I: Integer;
  250. begin
  251.   for I := 0 to FEvents.Count - 1 do
  252.     if TRxTimerEvent(FEvents[I]).Enabled then
  253.       TRxTimerEvent(FEvents[I]).FLastExecute := StartTicks;
  254. end;
  255. procedure TRxTimerList.SetActive(Value: Boolean);
  256. var
  257.   StartTicks: Longint;
  258. begin
  259.   if FActive <> Value then begin
  260.     if not (csDesigning in ComponentState) then begin
  261.       if Value then begin
  262.         FWndHandle := AllocateHWnd(TimerWndProc);
  263.         StartTicks := GetTickCount;
  264.         SetEvents(StartTicks);
  265.         CalculateInterval(StartTicks);
  266.         Sort;
  267.         UpdateTimer;
  268.       end
  269.       else begin
  270.         KillTimer(FWndHandle, 1);
  271.         DeallocateHWnd(FWndHandle);
  272.         FWndHandle := INVALID_HANDLE_VALUE;
  273.         if Assigned(FOnFinish) then FOnFinish(Self);
  274.       end;
  275.       FStartInterval := 0;
  276.     end;
  277.     FActive := Value;
  278.   end;
  279. end;
  280. {$IFDEF WIN32}
  281. procedure TRxTimerList.GetChildren(Proc: TGetChildProc {$IFDEF RX_D3};
  282.   Root: TComponent {$ENDIF});
  283. var
  284.   I: Integer;
  285. begin
  286.   inherited GetChildren(Proc {$IFDEF RX_D3}, Root {$ENDIF});
  287.   for I := 0 to FEvents.Count - 1 do
  288.     Proc(TRxTimerEvent(FEvents[I]));
  289. end;
  290. {$ELSE}
  291. procedure TRxTimerList.WriteComponents(Writer: TWriter);
  292. var
  293.   I: Integer;
  294.   Item: TRxTimerEvent;
  295. begin
  296.   inherited WriteComponents(Writer);
  297.   for I := 0 to FEvents.Count - 1 do begin
  298.     Item := TRxTimerEvent(FEvents[I]);
  299.     if Item.Owner = Writer.Root then Writer.WriteComponent(Item);
  300.   end;
  301. end;
  302. {$ENDIF WIN32}
  303. procedure TRxTimerList.Sort;
  304. var
  305.   I: Integer;
  306.   ExitLoop: Boolean;
  307. begin
  308.   if not (csDesigning in ComponentState) then
  309.     repeat
  310.       ExitLoop := True;
  311.       for I := 0 to Count - 2 do begin
  312.         if TRxTimerEvent(FEvents[I]).Interval > TRxTimerEvent(FEvents[I + 1]).Interval then
  313.         begin
  314.           FEvents.Exchange(I, I + 1);
  315.           ExitLoop := False;
  316.         end;
  317.       end;
  318.     until ExitLoop;
  319. end;
  320. function TRxTimerList.NextHandle: Longint;
  321. begin
  322.   Inc(FSequence);
  323.   Result := FSequence;
  324. end;
  325. function TRxTimerList.CreateNewEvent: TRxTimerEvent;
  326. begin
  327.   Result := TRxTimerEvent.Create(Owner);
  328. end;
  329. function TRxTimerList.AddItem(Item: TRxTimerEvent): Longint;
  330. begin
  331.   if FEvents.Add(Item) >= 0 then begin
  332.     Item.FHandle := NextHandle;
  333.     Item.FParentList := Self;
  334.     Result := Item.FHandle;
  335.     CalculateInterval(GetTickCount);
  336.     Sort;
  337.     UpdateTimer;
  338.   end
  339.   else Result := HInvalidEvent; { invalid handle }
  340. end;
  341. { Create a new timer event and returns a handle }
  342. function TRxTimerList.Add(AOnTimer: TNotifyEvent; AInterval: Longint;
  343.   ACycled: Boolean): Longint;
  344. var
  345.   T: TRxTimerEvent;
  346. begin
  347.   T := CreateNewEvent;
  348.   if (FEvents.Add(T) >= 0) then begin
  349.     with T do begin
  350.       OnTimer := AOnTimer;
  351.       FParentList := Self;
  352.       FHandle := NextHandle;
  353.       Interval := AInterval;
  354.       Cycled := ACycled;
  355.       Result := FHandle;
  356.     end;
  357.     CalculateInterval(GetTickCount);
  358.     Sort;
  359.     UpdateTimer;
  360.   end
  361.   else begin
  362.     T.Free;
  363.     Result := HInvalidEvent; { invalid handle }
  364.   end;
  365. end;
  366. function TRxTimerList.ItemIndexByHandle(AHandle: Longint): Integer;
  367. begin
  368.   for Result := 0 to FEvents.Count - 1 do
  369.     if TRxTimerEvent(FEvents[Result]).Handle = AHandle then Exit;
  370.   Result := -1;
  371. end;
  372. function TRxTimerList.ItemByHandle(AHandle: Longint): TRxTimerEvent;
  373. var
  374.   I: Integer;
  375. begin
  376.   I := ItemIndexByHandle(AHandle);
  377.   if I >= 0 then Result := TRxTimerEvent(FEvents[I])
  378.   else Result := nil;
  379. end;
  380. procedure TRxTimerList.Delete(AHandle: Longint);
  381. var
  382.   I: Integer;
  383.   Item: TRxTimerEvent;
  384. begin
  385.   I := ItemIndexByHandle(AHandle);
  386.   if I >= 0 then begin
  387.     Item := TRxTimerEvent(FEvents[I]);
  388.     RemoveItem(Item);
  389.     if not (csDestroying in Item.ComponentState) then Item.Free;
  390.     if Active then begin
  391.       CalculateInterval(GetTickCount);
  392.       UpdateTimer;
  393.     end;
  394.   end;
  395. end;
  396. function TRxTimerList.GetCount: Integer;
  397. begin
  398.   Result := FEvents.Count;
  399. end;
  400. function TRxTimerList.GetEnabledCount: Integer;
  401. var
  402.   I: Integer;
  403. begin
  404.   Result := 0;
  405.   for I := 0 to Count - 1 do
  406.     if TRxTimerEvent(FEvents[I]).Enabled then Inc(Result);
  407. end;
  408. procedure TRxTimerList.RemoveItem(Item: TRxTimerEvent);
  409. begin
  410.   FEvents.Remove(Item);
  411.   Item.FParentList := nil;
  412. end;
  413. procedure TRxTimerList.Clear;
  414. var
  415.   I: Integer;
  416.   Item: TRxTimerEvent;
  417. begin
  418.   for I := FEvents.Count - 1 downto 0 do begin
  419.     Item := TRxTimerEvent(FEvents[I]);
  420.     RemoveItem(Item);
  421.     if not (csDestroying in Item.ComponentState) then Item.Free;
  422.   end;
  423. end;
  424. procedure TRxTimerList.DoTimer(Event: TRxTimerEvent);
  425. begin
  426.   with Event do 
  427.     if Assigned(FOnTimer) then FOnTimer(Event);
  428.   if Assigned(FOnTimers) then FOnTimers(Self, Event.Handle);
  429. end;
  430. function TRxTimerList.ProcessEvents: Boolean;
  431. var
  432.   I: Integer;
  433.   Item: TRxTimerEvent;
  434.   StartTicks: Longint;
  435. begin
  436.   Result := False;
  437.   if not (csDesigning in ComponentState) then begin
  438.     StartTicks := GetTickCount;
  439.     for I := Count - 1 downto 0 do begin
  440.       Item := TRxTimerEvent(FEvents[I]);
  441.       if (Item <> nil) and Item.Enabled then
  442.         with Item do
  443.           if (StartTicks - FLastExecute) >= (Interval - (MinInterval div 2)) then
  444.           begin
  445.             FLastExecute := StartTicks;
  446.             Inc(FExecCount);
  447.             Enabled := not ((not Cycled) and (FExecCount >= RepeatCount));
  448.             if not Enabled then Result := True;
  449.             DoTimer(Item);
  450.           end;
  451.     end;
  452.   end;
  453. end;
  454. procedure TRxTimerList.TimerWndProc(var Msg: TMessage);
  455. begin
  456.   if not (csDesigning in ComponentState) then begin
  457.     with Msg do
  458.       if Msg = WM_TIMER then
  459.         try
  460.           if (not (csDesigning in ComponentState)) and
  461.             (FStartInterval = 0) and Active then 
  462.           begin
  463.             if ProcessEvents then begin
  464.               if EnabledCount = 0 then Deactivate
  465.               else begin
  466.                 CalculateInterval(GetTickCount);
  467.                 UpdateTimer;
  468.               end;
  469.             end;
  470.           end else
  471.             UpdateTimer;
  472.         except
  473.           Application.HandleException(Self);
  474.         end
  475.       else Result := DefWindowProc(FWndHandle, Msg, wParam, lParam);
  476.   end;
  477. end;
  478. procedure TRxTimerList.CalculateInterval(StartTicks: Longint);
  479. var
  480.   I: Integer;
  481.   ExitLoop: Boolean;
  482. begin
  483.   if not (csDesigning in ComponentState) then begin
  484.     if Count = 0 then FInterval := 0
  485.     else begin
  486.       FStartInterval := 0;
  487.       FInterval := MaxLongInt;
  488.       for I := 0 to Count - 1 do
  489.         with TRxTimerEvent(FEvents[I]) do
  490.           if Enabled and (Interval > 0) then begin
  491.             if Interval < Self.FInterval then Self.FInterval := Interval;
  492.             if Self.FInterval > (Interval - (StartTicks - FLastExecute)) then
  493.               Self.FInterval := (Interval - (StartTicks - FLastExecute));
  494.           end;
  495.       if FInterval < MinInterval then FInterval := MinInterval;
  496.       if FInterval = MaxLongint then FInterval := 0
  497.       else begin
  498.         repeat
  499.           ExitLoop := True;
  500.           for I := 0 to Count - 1 do
  501.             with TRxTimerEvent(FEvents[I]) do
  502.               if (Interval mod Self.FInterval) <> 0 then begin
  503.                 Dec(Self.FInterval, Interval mod Self.FInterval);
  504.                 ExitLoop := False;
  505.                 Break;
  506.               end;
  507.         until ExitLoop or (FInterval <= MinInterval);
  508.         if FInterval < MinInterval then FInterval := MinInterval;
  509.       end;
  510.     end;
  511.   end;
  512. end;
  513. procedure TRxTimerList.UpdateTimer;
  514. var
  515.   FTimerInterval: Cardinal;
  516. begin
  517.   if not (csDesigning in ComponentState) then begin
  518.     if FInterval <= MaxTimerInterval then FTimerInterval := FInterval
  519.     else
  520.       if (FInterval - FStartInterval) <= MaxTimerInterval then begin
  521.         FTimerInterval := Cardinal(FInterval - FStartInterval);
  522.         FStartInterval := 0;
  523.       end
  524.       else begin
  525.         FTimerInterval := MaxTimerInterval;
  526.         FStartInterval := FStartInterval + MaxTimerInterval;
  527.       end;
  528.     if not (csDesigning in ComponentState) and (FWndHandle <> INVALID_HANDLE_VALUE) then
  529.     begin
  530.       KillTimer(FWndHandle, 1);
  531.       if EnabledCount = 0 then Deactivate
  532.       else if FInterval > 0 then
  533.         if SetTimer(FWndHandle, 1, FTimerInterval, nil) = 0 then begin
  534.           Deactivate;
  535.           raise EOutOfResources.Create(ResStr(SNoTimers));
  536.         end;
  537.     end;
  538.   end;
  539. end;
  540. end.