I needed an analogue clock component and couldn't find one that quite fitted my requirements. So I wrote the TNuClock component. It was written for a specific app but it might be useful in your programs. Bug reports will be gratefully accepted but don't expect a high level of tech support!

The Delphi 3 TNuClock component is free but I reserve all rights and you may not incorporate it in commercial software. However, you may purchase the source for $19.95 and use/improve/debug it in any way you wish.

Please contact me on tony.lacy@btinternet.com if you wish to purchase the source.

The Delphi source for the NuClock demonstration program gives examples of how to
use NuClock components as clocks, timers etc. and should be included in this package.

Here is the interface section of the TNuClock component.

------------------------------------------------
Unit NuClock;
{$DEFINE DEMONSTRATION}
Interface
   
Uses
   Windows, Messages, SysUtils, Classes, Controls, Forms,extctrls,Graphics;
   
Type
   
//base type for objects that are drawn on the clock face
   TFaceObject = Class(TPersistent)
   Private
      Owner:TControl;
      FPenColor:TColor;
      FBrushColor:TColor;
      FSize:integer;
      FCanvas:TCanvas;
      Function PolarToRectX(angle:integer):Integer;
      Function PolarToRectY(angle:integer):Integer;
      Procedure SetRadius(ARadius:integer);
      Procedure Draw;virtual;abstract;
      Procedure SetPenColor(Value: TColor);
      Procedure SetBrushColor(Value: TColor);
      Procedure SetSize(Value: integer);
      Procedure UpdateFace;
   Public
      Constructor Create(AOwner:TControl;ACanvas:Tcanvas;ASize:integer);virtual;
      Destructor Destroy;override;
   Published
      Property Pen_Color:TColor read FPenColor write SetPenColor Default clBlack;
      Property Brush_Color:TColor read FBrushColor write SetBrushColor Default clWhite;
      Property Size:Integer read FSize write SetSize Default -20;
   End;
      
//could be extended to include Roman numerals and rotated numerals
      TBezelNumerals=(bnNone,bnArabic);
      
      
   TBezel = Class(TFaceObject)
   Private
      FBezelNumerals:TBezelNumerals;
      Procedure Draw;override;
   Public
      Constructor Create(AOwner:TControl;ACanvas:Tcanvas;ASize:integer);override;
      Destructor Destroy;override;
   Published
      Property Style:TBezelNumerals read FBezelNumerals write FBezelNumerals Default bnNone;
   End;
      
//hour and minute hands      
   THandObject = Class(TFaceObject)
   Private
      FValue:integer;
      Procedure Draw;override;
      Procedure SetValue(Value: integer);
   Public
      Constructor Create(AOwner:TControl;ACanvas:Tcanvas;ASize:integer);override;
      Destructor Destroy;override;
   End;
      
      
//a second hand is drawn slightly differently
   TSecondHandObject = Class(THandObject)
   Private
      Procedure ClockCenter;
      Procedure Draw;override;
   Public
      Constructor Create(AOwner:TControl;ACanvas:Tcanvas;ASize:integer);override;
      Destructor Destroy;override;
      
   End;
      
      
//Refresh rate
      TRRate=(rr10ms,rr100ms,rr1second,rr10seconds,rr1minute);
      
//How the clock gets its refresh pulses
      TClockMode=(cmNormal,cmMaster,cmSlave,cmManual);
      
//used in trig lookup table
      THandPosition=Record
      Hour,
      Minute,
      Second:word;
   End;
      
