How to make a simple Analog Clock

Digital clocks are cool. But Analog clocks are cooler… when you make them yourself! In this little article we are gonna create an analog clock!

Although digital clocks are the trend these days, analog clocks also hold a very special place in our hearts. Many luxury brands are still selling analog clocks. (If you are interested about digital clocks, see this previous tutorial on making a digital clock.)

No matter how old the design is, there is something special with the analog clocks. The way that it ticks with its hands and everything. It feels simple and friendly. Even in the modern Desktops, we seem to prefer an analog clock widget. That’s another topic. But to get you started I’ll show you a basic analog clock that you can make yourself, by hand. I mean hand-coding. ;)

We will draw the entire interface with code, so it should be super lightweight and a good source of reference too.

Take a look at our final result.

A cross platform analog clock project made with Lazarus (Free Pascal)

This clock is not written by me from scratch. Actually, I have translated it from another java source code written by Abhishek Dubey and converted to Free Pascal to make it available for Lazarus. I am thankful to him for writing the code and making it available for all the learners out there. ;)

Let’s start

Start Lazarus.

Create a new Application Project (Project -> New Project -> Application -> OK).

Set your form’s both Width and Height property to 350. Now add the following variables under the first var clause of the unit (use F12 to switch to & from Code view):

1
2
3
4
5
6
7
8
9
10
var
  ...

  xcenter:integer = 175;
  ycenter:integer = 175;
  lastxs,lastys,lastxm,lastym,lastxh,lastyh:integer;

  clockbg: tbitmap;

  second, minute, hour: integer;

xcenter and ycenter just holds a center point for the hands that we’ll draw later. Some other variables such as lastxs, lastys etc. will be used in the drawing of the hands.

clockbg will hold the background of the clock, that means everything except the hands.

second, minute and hour will hold the parts of time in them to help in the drawing of hands.

Now Draw a TTimer (from System tab) on the form. Set its Interval property to 500 from Object Inspector.

Preparing the Background

Now that we have the basics ready, we can concentrate on putting the details in. First, let’s write the Form’s OnCreate event. Double click on the form and then enter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
procedure TForm1.FormCreate(Sender: TObject);
begin
  clockbg:=tbitmap.Create;
  clockbg.SetSize(350,350);
  with clockbg.Canvas do begin
    // background clearing
    Brush.Color:=RGBToColor(0,90,82);
    FillRect(0,0,350,350);

    // clock area
    Brush.Color:=clBlack;
    Ellipsec(xcenter, ycenter, 150, 150);

    // draw numbers...
    Font.Color:=clRed;
    Brush.Style:=bsClear;
    TextOut(xcenter - 145, ycenter - 5, '9');
    TextOut(xcenter + 135, ycenter - 5, '3');
    TextOut(xcenter - 5, ycenter - 145, '12');
    TextOut(xcenter - 5, ycenter + 130, '6');

    // draw the points in between numbers (hour marks)
    Brush.Style:=bsSolid;
    Brush.Color:=clLime;
    // 1
    EllipseC(
      round(cos((1 * 30) * pi / 180 - pi / 2) * 140 + xcenter),
      round(sin((1 * 30) * pi / 180 - pi / 2) * 140 + ycenter),
      3,3);
    // 2
    EllipseC(
      round(cos((2 * 30) * pi / 180 - pi / 2) * 140 + xcenter),
      round(sin((2 * 30) * pi / 180 - pi / 2) * 140 + ycenter),
      3,3);
    // 4
    EllipseC(
      round(cos((4 * 30) * pi / 180 - pi / 2) * 140 + xcenter),
      round(sin((4 * 30) * pi / 180 - pi / 2) * 140 + ycenter),
      3,3);
    // 5
    EllipseC(
      round(cos((5 * 30) * pi / 180 - pi / 2) * 140 + xcenter),
      round(sin((5 * 30) * pi / 180 - pi / 2) * 140 + ycenter),
      3,3);
    // 7
    EllipseC(
      round(cos((7 * 30) * pi / 180 - pi / 2) * 140 + xcenter),
      round(sin((7 * 30) * pi / 180 - pi / 2) * 140 + ycenter),
      3,3);
    // 8
    EllipseC(
      round(cos((8 * 30) * pi / 180 - pi / 2) * 140 + xcenter),
      round(sin((8 * 30) * pi / 180 - pi / 2) * 140 + ycenter),
      3,3);
    // 10
    EllipseC(
      round(cos((10 * 30) * pi / 180 - pi / 2) * 140 + xcenter),
      round(sin((10 * 30) * pi / 180 - pi / 2) * 140 + ycenter),
      3,3);
    // 11
    EllipseC(
      round(cos((11 * 30) * pi / 180 - pi / 2) * 140 + xcenter),
      round(sin((11 * 30) * pi / 180 - pi / 2) * 140 + ycenter),
      3,3);

  end;
end;

I know it’s a mouthful. First, we create the clockbg TBitmap. Then the usual filling the background from Black to something we prefer. Then we draw a circle for the background of the clock. Then draw numbers 12, 3, 6, 9 on four corners. Then we put some points at the middle of those numbers to fill in the void for the hour marks.

Now as we have Create-d a TBitmap, now we have to free it before the program closes. If we don’t do this, a Memory leak will occur. Now select the form, then go to Object Inspector then Events tab and click on the […] button beside OnDestroy enter this code:

1
2
3
4
5
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if clockbg <> nil then
    FreeAndNil(clockbg);
end;

Through our code, we say that if clockbg has been created, free it from memory. This will usually run when the program closes.

Look Ma, 3 Hands!

Now let’s take care of the 3 hands of the clock. I said earlier that we’ll draw everything with code. So now we’ll write code to draw the hands.

Create a new procedure like the follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
procedure Tform1.DrawHands();
var
  HH,MM,SS,MS: Word;
  xhour, yhour, xminute, yminute, xsecond, ysecond, second, minute, hour: Integer;
  cSecond, cMinute, cHour: TColor;
begin
  // hand colors
  cSecond:=clGreen;
  cMinute:=clBlue;
  cHour:=clRed;

  // get the time
  DecodeTime(Time,HH,MM,SS,MS);
  second:=SS;
  minute:=MM;
  hour:=HH;

  // calculation of (x, y) points where the hands will point to
  xsecond := round(cos(second * pi / 30 - pi / 2) * 120 + xcenter);
  ysecond := round(sin(second * pi / 30 - pi / 2) * 120 + ycenter);
  xminute := round(cos(minute * pi / 30 - pi / 2) * 100 + xcenter);
  yminute := round(sin(minute * pi / 30 - pi / 2) * 100 + ycenter);
  xhour := round(cos((hour * 30 + minute / 2) * pi / 180 - pi / 2) * 80 + xcenter);
  yhour := round(sin((hour * 30 + minute / 2) * pi / 180 - pi / 2) * 80 + ycenter);

  with Canvas do begin

    // drawing the hands
    pen.Color:=cSecond;
    Line(xcenter, ycenter, xsecond, ysecond);
    pen.Color:=cMinute;
    Line(xcenter, ycenter - 1, xminute, yminute);
    Line(xcenter - 1, ycenter, xminute, yminute);
    pen.Color:=cHour;
    Line(xcenter, ycenter - 1, xhour, yhour);
    Line(xcenter - 1, ycenter, xhour, yhour);

  end;

  // some info we can use later...
  lastxs := xsecond;
  lastys := ysecond;
  lastxm := xminute;
  lastym := yminute;
  lastxh := xhour;
  lastyh := yhour;
end;

This procedure can be easily integrated with the Timer code we’ll see later. This is made just to keep it seperate from other code. In other way, it makes it look simpler.

Timing it right

Now double click the Timer1 component and enter:

1
2
3
4
5
6
7
8
9
10
11
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if clockbg <> nil then begin
    Canvas.Draw(0,0,clockbg);

    DrawHands;

    Canvas.TextOut(xcenter - 30, ycenter + 155,
      FormatDateTime('hh:nn:ss am/pm', now));
  end;
end;

This is basically drawing the clockbg, our background for the clock. Then it calls the DrawHands procedure that we made above. At the end, we draw the time in text, just in case anyone needs to read time quickly.

Now hit F9 (or Run -> Run).
Hopefully you will see your new shiny analog clock on your screen.

A cross platform analog clock project made with Lazarus (Free Pascal)

Things to try further

If you try to expand this project to fit in these features, I think it will benefit you-
- Implement an alarm system
- Draggable form
- Set its form shape to match the contents
- Always on top feature
- Tray icon to quit or set alarm

Downloads

You can download the source code for the tutorial project and executable/EXE files from the links below: