
Search

As of October, 2016, Embarcadero is offering a free release
of Delphi (Delphi
10.1 Berlin Starter Edition ). There
are a few restrictions, but it is a welcome step toward making
more programmers aware of the joys of Delphi. They do say
"Offer may be withdrawn at any time", so don't delay if you want
to check it out. Please use the
feedback link to let
me know if the link stops working.

Support DFF - Shop
If you shop at Amazon anyway, consider
using this link.
We receive a few cents from each
purchase. Thanks

Support DFF - Donate
If you benefit from the website, in terms of
knowledge, entertainment value, or something otherwise useful,
consider making a donation via PayPal to help defray the
costs. (No PayPal account necessary to donate via credit
card.) Transaction is secure.

Mensa®
Daily Puzzlers
For over 15 years
Mensa Page-A-Day calendars have provided several puzzles a year
for my programming pleasure. Coding "solvers" is most fun,
but many programs also allow user solving, convenient for "fill
in the blanks" type. Below are Amazon links to the
two most recent years.
Mensa®
365 Puzzlers Calendar 2017
Mensa®
365 Puzzlers Calendar 2018

(Hint: If you can
wait, current year calendars are usually on sale in January.)

Contact
Feedback:
Send an
e-mail with your comments about this program (or anything else).

|
| |
Problem Description
This program allows users to select clock face and hand BMP or JPG images and
combine them to for a running clock.
Background & Techniques
A user wrote a few weeks ago asking how to rotate JPEG clock hand images
to simulate an analog clock. That triggered another
learning/relearning experience figuring out how to do it. This program is
the result. Not that the world needs another analog clock but it did make an
interesting programming project.
The program includes these features:
 | A few sample clocks are included but users can provide face and
hand images in JPG or BMP format to be used in constructing the clock. Face
images should be square and are scaled to the image defined on the clock
page. Hand images should be in the vertical position pointing up and trimmed
to the width and height of the hand. Background (the non-hand part of the
image) should be white. |
 | The centers of rotation for hour and minute hands are generally not at
the end of the hand. Centers are estimated by the program but can be fine
tuned under user control. |
 | Scaling of hands as a fraction of the clock face radius is set by the
program at 0.8 for the minute hand and 0.6 for the hour hand, but can be
changed by the user. |
 | Clock definitions specifying the parameters can be saved and reloaded as
.CLK files. |
 | The default clock mode is "real time" but the clock can be stopped, or,
for testing, set to a user specified time in "one time" mode or run in
"fast" mode. |
 | A simple program generated second hand can be displayed or hidden. When
second hand is displayed, the clock image is updated about 10 times
per second compared to only once per second without the second hand. |
Non-programmers are welcome to read on, but may want to jump to bottom of
this page to download the executable program now.
Programmer's Notes:
The two biggest programming problems to overcome were bitmap rotation and
drawing the clock hands without flicker and while preserving the background
image.
I found several Delphi bitmap rotation functions online and chose two
techniques which use standard Windows features ("Set World Translation" and
"Parallelogram Blit") which do not require additional Delphi components.
The solution to drawing the hands over the face image and each other requires
"mask" drawing where pixels of a specified color in the image being drawn remain
transparent an allow the existing background to show through.
A few other features of the program have been implemented and previously
discussed.
 | I used the TIniFile control to save the file names and centers of
rotation and scaling factors for the hands. Ini files have the
advantage of being easy to create and restore and are in plain text, making
them easy to debug and/or edit. I save the files with an extension of
".clk". |
 | Users can define new clocks and may fine tune existing clocks. In
either case, it is polite program behavior to ask the user if they wish to
save any unsaved changes before loading or starting a new clock or exiting
the program. A technique I often use defines a global Boolean variable
"Modified" which is initialized to False when a new clock is
defined or clock definition is loaded and set to True when changes
are made to the current clock. A CheckModified function
called before overwriting or abandoning a changed clock looks like this: |
function TForm1.checkmodified:boolean; {Give user a chance to save a new or changed clock before closing or
overwriting it} var mr:integer; begin result:=true; if modified then begin mr:=messagedlg('Save clock first?',
mtconfirmation,mbyesnocancel,0); if mr=mryes then savebtnclick(self)
else if mr=mrcancel then
result:=false; end; end;
If the function returns "True", either the existing clock has not
been modified, or was modified and the user replied "Yes" and the
clock was saved, or the user replied "No" even though the clock had
changes. Only if the clock had been modified and the user replied "Cancel"
to the "save it first" question will the function return "False" and
the load or new request be abandoned.
 | Converting a time field to hand angles was another interesting exercise.
Delphi TDateTime fields are floating point numbers with dates as
number of days from some long ago start date and times as fractions of a
day. Since our clocks use the 12 hour time scale we can extract the
fractional part of a date-time using the TimeOf or Frac
functions and double it to get the current angle of the hour hand in
revolutions (between 0 and 2). In degrees, we can throw out the full
number of revolutions and multiply the resulting "revolution" angle by 360
for degrees or 2Pi for radians. For minute hand angle, Frac(24 *
Time) = number of revolutions and for the second hand, Frac(1440*Time) =
fraction of a revolution which can be multiplied by 360 or 2Pi.
In this program, procedure HandAngles calculates these three angles. |
October 27, 2012: Version 2 posted today changes the way that
the clock is updated. Instead of using timer event pops, a "Runclock" loop
now manages clock hand movements. This allows second hand updates at exact
second boundaries and reduces processor time significantly. If your
computer is in the US and connects to the Internet, chances are that its date
and time are synchronized with the National Institute of Standards time server
web site. I have an "atomic watch: which synchs with the WWVB radio signal
daily. It surprised me to see that the seconds hands of these JPG Clocks
and my wristwatch are typically within one second of each other!
Running/Exploring the Program
Suggestions for Further Explorations
 |
Improve rotated image quality with
anti-aliasing code |
 |
.Improve
efficiency by reducing size of rotated images to rectangles just large
enough to hold rotated hand images. |
 |
|
Original: October 21, 2012 |
Modified:
May 15, 2018
|
|