home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d6 / RX275D6.ZIP / Units / TIMERLST.PAS < prev    next >
Pascal/Delphi Source File  |  1999-10-12  |  16KB  |  594 lines

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