Introduction
There are several nice implementations of digital clocks available on
CodeProject and other sites, but good-looking analog clocks are harder
to find. The typical analog clock you will see looks like:
Even the Microsoft XP Date and Time dialog displays a flat 2D clock:
There are some good-looking analog clocks. I found these in my search:
Unfortunately, all of these last three have drawbacks: use of Flash,
or dependence on a large-footprint "skinning" engine, or tight
integration with a "widget" framework (also large footprint). And,
of course, the source code is not available.
At this point I began thinking about what is actually involved in displaying
an analog clock. It seemed to me that there were two basic problems: first,
display the clock face. To achieve realistic shading and lighting
effects, it was obvious that starting with a bitmap of a clock face was
the easiest solution. Second, display the second, minute, and
hour hands. This turned out to be the most time-consuming task. I
wanted hands that came to a point for minute and hour hands,
and I knew that I would have to do some kind of anti-aliasing on
edges of the hands - rotating a line in a 360� range is sure to produce
jaggies. I very quickly found a solution to this problem in
the CodeProject article
Antialiasing:
Wu Algorithm, which shows how to draw anti-aliased lines.
Demo App
This is what the
XAnalogClock
looks like:
| |
Blue Skin | Silver Skin |
The date and second hand are optional, and will be added (or removed)
the next time the Run button is clicked after the options are changed.
How To Use XAnalogClock
To integrate XAnalogClock
into your app, you first need
to add the following files to your project:
- XAnalogClock.cpp
- XAnalogClock.h
- CDCBuffer.h
- WuLine.cpp
- WuLine.h
- clockface.bmp - see section on skinning XAnalogClock
- date.bmp - see section on skinning XAnalogClock
Then use resource editor to add a static control to your dialog,
and use the Class Wizard to attach a member variable to that control.
Next, include the header file XAnalogClock.h in
the dialog's header file. Then replace
the CStatic
definition with CXAnalogClock
.
The final step is to include msimg32.lib for linker (this is needed for the
TransparentBlt()
function).
Go to Project | Settings, select All Configurations
in the combo box at left, select the Link tab, and enter
msimg32.lib in the Object/library modules entry field:
Now you are ready to start using XAnalogClock
.
Here is some code from XAnalogClockTestDlg.cpp, that shows how to use the clock:
m_Clock.SetBitmaps(IDB_BLUE_CLOCK_FACE, IDB_BLUE_DATE);
CSize size = m_Clock.GetWindowSize();
CRect rect;
m_Clock.GetWindowRect(&rect);
ScreenToClient(&rect);
rect.right = rect.left + size.cx;
rect.bottom = rect.top + size.cy;
m_Clock.MoveWindow(&rect);
m_Clock.Run();
Skinning XAnalogClock
Skinning XAnalogClock
is accomplished by two bmp files,
clockface.bmp and date.bmp. (The file names can
be anything you want - just import two bmp files using
the resource editor, and assign resource IDs). In demo project,
two skins are provided - "blue" and "silver".
Note - since XAnalogClock
bitmap files use 24-bit (True Color),
the clock might not display well if your screen color depth is
set to 256 colors.
The demo file blue clockface.bmp contains bitmap for clock face:
The clock face bitmap must be 100x100.
The demo file blue date.bmp contains a bitmap for date box (image has been enlarged):
The date box bitmap must be 18x14.
XAnalogClock Implementation
Since
XAnalogClock
is based on bitmaps, it was important to provide efficient
bitmap handling and display. One way I did this was by using the
CDCBuffer
class, which handles loading and buffering bitmaps,
and speeds up display of frequently-used bitmaps.
A second optimization technique was driven by the rather obvious
observation that the date, minute hand, and hour hand do not change
unless the minute changes. So, for 59 out of 60 seconds,
the only thing being updated on the display is the second hand. This results in
a huge reduction in the CPU cycles required for processing and displaying
the Wu lines. Within each minute, the current clock face
CDC
is saved (including the minute and hour hands), and is simply
BLT'd to the display CDC when a paint occurs. Then the second hand is
BLT'd to the display CDC on top of this saved CDC.
XAnalogClock Functions
Here are the functions available on CXAnalogClock
:
GetTime() | Get currently displayed time |
GetWindowSize() | Get control size |
IsClockRunning() | Get run state of clock |
SetBackgroundColor() | Set background color |
SetBitmaps() | Set bitmap resource IDs |
SetGmtAdjust() | Not currently used |
SetHourHandColor() | Set color of hour hand; default is black |
SetMinuteHandColor() | Set color of minute hand; default is black |
SetSecondHandColor() | Set color of second hand; default is cardinal |
SetTime() | Set starting time; used only when UseSystemTime() is called with FALSE |
SetTransparentColor() | Set transparent color |
ShowDate() | Show/hide date |
ShowSecondHand() | Show/hide second hand |
Run() | Start the clock |
Stop() | Stop the clock |
UseSystemTime() | Use system time; if parameter is FALSE , the time specified by SetTime() will be used |
Acknowledgments
Revision History
Version 1.1 - 2006 July 20
- Updated article to include link instructions for msimg32.lib
(no source code changes).
Version 1.0 - 2006 March 23
Usage
This software is released into the public domain. You are free
to use it in any way you like, except that you may not sell this
source code. If you modify it or extend it, please consider posting
the new code here for everyone to share. This software is provided "as is"
with no expressed or implied warranty. I accept no liability for any
damage or loss of business that this software may cause.