//The clock object defined
   TNuClock = class(TGraphicControl)
   Private
      FPicture: TPicture;
      FOnProgress: TProgressEvent;
      FOnClockTick:TNotifyEvent;
      FAutoSize: Boolean;
      FStretch: Boolean;
      FCenter: Boolean;
      FIncrementalDisplay: Boolean;
      FTransparent: Boolean;
      FDrawing: Boolean;
      FWorkspace:TBitmap;
      FXOffset,
      FYOffset,
      FRadius,
      FShortest:integer;
      FFaceColor:TColor;
      FBezel:TBezel;
      FHourHand,
      FMinuteHand:THandObject;
      FSecondHand:TSecondHandObject;
      FTimerHours,
      FTimerMinutes,
      FTimerSeconds,
      FTimermSecs:word;
      FTimer1:TTimer;
      FTimerinterval:word;
      FOffset:Double;
      FClockMode:TClockMode;
      Function GetCanvas: TCanvas;
      Procedure PictureChanged(Sender: TObject);
      Procedure SetAutoSize(Value: Boolean);
      Procedure SetCenter(Value: Boolean);
      Procedure SetPicture(Value: TPicture);
      Procedure SetStretch(Value: Boolean);
      Procedure SetTransparent(Value: Boolean);
      Procedure PaintClockFace;
      Procedure SetFaceColor(Value: TColor);
      Procedure SetWorkspaceFont(Value: TFont);
      Function GetWorkspaceFont:TFont;
      Procedure SetsecondHand(Value:TSecondHandObject);
      Procedure SetMinuteHand(Value:THandObject);
      Procedure SetHourHand(Value:THandObject);
      Procedure SetBezelStyle(Value:TBezel);
      Function GetRInterval:TRRate;
      Procedure SetRInterval(Value:TRRate);
      Function GetClockMode:TClockMode;
      Procedure SetClockMode(Value:TClockMode);
      Function GetHandPosition:THandPosition;
      Procedure SetHandPosition(Value:ThandPosition);
{ Protected declarations }
   Protected
      Procedure SetOffset(Value:Double);virtual;
      Procedure SlaveClick;virtual;
      Function DestRect: TRect;
      Function DoPaletteChange: Boolean;
      Function GetPalette: HPALETTE; override;
      Procedure Paint; override;
      Procedure Progress(Sender: TObject; Stage: TProgressStage;
      PercentDone: Byte; RedrawNow: Boolean; Const R: TRect; Const Msg: string); dynamic;
      Procedure ClockTick(Sender:TObject); dynamic;
      Procedure TimerClick(Sender: TObject);virtual;
      
   Public
{ Public declarations }
      Procedure UpdateClock;
      Function AdjustHours:integer;virtual;
      Property Canvas: TCanvas read GetCanvas;
      Constructor Create(AOwner:TComponent);override;
      Destructor Destroy;override;
      Property HandPosition:THandPosition read GetHandPosition write SetHandPosition;
   Published
{ Published declarations }
      Property Height default 100;
      Property Width default 100;
      Property Align;
      Property AutoSize: Boolean read FAutoSize write SetAutoSize default False;
      Property Center: Boolean read FCenter write SetCenter default False;
      Property DragCursor;
      Property DragMode;
      Property Enabled;
      Property IncrementalDisplay: Boolean read FIncrementalDisplay write       FIncrementalDisplay default False;
      Property ParentShowHint;
      Property Picture: TPicture read FPicture write SetPicture;
      Property ShowHint;
      Property Stretch: Boolean read FStretch write SetStretch default False;
      Property Transparent: Boolean read FTransparent write SetTransparent default False;
      Property Visible;
      Property OnClick;
      Property OnDblClick;
      Property OnDragDrop;
      Property OnDragOver;
      Property OnEndDrag;
      Property OnMouseDown;
      Property OnMouseMove;
      Property OnMouseUp;
      Property OnProgress: TProgressEvent read FOnProgress write FOnProgress;
      Property OnClockTick: TNotifyEvent read FOnClockTick write FOnClockTick;
      Property OnStartDrag;
      Property Face_Color: TColor read FFaceColor write SetFaceColor
      default clBtnface;
      Property Face_Font:TFont read GetWorkSpaceFont write SetWorkSpaceFont;
      Property Bezel:TBezel read FBezel write SetBezelStyle;
      Property SecondHand:TSecondHandObject read FSecondHand write SetSecondHand;
      Property MinuteHand:THandObject read FMinuteHand write SetMinuteHand;
      Property HourHand:THandObject read FHourHand write SetHourHand;
      Property RefreshInterval:TRRate read GetRInterval write SetRInterval default rr100ms;
      Property Offset:Double read FOffset write SetOffset;
      Property ClockMode:TClockMode read GetClockMode write SetClockMode default cmNormal;
   End;
      Procedure Register;
      
