Alarm clocks are simple but very useful in our daily lives, right? How about if we make our own?
I work on my computer very often. So it gets easy for me to forget things. I need alarm clocks to remind me of time sensitive things. It might be simple as reminding me to turn of the stove after the water gets boiled, to feed the pet, water plants etc. Alarm clocks are handy for me.
Like me, I think you have many uses for one too. So today let’s see how we can create an alarm clock in Lazarus.
The concept is simple. If we break it down a little bit an alarm app does these 2 basic things:
- Keep a list of alarm times
- Check if it is time to ring any of the listed alarms
Really easy, right?
So let’s get our hands dirty with a simple version of the alarm…
Basic Tutorial
Start Lazarus.
Create a new Program project (Project - New Project - Application - OK).
Create this simple layout:
Just draw a TLabel, a TEdit and a TTimer (from System tab). They’ll probably be named Label1, Edit1 and Timer1 consecutively. Empty Text property of Edit1 and set --:-- --
as Caption of Label1. Optionally, set Caption property of Form1 to something like “Simple Alarm“. You can also set Project - Project Options - Project Options - Application Settings - Title to Simple Alarm.
Then draw as many TLabels as you want to indicate what element does which. Let them take any name that comes in automatically. In this case two TLabels for “Time now:” and “Alarm time:” are what you’d want to create.
Now double click Timer1 and enter:
1 | procedure TForm1.Timer1Timer(Sender: TObject); |
Now press F9 (or Run - Run) and input a time for your alarm. Be cautious to follow the exact format (HH-MM am/pm). e.g. “08:45 pm”. Then wait.
It should show a message when it hits the time you entered. After you click OK the program will close itself.
It is as simple as that.
But it would be nice if we could have multiple alarms and inputs could be little easier. That’s why we’ll be making an advanced version of an alarm clock next…
Tutorial
Start Lazarus.
Create a new Application project (Project - New Project - Application - OK).
Draw TLabel, TListBox, TBitBtn (from Additional tab), TTrayIcon (from Additional tab), TTimer (from System tab) components like the screenshot below:
Set the Name
property of the TListBox to lstAlarms
, one TBitButton to btnAdd
and another to btnRemove
. Set Name
of the second TLabel to lblTime
and the third one to lblDate
.
Set Caption
property of TLabels and TBitBtns according to screenshot. Set AutoSize
property to False
and Alignment
to taCenter
for TLabels, then resize them to same size. This is so that the TLabels stay center.
Set MultiSelect
property of lstAlarms to True
to allow selecting multiple items and remove them at once. Set Font -> Size
property of lblTime to 24
. Set Interval
property of Timer1
to 5000
. Set BalloonHint
to Alarm
and Visible
to True
for TrayIcon1
.
Optionally, you can set the Glyph
property of TBitBtns and Icon
property of TTrayIcon. I found CC0 licensed icons from Aiconica and resized to 16px x 16px size (convert input.png -background transparent -resize 16x16 output.png
or ffmpeg -i input.png -pix_fmt rgba -s 16x16 output.png
) and used them. The files are included in the images
directory in the project source code. But you can use other ones as you wish.
Double click Timer1
and enter:
1 | procedure TForm1.Timer1Timer(Sender: TObject); |
The above is the lifeblood of this project. It shows the time, date and most importantly rings the alarm when the time is detected to be alarm trigger time.
Switch to Form View (F12) and double click the form and enter:
1 | procedure TForm1.FormCreate(Sender: TObject); |
The LoadFromFile
command will load the file alarmlist.dat
into lstAlarms
. You can use '/'
instead of DirectorySeparator
. But this is the proper solution because it changes according to platform (e.g. becomes \
on Windows and /
on Linux distros or Unix).
Timer1Timer(Sender);
just calls the Timer1’s OnTimer procedure. This is so that the time display gets updated on launch of our app.
Now on Object Inspector, go to Events and click on […] button beside OnClose and enter:
1 | procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction); |
This is to save the alarms users created to alarmlist.dat
file so that the app can load it when it launches next time.
Click […] button next to OnWindowStateChange and enter:
1 | procedure TForm1.FormWindowStateChange(Sender: TObject); |
This gives you a nice feature that when you minimize the form it hides itself and gets out of your workflow. We have a TTrayIcon to show a little tray icon while it is minimized. Now we want to make the form visible again when the form is unminimized. So, switch to Form view (F12), double click TrayIcon1 and enter:
1 | procedure TForm1.TrayIcon1Click(Sender: TObject); |
Now we’ll create our second form for setting alarms. Go to File - New Form. We had Unit1 for Form1 before. After this, a new form will be created named Form2 and with it a new unit file called Unit2. A little tip. You can click Project - Forms (Shift+F12) to switch between forms if other ways of navigating between forms is not working for you. You can then use F12 to switch to code view for that form.
Now find the implementation
clause on Unit1 (you should find a tab on source editor, or if not, Ctrl+F12, double click Form1, F12) and make it look something like this:
1 | implementation |
Now we will be able to use Form2’s components in our code in Form1. With that out of the way let’s create components on Form2. Here is a screenshot of the components for Form2:
Create 1 TEdit, 3 TListBoxes, 1 TLabel and 2 TBitBtns. Set Name
property of the TEdit to edtHint
; TListBoxes to lstHour
, lstMinute
and lstampm
; TLabel to lblTimeHint
, 2 TBitBtns to btnOK
and btnCancel
. Add other TLabels as needed and change Caption
properties to make your form look similar to the above screenshot.
Select lstHour and set it’s Items property to:
1 | 01 |
Select lstMinute and set it’s Items property to:
1 | 01 |
Select lstampm and set it’s Items property to:
1 | am |
Select the form (Form2), go to Object Inspector - Events and click […] beside OnShow and enter:
1 | procedure TForm2.FormShow(Sender: TObject); |
This basically prepares the form for the user. Don’t you hate it when alarm apps just choose the first hour, minute etc. in the input? So we select the current hour, minute etc. so that user can easily adjust from there. We also empty the hint input.
We’re using FormatDateTime()
to create a timestamp string of current time with |
in middle of different parts. That’s on purpose. We use that |
(pipe character) to split the string into different elements. We then use these elements for setting selection of each element to appropriate input. StrToInt( parts[0] ) - 1
is just a clever way to convert the current hour value to list index number. Index numbers are zero based, so we subtract 1 from hour value. StrToInt( parts[1] ) - 1
is similar but just for the minute.
Pay attention that we’re using the OnShow
event instead of OnCreate
(which is created by double clicking the form), because OnCreate
event runs on project startup. But OnShow
runs everytime we show the form, meaning everytime the user will click the Add button. If we ran the above commands on OnCreate
the hint would just empty on project startup and everytime user clicks add it would show the last input. By using OnShow
we’re emptying that every time the Form2.Show
is run. Same with time inputs. We update the time selection every time the form is shown.
Now we look to update the time hint label when the user selects a time.
Switch to form view (F12) and select lstHour, go to Object Inspector - Events and click […] beside OnSelectionChange and enter:
1 | procedure TForm2.lstHourSelectionChange(Sender: TObject; User: boolean); |
Now select lstMinute and lstampm and enter lstHourSelectionChange
in the input beside OnSelectionChange.
We got most of the functionality done for Form2. We just have the OK and Cancel buttons to cover. That’s easy. Just double click btnOK and enter:
1 | procedure TForm2.btnOKClick(Sender: TObject); |
Then double click btnCancel and enter:
1 | procedure TForm2.btnCancelClick(Sender: TObject); |
When we show Form2 from Form1 and when user clicks either OK or Cancel, we need a way to know from Form1 which button the user clicked. These are just a way of sending that information to Form1. Which will be clear in a minute…
Switch to Form1‘s form view (Shift+F12), double click btnAdd and enter:
1 | procedure TForm1.btnAddClick(Sender: TObject); |
So basically this is checking if the user clicked the OK button and adding the alarm if so.
Now run the project (Run - Run or F9).
Click Add to create alarms.
Play around to your heart’s content!
If you want to play a sound when your alarms ring, you can try this or any of the solutions that work for you.
Ref:
- Date and time formatting reference: https://www.freepascal.org/docs-html/rtl/sysutils/formatchars.html
Downloads
You can download the source code for the tutorial project and executable/EXE files from the links below: