Timer Component

(second from left - the clock!)

This provides a simplified way to access the Windows API timer functions SetTimer and KillTimer. The basic approach is to add a timer to a unit, set its Enabled property to False when the module runs and then set Enabled to True in response to some event such as a button press. Different programs will then react in different ways to the Timer OnTimer event.

Methods

Clear

This clears all settings in a timer.

Properties

Enabled

Whether the timer is enabled.

Interval

Time in milliseconds between calling of the OnTimer event. The OnTimer event is called after the passing of interval milliseconds.

Events

There is only one event for the Timer, OnTimer. This is triggered when the timer interval has elapsed so that the program can respond in the way the user requires.

Examples

Putting The Date On a Form

Add a label to a form for the display of the date and/or time.

Add a timer control from the System palette. Set the timer interval to the desired value (measured in milliseconds so 1000=1 second). Double click the timer icon to open the Timer1Timer procedure. Add these lines:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
 label1.caption:=DateTimeToStr(Now);
end;

Double click the form and set the time when the form is created:

procedure TForm1.FormCreate(Sender: TObject);
begin
 label1.caption:=DateTimeToStr(Now);
end;

The Timer performs an interrupt each time the specified interval elapses.

Traffic Lights

In this example we simulate a sequence of traffic lights. To begin with we can define a red light (placed on a panel for easier manipulation later).

We draw a circle for the red light and add a timer so we can activate the colour when we need it:

procedure TTrafficLights.FormCreate(Sender: TObject);
begin
 RedTimer1.Enabled:=false;
end;

We use a button to start the lights:

procedure TTrafficLights.Button1Click(Sender: TObject);
begin
 RedTimer1.Enabled:=true;
 Red.brush.Color:=clRed;
end;

The interval for the lights can be set to whatever we wish, for example 1 second (1,000 milliseconds), 5 seconds (5,000 milliseconds), etc.

We can now add a second light, amber (or orange or yellow):

procedure TTrafficLights.FormCreate(Sender: TObject);
begin
 RedTimer1.Enabled:=false;
 AmberTimer1.Enabled:=false;
end;

When the RedTimer times out we move to the procedure that runs when the OnTimer event occurs

procedure TTrafficLights.RedTimer1Timer(Sender: TObject);
begin
 RedTimer1.Enabled:=false;
 AmberTimer1.enabled:=true;
 Amber.Brush.Color:=clYellow;
end;

This turns off the RedTimer, activates the AmberTimer and sets the amber circle to yellow (note that the red circle is not yet switched to white).

Adding a green circle and a GreenTimer we have:

procedure TTrafficLights.FormCreate(Sender: TObject);
begin
 RedTimer1.Enabled:=false;
 AmberTimer1.Enabled:=false;
 GreenTimer1.Enabled:=false;
end;

On completion of the AmberTimer interval we move to the procedure that runs when its OnTimer event occurs:

procedure TTrafficLights.AmberTimer1Timer(Sender: TObject);
begin
 AmberTimer1.Enabled:=false;
 Red.brush.Color:=clWhite;
 Amber.brush.Color:=clWhite;
 GreenTimer1.enabled:=true;
 Green.Brush.Color:=clGreen;
end;

This disables the AmberTimer and sets the colour of the red and amber lights to white. It then enbales the GreenTimer and sets the green light to green.

We can imagine two basic situations for traffic lights, one with a pedestrian crossing and one without. Where there is no pedestrian crossing, with a button and separate pedestrian lights, as at a crossroads, the traffic lights will change in the sequence:

  1. Red
  2. Red-Amber
  3. Green
  4. Amber
  5. Red

So far we have got to step 3. When the lights for one road have turned from green to amber and red, to stop the traffic, the lights for the other road can turn from red to red-amber and then to green. Traffic engineers need to build in a period when the lights are all red so that any car going through on amber or red will not crash into a car coming the other way on green (it does happen: in some countries you never stop at a red light!) .

For Step 4 in the sequence we look for the GreenTimer event:

procedure TTrafficLights.GreenTimer1Timer(Sender: TObject);
begin
 GreenTimer1.Enabled:=false;
 Green.brush.Color:=clWhite;
 Amber.brush.Color:=clYellow;
 AmberTimer2.enabled:=true;
end;

We now move to a second timer for the Amber light:

procedure TTrafficLights.AmberTimer2Timer(Sender: TObject);
begin
 AmberTimer2.Enabled:=false;
 Amber.Brush.color:=clWhite;
 RedTimer1.Enabled:=true;
 Red.Brush.color:=clRed;
end;

This is different to the first AmberTimer because it ends by activating the RedTimer. From this point the sequence starts all over again. We can imagine a situation where we build a second set of lights controlling traffic coming along another road and manipulating these lights at the same time as the ones we have already covered. It would be easy if we could simply switch one set of lights in one direction (steps 1-3) at the same time as we switch the other set in the other direction (steps 4-5), but this would leave no overlap in the red lights. To achieve the correct sequence we need to extend the sequence of light combinations:

  1. Red - Red
  2. Red+Amber - Red
  3. Green - Red
  4. Amber - Red
  5. Red - Red
  6. Red - Red+Amber
  7. Red - Green
  8. Red - Amber
  9. Red - Red

For a crossroads the north-south lights are in plain text while the east-west lights are in italics. Only when the north-south lights are red can the east-west lights begin their sequence to red+amber and green. For this sequence we need nine timers.

We can complicate things further (and bring them closer to reality) by adding a button for pedestrians so that they can set the traffic lights to red and cross the road in safety. To allow for cars turning left or right the pedestrian button needs to set all lights to red. A typical sequence of lights for a 'pelican' crossing might be:

Red - Red
Red+Amber - Red
Green - Red
If pedestrian button pressed:
  Amber - Red
  Red - Red
  Red - Green
  Red - Red

(Pedestrian lights in italics.)

We add an extra line to the FormCreate procedure to initialise a timer for the Pedestrian lights and also to the AmberTimer1 procedure to turn on the pedestrian Cross button:

procedure TTrafficLights.FormCreate(Sender: TObject);
begin
 ...
 PedestrianTimer1.Enabled:=false;
end;

procedure TTrafficLights.AmberTimer1Timer(Sender: TObject);
begin
 AmberTimer1.Enabled:=false;
 Red.brush.Color:=clWhite;
 Amber.brush.Color:=clWhite;
 Green.Brush.Color:=clGreen;
 CrossButton.Enabled:=true; //enable the pedestrian crossing button
end;

The Cross button is available only when the green traffic light is set to on. When the pedestrian presses the Cross button the traffic is stopped by turning the green traffic light to amber and then enabling the timer for the amber light:

procedure TTrafficLights.CrossButtonClick(Sender: TObject);
begin
 GreenTimer1.Enabled:=false;
 AmberTimer2.enabled:=false;
 Green.Brush.color:=clWhite;
 Amber.Brush.color:=clYellow;
 AmberTimer3.Enabled:=true;
 CrossButton.Enabled:=false;
end;

This disables the GreenTimer, switches the green traffic light to white (off), switches the amber light to yellow (on) and enables an alternative procedure for the amber light, AmberTimer3. When AmberTimer3 is timed out the following procedure is activated:

procedure TTrafficLights.AmberTimer3Timer(Sender: TObject);
begin
 AmberTimer3.Enabled:=false;
 Amber.Brush.color:=clWhite;
 Red.Brush.color:=clRed;
 PedestrianTimer1.Enabled:=true;
 PedestrianRed.Brush.Color:=clWhite;
 PedestrianGreen.Brush.Color:=clGreen;
end;

The next event will be the timing out of the pedestrian lights:

procedure TTrafficLights.PedestrianTimer1Timer(Sender: TObject);
begin
 PedestrianTImer1.Enabled:=false;
 PedestrianGreen.Brush.Color:=clWhite;
 PedestrianRed.Brush.Color:=clRed;
 RedTimer1.Enabled:=true;
end;

After this the sequence returns to the beginning with all lights set to red and RedTimer1 enabled. Here is a sample display with the North-South lights at Red+Amber:

A crossroads with four pedestrian crossings (which might be broken into two parts each) would be more complicated still.

As well as changing colour you should see how these simple techniques might be used to move objects around the screen, producing a simple animation, even a rudimentary game.

Scanning a Keyboard

In the first example an on-line keyboard is created (with just 3 keys at this stage). When the Start button is pressed the keys are scanned in sequence and, as the focus passes from one to the next, the user can either click the key to get the character in the output box, or press the Enter key. 

The following code is run when the form is activated:

procedure TForm1.FormActivate(Sender: TObject);
begin
  Timer1.Enabled:=false;
  display_string:='';
end;

This disables the timer and sets the display string to empty.

When the start button is clicked the timer is enabled and the first letter button receives the focus:

procedure TForm1.Button1Click(Sender: TObject);
begin
  ButtonA.SetFocus;
  Timer1.Enabled:=true;
end;

As each period of the timer finishes the Timer event handler proceeds as follows:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if ButtonA.Focused then ButtonB.SetFocus
  else
    if ButtonB.Focused then ButtonC.SetFocus
    else
      if ButtonC.Focused then ButtonA.SetFocus;
  Edit3.Text:=display_string;
end;

Once the timer is enabled it is activated after interval milliseconds have elapsed. The code here simply checks to see which button is active and advances the focus to the next one, at the same time displaying the current status of the string.

Here the user has clicked the keys a few times to generate a string. Each button has its own event which adds the character associated with it to the display string.

This could form the basis of an on-screen keyboard for use by someone with a physical impairment or disability, especially if linked to an alternative source of input such as a push-switch or blow-switch.

An  Alarm Timer

Two procedures are declared in the Public section of the class definition for the form:

type
  ...
   { Private declarations }
  public
  { Public declarations }
    AlarmTime: TDateTime;
    procedure SetAlarm(Sender: TObject);
end;

When the form is activated the current time is displayed and the timer enabled property is set to false.

procedure TForm1.FormActivate(Sender: TObject);
begin
  Edit1.Text:=DateTimeToStr(Now);
  Timer1.Enabled:=false;
end;

When the Set Alarm button is clicked the SetAlarm procedure is called with a reference to the current object (self):

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetAlarm(self);
end;

This calls the SetAlarm procedure with the self parameter (a reference to subject of the method/procedure call).

The SetAlarm procedure is as follows:

procedure TForm1.SetAlarm(Sender: TObject);
var AlarmStr:string;
begin
  edit1.Text:=DateTimeToStr(Now);
  AlarmStr:=DateTimeToStr(Now);
  if InputQuery('Set Alarm','When do you want the alarm to go off?',AlarmStr) then
    begin
      Edit2.Text:=AlarmStr;
      AlarmTime:=StrToDateTime(AlarmStr);
      Timer1.Enabled:=true;
    end;
end;


This prompts the user for an input and sets the AlarmTime variable to the time entered. The following procedure is for the Timer1 icon:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Edit1.Text:=DateTimeToStr(Now);
  if AlarmTime <= Now then
    edit3.Text:='Finished'
  else 
    edit3.Text:=TimeToStr(AlarmTime - Now);
end;

The Clear Timer button runs this code:

procedure TForm1.Button2Click(Sender: TObject);
begin
  Timer1.Enabled:=false;
  Edit1.Text:=DateTimeToStr(Now);
  Edit2.Text:='';
  Edit3.Text:='';
end;

In this case the Time Entered has been set to 24 hours after the current time.

Back to Tutorial

Back to Palette List