Cykliczne wykonywanie kodu

Adam Boduch

Poniższy kod pozwala na cykliczne wywoływanie danego kodu w zależności od ustawień. Nie jest to typowy algorytm lecz rozwiązanie pewnego nurtującego wielu ludzi problemu. Kod ten pobiera aktualną datę i czas
z systemu, a następnie rozdziela go na poszczególne wartości - sekundy, minuty, milisekundy, godziny tak, aby można było kontrolować zachowanie programu. Np. chciałbyś, aby jakiś kod wykonywał się co pół godziny, co godzinę lub co minutę. Dzięki poniższej klasie będzie to proste. Wykorzystamy do tego celu wątki.

Ważne czynności wykonywane więc będą w osobnej klasie, która zadeklarowana została w module ClockUnit. Na początek wygląd samej klasy:

type
  TTimeEvent = procedure of object;  // nowy typ 
{
 Jak widzisz kod tej klasy to watek. Zasada dzialania jest prosta - metoda
 GetTime pobiera czas i odpowiednio go rozdziela pomiedzy rozne zmienne.
 Nastepnie zmienne sa porownywane i generowane sa odpowiednie zdarzenia.
}
  TClock = class(TThread)
  private
    FHour, FMinute, FSecond, FMilSec : Word; // zmienne zawieraja godzine, minuty itp.
    FOnHour, FOnMinute, FOnSecond, FOnMilisecond, FOnHalf : TTimeEvent; // zdarzenia
    FDateTime : TDateTime; // pobrany czas
    procedure GetTime;  // pobiera aktualny czas
  protected
    procedure Execute; override;
  published
    property Milisecond : Word read FMilSec; // wlasciwosc zawiera aktualny czas ( w milisekundach )
    property Second : Word read FSecond;  // sekundy
    property Minute : Word read FMinute; // minuty
    property Hour : Word read FHour; // godziny
    property DateTime : TDateTime read FDateTime; // aktualny czas
  { Zdarzenia }
    property OnMilisecond : TTimeEvent read FOnMilisecond write FOnMilisecond;
    property OnSecond : TTimeEvent read FOnSecond write FOnSecond;
    property OnMinute : TTimeEvent read FOnMinute write FOnMinute;
    property OnHour : TTimeEvent read FOnHour write FOnHour;
    property OnHalf : TTimeEvent read FOnHalf write FOnHalf;
  end;

Klasa ta może wyglądać dość przerażająco, ale w sumie kodu będzie dość mało. Na co warto
zwrócić uwagę to to, że zadeklarowany został nowy typ proceduralny TTimeEvent . Najwięcej właściwości jest w sekcji Published gdyż zawarte są tam zdarzenia. Jeżeli chodzi o sekcje Implementation modułu to

procedure TClock.Execute;
begin
  FreeOnTerminate := TRUE; // zwolnij po zakonczeniu
  //kontynuuj az do zakonczenia dzialania programu
  while not (Application.Terminated) or (Terminated) do 
  begin
    Sleep(1000); // czekaj sekunde
    GetTime; // pobierz czas - wywolanie procedury
    OnSecond; // wywolanie zdarzenia występującego co sekunde
    if (FMinute =  0) and (FSecond = 0) then OnHour; // generowanie zdarzenia godzinnego
    if (FMinute = 30) and (FSecond = 0) then OnHalf; // wystepuje co pol godziny
    if (FSecond = 0) then OnMinute;  // wystepuje co minute
  end;
end;

procedure TClock.GetTime;
begin
  FDateTime := Now;  // pobierz aktualny czas
  DecodeTime(FDateTime, FHour, FMinute, FSecond, fMilSec); // rozdziel go na poszczegolne zmienne
end;

Druga metoda pobiera aktualną datę i czas, a następnie rozdziela czas pomiędzy różne zmienne zawierające wartości godziny, minut, sekund oraz milisekund.

Druga metoda - Execute związana jest z programowaniem wątków. Jest on kontynuowany do czasu zakończenia programu. Odczekuje sekundę, a następnie wywołuje metodę GetTime. W końcu porównuje wartości zmiennych (pól klasy). Jeżeli zmienna FMinute ma wartość 0 to znaczy, że zmieniła się godzina - generowane jest wówczas zdarzenie OnHout. Itd...

Teraz w swoim programie musisz stworzyć procedury zdarzeniowe, które będą obsługiwać zdarzenia, które występują co godzinę, sekundę, minutę i o wpół do danej godziny.

Oto te metody:

procedure TMainFormU.FHalf;
begin
{ W przypadku wystapenia zdarzenia wyswietla tekst na pasku stanu }
  HelpBar.SimpleText := Format('Jest w pół do: %d', [Clock.Hour]);
end;

procedure TMainFormU.FHour;
begin
{ Wyswietl co godzine: }
  HelpBar.SimpleText := Format('Mineła godzina: %d', [Clock.Hour]);
end;

procedure TMainFormU.FMinute;
begin
{ Wyswietl co minute }
  HelpBar.SimpleText := Format('Mineła już kolejna: %d minuta', [Clock.Minute]);
end;

procedure TMainFormU.FSecond;
begin
{ Wyswietl co sekunde - pobiera czas z wlaciwosci DateTime }
  pnlTime.Caption := TimeToStr(Clock.DateTime);
end;

Nie robią one nic specjalnego - po prostu na pasku stanu (komponencie) StatusBar wyświetlają odpowiednie informacje.

Natomiast w metodzie OnCreate programu musisz umieścić następujące instrukcje:

procedure TMainFormU.FormCreate(Sender: TObject);
begin
  Clock := TClock.Create(False);
{ Przypisanie procedur zdarzeniowych }
  Clock.OnSecond := FSecond;
  Clock.OnMinute := FMinute;
  Clock.OnHour := FHour;
  Clock.OnHalf := FHalf;
end;

3 komentarzy

ok, bede pamietac, nie wiedzialem

taka drobna uwaga - art jest własnością serwisu a nie autora (o ile nie zaznaczy inaczej) więc jeśli widzisz, że jest ewidentny błąd to po prostu popraw arta i już

Zle Pan to napisał. Testowalem pod Kylixem, po uruchomieniu programu oczywiscie zwiech, n a konsoli wyskoczyły błedy "Xlib: unexpected async reply (sequence 0x730)!"

Zmieniłem całość zgodnie z zaleceniem jakie jest generowane przy automatycznym tworzeniu watku. (synchronize). Wkleje ponizej pełny kod (naglowki prosze zmienic poniewaz te sa pod linuxa np QForms) . Unit1.pas - Form1 (glowna forma), watek TClock - unit2.pas

unit2.pas:
[code=delphi]
unit Unit2;

interface

uses
SysUtils, Types, Classes, Variants, QTypes, QGraphics, QControls, QForms,
QDialogs, QStdCtrls;

type
TClock = class(TThread)
private
FHour, FMinute, FSecond, FMilSec : Word; // zmienne zawieraja godzine, minuty itp.
FDateTime : TDateTime; // pobrany czas
procedure GetTime; // pobiera aktualny czas

protected
procedure Execute; override;

published

property Milisecond : Word read FMilSec; // wlasciwosc zawiera aktualny czas ( w milisekundach )
property Second : Word read FSecond;  // sekundy
property Minute : Word read FMinute; // minuty
property Hour : Word read FHour; // godziny
property DateTime : TDateTime read FDateTime; // aktualny czas

end;

implementation

uses unit1;

procedure TClock.Execute;
begin
FreeOnTerminate := TRUE; // zwolnij po zakonczeniu
//kontynuuj az do zakonczenia dzialania programu
while not (Application.Terminated) or (Terminated) do
begin
Sleep(1000); // czekaj sekunde
GetTime; // pobierz czas - wywolanie procedury
Synchronize(Form1.FSecond); // wywolanie zdarzenia wystpujcego co sekunde
if (FMinute = 0) and (FSecond = 0) then Synchronize(Form1.FHour); // generowanie zdarzenia godzinnego
if (FMinute = 30) and (FSecond = 0) then Synchronize(Form1.FHalf); // wystepuje co pol godziny
if (FSecond = 0) then Synchronize(Form1.FMinute); // wystepuje co minute
end;
end;

procedure TClock.GetTime;
begin
FDateTime := Now; // pobierz aktualny czas
DecodeTime(FDateTime, FHour, FMinute, FSecond, fMilSec); // rozdziel go na poszczegolne zmienne
end;

end.
[/code]

unit1.pas:
[code=delphi]
unit Unit1;

interface

uses
SysUtils, Types, Classes, Variants, QTypes, QGraphics, QControls, QForms,
QDialogs, QStdCtrls;

type
TForm1 = class(TForm)
Label_Czas: TLabel;
Label_info: TLabel;
procedure FormCreate(Sender: TObject);
procedure FSecond;
procedure FMinute;
procedure FHour;
procedure FHalf;
private
{ Private declarations }

public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.xfm}

uses
Unit2;

var
Clock : TClock;

procedure TForm1.FormCreate(Sender: TObject);
begin
Clock := TClock.Create(False);
end;

procedure TForm1.FMinute;
begin
{ Wyswietl co minute }
Label_info.Caption :=Format('Minea ju kolejna: %d minuta', [Clock.Minute]);
end;

procedure TForm1.FSecond;
begin
{ Wyswietl co sekunde - pobiera czas z wlaciwosci DateTime }
Label_Czas.Caption := TimeToStr(Clock.DateTime);

end;

procedure TForm1.FHalf;
begin
{ W przypadku wystapenia zdarzenia wyswietla tekst na pasku stanu }
Label_info.Caption := Format('Jest w pó do: %d', [Clock.Hour]);
end;

procedure TForm1.FHour;
begin
{ Wyswietl co godzine: }
Label_info.Caption := Format('Minea godzina: %d', [Clock.Hour]);
end;

end.
[/code]

pozdrawiam
PrzemekCoSiePisNieBoi
www.zbigniewziobro.org :-)