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;
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
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 :-)