Implementation
.....
Procedure Register;
Begin
   RegisterComponents('Samples', [TNuClock]);
End;

End.
----------------------------------------------------------
Notes:

MinuteHand, HourHand, SecondHand and bezel are all face object descendants.

Face object properties:


Property Pen_Color:TColor
Select from a palette or use predefined colors.


Property Brush_Color:TColor
Select from a palette or use predefined colors. 


Property Size:Integer
The length of a hand or the radius of the bezel in pixels. If size is a negative integer then the object size is determined by the size of the clock. For example:
HourHand.Size:=-10 makes the hour hand length length 10 pixels smaller than the clock
face. Set Size to 0 to suppress dislay of a clock face object.


Bezel object has an extra property called style which determines if numerals are to be displayed.



NuClock properties and methods


Procedure UpdateClock;
If ClockMode is not cmManual obtains system time  and draws the clock face objects and any underlying image. If ClockMode is cmManual then you will have to set the required hand positions using property HandPosition.


Function AdjustHours:integer;
Used to determine the hour hand position. For example 04:30 will display the hours hand
midway between 4 and 5 using this function.


Property HandPosition:THandPosition
Set and get the position of the clock hands. Useful if you are manually controlling the clock from your program. THandPosition is in units of 6 degrees.
Example: 01:35:10 gives
THandPosition.hour:=5
THandPosition.minute:=35
THandPosition.second:=10
If the clock is in cmManual mode you will need to repaint the clock before changes are seen.


Property OnClockTick: TNotifyEvent;


Property Face_Color: TColor
Determines the clock face color.


Property Face_Font:TFont
If Bezel.Style is set to Arabic will determine font and color of numerals.


Property Bezel:TBezel
Set to bnArabic for numerals, bnNone for no numerals.


Property SecondHand:TSecondHandObject
Gives access to the properties of the Second hand. 


Property MinuteHand:THandObject
Gives access to the properties of the Minute hand.  


Property HourHand:THandObject
Gives access to the properties of the hour hand. 


Property RefreshInterval:TRRate
Selects how often a redisplay is triggered. RefreshInterval does not determine
what time is displayed. The time displayed is taken from the Now function plus an optional offset value. Clock display updates are triggered by a system timer and the actual interval can be rather irregular. 


Property Offset:Double
This value is added to the time obtained from the Now function to allows shifted time displays. Positive or negative values can be used. Example:
To display one hour behind current time:
NuClock.Offset:=-EncodeTime(1,0,0,0);




Property ClockMode:TClockMode

A master/slave system is used when multiple clocks are required. This eases the problem of
a limited number of system timers being available. If you intend to display more than 2-3 clocks in a form then set one clock to cmMaster ClockMode and the rest to cmSlave ClockMode.

cmNormal. A system timer is allocated to this clock.

cmMaster. A system timer is allocated to this clock and all other slave clocks owned by the form are updated by this timer. 

cmSlave. No system timer is allocated. The clock is updated every time an associated master
clock updates. A slave clock can display any time, it is only the display refresh interval that is locked to a master clock.

cmManual. No system timer is allocated. The clock must be updated under program control.


Other NuClock properties not mentioned in these notes are similar to the ones in the TImage component. For example, the picture property is used in the same way as a Timage and will appear on the clock face.

Tony Lacy December 1997

tony.lacy@btinternet.com
Tony_Lacy@compuserve.com
100030.157@compuserve.com
tony.lacy@usa.net
http://www.btinternet.com/~tony.lacy/

----------------------------------------------------------

