Since you mentioned a semaphore and a countdown timer, I made a small functional example, although using the TTimer, not in the same way as you put it in the question.
First, let's see the traffic light working:
I've done it using Firemonkey, but the basic idea is the same if you use VCL.
I have a form with 3 TCircle
, which will be the lights of the traffic light. A TStopWatch
of the unit Diagnostics
, which is what helps me keep track of elapsed time, and a TTimer
established at a 50ms interval.
The OnTimer event is this:
procedure TForm1.tTiempoTimer(Sender: TObject);
begin
if FStopWatch.ElapsedMilliseconds > FSegundosAEsperar * 1000 then
CambiarDeColor;
ActualizarEtiqueta;
end;
As you can see, this event handler pulls these two methods:
procedure TForm1.CambiarDeColor;
begin
case FColorEncendido of
Verde: EstablecerColor(Amarillo, SegundosAmarillo);
Amarillo: EstablecerColor(Rojo, SegundosRojo);
Rojo: EstablecerColor(Verde, SegundosVerde);
end;
end;
procedure TForm1.ActualizarEtiqueta;
var
FaltaMSec: Int64;
Min, Sec: Word;
begin
FaltaMSec := FSegundosAEsperar * 1000 - FStopWatch.ElapsedMilliseconds + 950;
Sec := (FaltaMSec div 1000) mod 60;
Min := (FaltaMSec div 1000) div 60;
lblTiempo.Text := Format('%.2d:%.2d', [Min, Sec]);
end;
The CambiarDeColor
method has the basic logic of the semaphore operation, and the ActualizarEtiqueta
method of the countdown timer operation. For the operation of the latter, I store in a member of the class the waiting time of the light in progress, and the first line of the method obtains the difference between the time to be expected and the elapsed time, plus a little less than a second, since otherwise the chronometer would show the text '00: 00 'for a whole second before the color change, and it is not the behavior expected by the user.
Finally, the EstablecerColor
method is responsible for adjusting the colors of the semaphore each time a color change occurs, and restarting the FStopWatch
so that the count of the time elapsed from 0 starts again.
procedure TForm1.EstablecerColor(AColor: TColorSemaforo; ASegundos: Integer);
var
cRojo: TAlphaColor;
cAmarillo: TAlphaColor;
cVerde: TAlphaColor;
cEtiqueta: TAlphaColor;
begin
FColorEncendido := AColor;
cRojo := TAlphaColorRec.Indianred;
cAmarillo := TAlphaColorRec.Palegoldenrod;
cVerde := TAlphaColorRec.Darkseagreen;
cEtiqueta := TAlphaColorRec.Silver;
case AColor of
Verde:
begin
cVerde := TAlphaColorRec.Lime;
cEtiqueta := cVerde;
end;
Amarillo:
begin
cAmarillo := TAlphaColorRec.Yellow;
cEtiqueta := cAmarillo;
end;
Rojo:
begin
cRojo := TAlphaColorRec.Red;
cEtiqueta := cRojo;
end;
end;
LuzRoja.Fill.Color := cRojo;
LuzAmarilla.Fill.Color := cAmarillo;
LuzVerde.Fill.Color := cVerde;
lblTiempo.TextSettings.FontColor := cEtiqueta;
FStopWatch.Reset;
FStopWatch.Start;
FSegundosAEsperar := ASegundos;
end;
Finally, the declaration of the class:
type
TForm1 = class(TForm)
LuzRoja: TCircle;
LuzAmarilla: TCircle;
LuzVerde: TCircle;
lblTiempo: TLabel;
tTiempo: TTimer;
procedure tTiempoTimer(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
const
SegundosVerde = 7;
SegundosAmarillo = 3;
SegundosRojo = 10;
type
TColorSemaforo = (Verde, Amarillo, Rojo);
var
FColorEncendido: TColorSemaforo;
FStopWatch: TStopWatch;
FSegundosAEsperar: Integer;
procedure EstablecerColor(AColor: TColorSemaforo; ASegundos: Integer);
procedure CambiarDeColor;
procedure ActualizarEtiqueta;
public
end;
The result is the one you see in the image above, which I made with a screenshot after executing this project.