JPG Clock

[Home]   [Puzzles & Projects]    [Delphi Techniques]   [Math topics]   [Library]   [Utilities]

 

Search

Search WWW

Search DelphiForFun.org

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).

Search DelphiForFun.org only

 

 

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:
 

bullet 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.
bulletThe 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.
bulletScaling 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.
bulletClock definitions specifying the parameters can be saved and reloaded as .CLK files.
bulletThe 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.
bulletA 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. 

 

bulletI 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".
bulletUsers 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.  

bulletConverting 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 

bulletDownload  executable
bulletDownload source 

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:  July 29, 2017

 
  [Feedback]   [Newsletters (subscribe/view)] [About me]
Copyright 2000-2017, Gary Darby    All rights reserved.