Odliczanie
Adam Boduch
Ostatnio dostałem list z prośbą napisania programu, który odliczałby czas od
podanej wartości do zera. Przy czym czas musiałbyć zapisany w postaci:
HH:MM:SS. Czyli program wyglądałby jak stoper tyle, że od podanej wartości
czasowej do 0.
Co nam będzie potrzebne? Przede wszystkim komponent Timer. Umieść go na
formularzu i zmień
jego wartość Enabled na False. Wszystko co nam będzie potrzebne to komponent
Timer oraz
polecenia EncodeTime i DecodeTime. Te polecenia służą do rozdzielania
zmiennej czasowej
typu TTime na oddzielne wartości (godziny, minuty, sekundy), a następnie na
podstawie podanych wartości połączenie ich w zmienną typu TTime.
Na formularzu umieść dodatkowo komponent MaskEdit, który będzie dbał o
poprawność
wprowadzanych danych. Czyli użytkownik nie będzie mógł wpisać żadnych liter,
a tylko
cyfry. Ustaw maskę tego komponentu na LongTime.
Dekodowanie czasu na poszczególne "człony" wygląda tak:
BeforeTime := StrToTime(meTime.Text); // pobierz tekst z kontrolki iprzeksztalc go na zmienna TTime
DecodeTime(BeforeTime, wHour, wMin, wSec, wMSec); // rozłącz czas nagodziny, minuty i sekundy
Natomiast kodowanie wartości na zmienną czasową następująco:
{ tak zmodyfikowane wartosci przeksztalc do postaci zmiennej typu TTime iwyswietl
na kontrolce TMaskEdit }
AfterTime := EncodeTime(wHour, wMin, wSec, wMSec);
meTime.Text := TimeToStr(AfterTime);
Zdarzenie OnTimer komponentu Timer występować będzie co 1000 milisekund,
czyli co jedną sekundę. Następować w niej będzie
zmniejszanie wartości wSec (która to oznacza ilość sekund) i ew.
zmniejszenie pozostałych wartości, czyli wMin oraz wHour.
Przy tym trzeba będzie zastosować trochę warunków if aby wszystko było tak
jak trzeba.
Cała procedura OnTimer wygląda tak:
procedure TMainForm.TimerTimer(Sender: TObject);
var
BeforeTime, AfterTime : TTime;
wHour, wMin, wSec, wMSec : Word;
begin
BeforeTime := StrToTime(meTime.Text); // pobierz tekst z kontrolki i przeksztalc go na zmienna TTime
DecodeTime(BeforeTime, wHour, wMin, wSec, wMSec); // rozłącz czas na godziny, minuty i sekundy
Dec(wSec); // zmniejsz liczbe sekund
{ tutaj nastepuje sprawdzenie, czy odliczanie sie zakonczylo. Jezeli liczba godzin
minut i sek rowna sie 0 to nastepuje wylaczenie timera i uruchomienie procedury "Run"
}
if ((wSec = 0) and (wMin = 0) and (wHour = 0)) then
begin
Timer.Enabled := False; // wylacz timer
btnGo.Caption := 'Odliczaj...'; // zmień wartość Caption
Run; // wywolaj procedure
Exit;
end;
if wSec = 0 then // sprawdz, czy liczba sekund nie rowna sie przypadkiem0
begin
wSec := 59; // w takim wypadku zmien te wartosc na 59
{ jezeli liczba godzin oraz liczba minut rowna sie 0 to zmniejsz liczegodzin,
a zmiennej wMin przypisz wartosc 60 }
if ((wHour > 0) and (wMin = 0)) then begin dec(wHour); wMin := 60;end;
{ jezeli liczba minut jest wieksza od 0 to zmniejsz te wartosc o jeden }
if wMin > 0 then dec(wMin);
end;
{ tak zmodyfikowane wartosci przeksztalc do postaci zmiennej typu TTime iwyswietl
na kontrolce TMaskEdit }
AfterTime := EncodeTime(wHour, wMin, wSec, wMSec);
meTime.Text := TimeToStr(AfterTime);
end;
Czyli następuje tutaj sprawdzenie czy przypadkiem odliczanie się nie
zakończyło. Później w przypadku, gdy wartość wSec wyniesie 0 trzeba będzie
sprawdzić parę warunków. Bowiem liczba minut może wynieść 0 - wtedy trzeba
będzie zmniejszyć o jeden
wartość godzin. Także w przypadku, gdy ilość sekund wyniesie 0 to trzeba
będzie ponownie przypisać tej wartości liczbę 59,
a później zmniejszyć o jeden liczbę minut. Itd., itp.
Cały kod źródłowy programu wygląda tak:
(****************************************************************)
(* *)
(* Copyright (c) 2002 by Adam Boduch *)
(* http://4programmers.net *)
(* adam@4programmers.net *)
(* *)
(****************************************************************)
unit MainFrm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Mask;
type
TMainForm = class(TForm)
meTime: TMaskEdit;
Timer: TTimer;
btnGo: TButton;
procedure btnGoClick(Sender: TObject);
procedure TimerTimer(Sender: TObject);
private
procedure Run;
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.Run;
begin
{ wyświetl okienko informacyjne w przypadku skończenia odliczania }
ShowMessage('Skończone');
end;
procedure TMainForm.btnGoClick(Sender: TObject);
begin
{
tutaj nastepuje ew. sprawdzenie, czy Timer jest uruchomiony - jezelitak
to jest mozliwosc zatrzymania jego - w przeciwnym wypadku - nastepujeuruchomienie
}
if not Timer.Enabled then
begin
Timer.Enabled := True;
btnGo.Caption := 'Zatrzymaj...';
end else
begin
Timer.Enabled := False;
btnGo.Caption := 'Odliczaj...';
end;
end;
procedure TMainForm.TimerTimer(Sender: TObject);
var
BeforeTime, AfterTime : TTime;
wHour, wMin, wSec, wMSec : Word;
begin
BeforeTime := StrToTime(meTime.Text); // pobierz tekst z kontrolki iprzeksztalc go na zmienna TTime
DecodeTime(BeforeTime, wHour, wMin, wSec, wMSec); // rozłącz czas nagodziny, minuty i sekundy
Dec(wSec); // zmniejsz liczbe sekund
{ tutaj nastepuje sprawdzenie, czy odliczanie sie zakonczylo. Jezeliliczba godzin
minut i sek rowna sie 0 to nastepuje wylaczenie timera i uruchomienieprocedury "Run"
}
if ((wSec = 0) and (wMin = 0) and (wHour = 0)) then
begin
Timer.Enabled := False; // wylacz timer
btnGo.Caption := 'Odliczaj...'; // zmień wartość Caption
Run; // wywolaj procedure
Exit;
end;
if wSec = 0 then // sprawdz, czy liczba sekund nie rowna sie przypadkiem0
begin
wSec := 59; // w takim wypadku zmien te wartosc na 59
{ jezeli liczba godzin oraz liczba minut rowna sie 0 to zmniejsz liczegodzin,
a zmiennej wMin przypisz wartosc 60 }
if ((wHour > 0) and (wMin = 0)) then begin dec(wHour); wMin := 60;end;
{ jezeli liczba minut jest wieksza od 0 to zmniejsz te wartosc o jeden }
if wMin > 0 then dec(wMin);
end;
{ tak zmodyfikowane wartosci przeksztalc do postaci zmiennej typu TTime iwyswietl
na kontrolce TMaskEdit }
AfterTime := EncodeTime(wHour, wMin, wSec, wMSec);
meTime.Text := TimeToStr(AfterTime);
end;
end.
Cały kod programu możesz ściągnąć tutaj:
W tym programie coś brakuje bo jak się ustawi pełną godzinę lub minutę to wyrzuca błąd. Nie dzieje się to tylko jak się doda przynajmniej jedną sekundę.
Nigdy nie ufaj, ze timer wywola ci metode rowno po sekundzie, co jesli w tym momecie twoj program nie bedzie mial dostepu do procesora (co jest wysoce prawdopodobne) i co jesli to sie powtorzy kilka tysiecy razy? Do takich rzeczy uzywa sie RTC (choc zauwazylem, ze w moim laptopie zegarek potrafi sie presunac az o 10 sek w ciagu dnia! ale to inna historia ;)
Nie jestem pewien, czy dobrze zrozumialem problem, ale wydaje mi sie ze ponizszy kod bedzie robil cos podobnego (opuszczam graficzna otoczke, zeby nie dublowac kodu).
Pozdrawiam, BcbMan.
Link nie dziala. Blad 404???