Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
{
Custom Needle Gauge Component
by Jerry Dodge
Component: TJDNeedleGauge
Sub-Classes:
- TNeedles: TCollection - Group of needle objects
- TNeedle: TCollectionItem - Individual needle object
- TTickMarks: TCollection - Group of tick mark objects for one needle
- TTickMark: TCollectionItem - Individual set of tick marks for one needle
- THotspots: TPersistent - Group of possible TPoint's for clickability
(Used for ability to click Needles or Tick Marks - need to redesign)
Abilities:
- Add virtually unlimited number of needles to point around a canvas
- Add virtually unlimited number of tick mark sets, unique for each needle
- Fade background with a custom color
- Color and size each needle and tick mark
Coming Soon:
- Set a needle's range around a certain start/stop point around canvas
(Partially working, needs a lot of development)
- Use images for Needles and Tick Marks instead of plain Lines and Elipses
(Picture properties exist, need to implement drawing)
- Add centerpiece elipse or image over needles
(Some properties exist, but is far from working)
- Ability to click on Needles and Tick Marks
(Partially working, needs a lot of development)
- Changing cursor over Needles or Tick Marks is somewhat working
- Mouse events distinctly over Needles or Tick Marks is somewhat working
(Need to recognize the exact Needle or Tick Mark in event)
- Functionality wrapped in "THotspots" class but needs to be redesigned
- Position a needle anywhere on the canvas, not just the center point
(No development started yet for this)
- Smooth drawing of lines and elipses on canvas
(No development started yet for this)
To Do:
- Properly implement degree start/stop of needles and tick marks
- Properly implement percentage length of needles
- Implement drawing pictures for needles and tick marks
}
unit JDNeedleGauge;
interface
uses
Classes, Controls, SysUtils, Windows, StdCtrls, ExtCtrls, Graphics, StrUtils,
JPEG, Messages, Variants, Forms, ComCtrls;
type
TJDNeedleGauge = class;
TNeedles = class;
TNeedle = class;
TTickMarks = class;
TTickMark = class;
THotspots = class;
TPoints = array of TPoint;
TJDMouseEvent = procedure(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer) of object;
TJDMouseMoveEvent = procedure(Sender: TObject; Shift: TShiftState;
X, Y: Integer) of object;
TJDGTickStyle = (gtsNone, gtsCircle, gtsBall, gtsLine);
TJDGNeedleStyle = (gnsLine, gnsImage);
TJDGNeedleSizing = (gnsAuto, gnsPixels, gnsPercent);
THotspot = record
Point: TPoint;
Size: Integer;
Active: Bool;
Value: String;
end;
THotspots = class(TPersistent)
private
fHotspots: String;
function GetHotspot(Point: TPoint): THotspot;
procedure SetHotspot(Point: TPoint; Hotspot: THotspot);
public
constructor Create;
destructor Destroy; override;
procedure Clear;
function InHotspot(APoint: TPoint): THotspot;
property Hotspot[Point: TPoint]: THotspot read GetHotspot write SetHotspot;
end;
TTickMarks = class(TCollection)
private
fOwner: TJDNeedleGauge;
fEvent: TNotifyEvent;
fRedraw: TNotifyEvent;
function GetItems(Index: Integer): TTickMark;
procedure SetItems(Index: Integer; Value: TTickMark);
procedure GaugeEvent(Sender: TObject);
procedure GaugeRedraw(Sender: TObject);
protected
function GetOwner: TPersistent; override;
public
constructor Create(AOwner: TPersistent);
function Add: TTickMark;
property OnEvent: TNotifyEvent read fEvent write fEvent;
property OnRedraw: TNotifyEvent read fRedraw write fRedraw;
property Items[Index: Integer]: TTickMark read GetItems write SetItems;
end;
TTickMark = class(TCollectionItem)
private
fHotspots: THotspots;
fOwner: TJDNeedleGauge;
fIncrement: Integer;
fSize: Integer;
fColor: TColor;
fCanClick: Bool;
fVisible: Bool;
fEvent: TNotifyEvent;
fRedraw: TNotifyEvent;
procedure DoEvent;
procedure DoRedraw;
procedure SetIncrement(Value: Integer);
procedure SetSize(Value: Integer);
procedure SetColor(Value: TColor);
procedure SetCanClick(Value: Bool);
procedure SetVisible(Value: Bool);
protected
function GetDisplayName: String; override;
public
constructor Create(AOwner: TCollection); override;
destructor Destroy; override;
procedure Assign(source:TPersistent); override;
property OnEvent: TNotifyEvent read fEvent write fEvent;
property OnRedraw: TNotifyEvent read fRedraw write fRedraw;
published
property Increment: Integer read fIncrement write SetIncrement;
property Size: Integer read fSize write SetSize;
property Color: TColor read fColor write SetColor;
property CanClick: Bool read fCanClick write SetCanClick;
property Visible: Bool read fVisible write SetVisible;
end;
TNeedles = class(TCollection)
private
fOwner: TComponent;
fEvent: TNotifyEvent;
fRedraw: TNotifyEvent;
procedure NeedleEvent(Sender: TObject);
procedure NeedleRedraw(Sender: TObject);
protected
function GetOwner: TPersistent; override;
function GetItem(Index: Integer): TNeedle;
procedure SetItem(Index: Integer; Value: TNeedle);
procedure Update(Item: TNeedle);
public
constructor Create(AOwner: TComponent);
function Add: TNeedle;
function Insert(Index: Integer): TNeedle;
property OnEvent: TNotifyEvent read fEvent write fEvent;
property OnRedraw: TNotifyEvent read fRedraw write fRedraw;
property Items[Index: Integer]: TNeedle read GetItem write SetItem; default;
end;
TNeedle = class(TCollectionItem)
private
fPicture: TPicture;
fHotspots: THotspots;
fTickMarks: TTickMarks;
fOwner: TPersistent;
fLength: Integer;
fWidth: Integer;
fColor: TColor;
fTransparentColor: TColor;
fStyle: TJDGNeedleStyle;
fCursor: TCursor;
fPosition: Integer;
fCanClick: Bool;
fMin: Integer;
fMax: Integer;
fDegreeStart: Integer;
fDegreeStop: Integer;
fSizing: TJDGNeedleSizing;
fPassMax: Bool;
fVisible: Bool;
fEvent: TNotifyEvent;
fRedraw: TNotifyEvent;
procedure DoEvent;
procedure DoRedraw;
procedure SetPicture(Value: TPicture);
procedure SetLength(Value: Integer);
procedure SetWidth(Value: Integer);
procedure SetColor(Value: TColor);
procedure SetTransparentColor(Value: TColor);
procedure SetStyle(Value: TJDGNeedleStyle);
procedure SetCursor(Value: TCursor);
procedure SetPosition(Value: Integer);
procedure SetMin(Value: Integer);
procedure SetMax(Value: Integer);
procedure SetDegreeStart(Value: Integer);
procedure SetDegreeStop(Value: Integer);
procedure SetTickMarks(Value: TTickMarks);
procedure SetSizing(Value: TJDGNeedleSizing);
procedure SetPassMax(Value: Bool);
procedure SetVisible(Value: Bool);
procedure SetIndex(Value: Integer); override;
procedure TickEvent(Sender: TObject);
procedure TickRedraw(Sender: TObject);
protected
function GetDisplayName: String; override;
public
constructor Create(AOwner: TCollection); override;
destructor Destroy; override;
property OnEvent: TNotifyEvent read fEvent write fEvent;
property OnRedraw: TNotifyEvent read fRedraw write fRedraw;
published
property Picture: TPicture read fPicture write SetPicture;
property Length: Integer read fLength write SetLength;
property Width: Integer read fWidth write SetWidth;
property Color: TColor read fColor write SetColor;
property TransparentColor: TColor read fTransparentColor
write SetTransparentColor;
property Style: TJDGNeedleStyle read fStyle write SetStyle;
property Cursor: TCursor read fCursor write SetCursor;
property Position: Integer read fPosition write SetPosition;
property CanClick: Bool read fCanClick write fCanClick;
property Min: Integer read fMin write SetMin;
property Max: Integer read fMax write SetMax;
property DegreeStart: Integer read fDegreeStart write SetDegreeStart;
property DegreeStop: Integer read fDegreeStop write SetDegreeStop;
property TickMarks: TTickMarks read fTickMarks write SetTickMarks;
property Sizing: TJDGNeedleSizing read fSizing write SetSizing;
property PassMax: Bool read fPassMax write SetPassMax;
property Visible: Bool read fVisible write SetVisible;
end;
TJDNeedleGauge = class(TCustomControl)
private
fBmp: TBitmap;
fBackground: TBitmap;
fNeedles: TNeedles;
fPicture: TPicture;
fBackColor: TColor;
fForeColor: TColor;
fLabelTop: String;
fLabelBottom: String;
fDoFade: Bool;
fFadeStep: Single;
fShowCenter: Bool;
fCenterColor: TColor;
fCenterSize: Integer;
fMouseDown: TJDMouseEvent;
fMouseUp: TJDMouseEvent;
fMouseMove: TJDMouseMoveEvent;
fNeedleMouseDown: TJDMouseEvent;
fNeedleMouseUp: TJDMouseEvent;
fNeedleMouseMove: TJDMouseMoveEvent;
procedure CreateBackground;
procedure DrawScale;
procedure DrawNeedles;
procedure DrawNeedle(ANeedle: TNeedle);
procedure DrawCenter;
procedure DisplayGauge;
procedure SetBackColor(Value: TColor);
procedure SetForeColor(Value: TColor);
procedure SetDoFade(Value: Bool);
procedure SetShowCenter(Value: Bool);
procedure SetCenterColor(Value: TColor);
procedure SetCenterSize(Value: Integer);
procedure SetLabelTop(Value: String);
procedure SetLabelBottom(Value: String);
procedure SetFadeStep(Value: Single);
procedure OnNeedleEvent(Sender: TObject);
procedure OnNeedleRedraw(Sender: TObject);
procedure MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
procedure NeedleMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure NeedleMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure NeedleMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure Paint; override;
procedure DoRefresh(DrawBackground: Bool);
published
property BackColor: TColor read fBackColor write SetBackColor;
property ForeColor: TColor read fForeColor write SetForeColor;
property DoFade: Bool read fDoFade write SetDoFade;
property ShowCenter: Bool read fShowCenter write SetShowCenter;
property CenterColor: TColor read fCenterColor write SetCenterColor;
property CenterSize: Integer read fCenterSize write SetCenterSize;
property LabelTop: String read fLabelTop write SetLabelTop;
property LabelBottom: String read fLabelBottom write SetLabelBottom;
property Needles: TNeedles read fNeedles write fNeedles;
property Picture: TPicture read fPicture write fPicture;
property FadeStep: Single read fFadeStep write SetFadeStep;
property Anchors;
property Align;
property Visible;
property OnGMouseDown: TJDMouseEvent read fMouseDown write fMouseDown;
property OnGMouseUp: TJDMouseEvent read fMouseUp write fMouseUp;
property OnGMouseMove: TJDMouseMoveEvent read fMouseMove write fMouseMove;
property OnGNeedleMouseDown: TJDMouseEvent read fNeedleMouseDown write fNeedleMouseDown;
property OnGNeedleMouseUp: TJDMouseEvent read fNeedleMouseUp write fNeedleMouseUp;
property OnGNeedleMouseMove: TJDMouseMoveEvent read fNeedleMouseMove write fNeedleMouseMove;
property OnClick;
property OnDblClick;
end;
function NewPosition(Center: TPoint; Distance: Integer; Degrees: Integer): TPoint;
procedure Register;
implementation
{$R JDNeedleGauge.dcr}
procedure Register;
begin
RegisterComponents('JD Custom', [TJDNeedleGauge]);
end;
function NewPosition(Center: TPoint; Distance: Integer; Degrees: Integer): TPoint;
var
Radians: Real;
begin
//Convert angle from degrees to radians; Subtract 135 to bring position to 0 Degrees
Radians:= ((Degrees - 135) * Pi / 180.0);
Result.X:= Trunc(Distance*Cos(Radians)-Distance*Sin(Radians))+Center.X;
Result.Y:= Trunc(Distance*Sin(Radians)+Distance*Cos(Radians))+Center.Y;
end;
function IntRange(Value: Integer; Min: Integer; Max: Integer): Integer;
begin
Result:= Value;
if Result < Min then Result:= Min;
if Result > Max then Result:= Max;
end;
{ THotspots }
function THotspots.GetHotspot(Point: TPoint): THotspot;
var
H, D: String;
P, P2: Integer;
begin
D:= IntToStr(Point.X)+'x'+IntToStr(Point.Y)+',';
P:= Pos(D, fHotspots);
if P > 0 then begin
H:= fHotspots;
Result.Point:= Point;
Result.Active:= True;
Delete(H, 0, P+Length(D));
P2:= Pos(',', H);
Result.Size:= StrToIntDef(Copy(H, 0, P2), 0);
Delete(H, 0, P2+1);
P2:= Pos(';', H);
Result.Value:= Copy(H, 0, P2);
end else begin
Result.Point:= Point;
Result.Active:= False;
Result.Size:= 0;
Result.Value:= '';
end;
end;
procedure THotspots.SetHotspot(Point: TPoint; Hotspot: THotspot);
begin
if Self.GetHotspot(Point).Active = False then begin
Self.fHotspots:= Self.fHotspots + IntToStr(Point.X)+'x'+IntToStr(Point.Y)+
','+IntToStr(Hotspot.Size)+','+Hotspot.Value+';';
end;
end;
constructor THotspots.Create;
begin
Self.fHotspots:= '';
end;
destructor THotspots.Destroy;
begin
end;
procedure THotspots.Clear;
begin
fHotspots:= '';
end;
function THotspots.InHotspot(APoint: TPoint): THotspot;
var
Lst: TStringList;
X, P: Integer;
SX, SY, SS: String;
TX, TY, TS: Integer;
V: String;
begin
if Length(fHotspots) > 0 then begin
Lst:= TStringList.Create;
try
Lst.Delimiter:= ';';
Lst.DelimitedText:= fHotspots;
for X:= 0 to Lst.Count - 1 do begin
V:= Lst[X];
P:= Pos('x', V);
SX:= Copy(V, 1, P-1);
TX:= StrToIntDef(SX, 0);
Delete(V, 1, P);
P:= Pos(',', V);
SY:= Copy(V, 1, P-1);
TY:= StrToIntDef(SY, 0);
Delete(V, 1, P);
P:= Pos(',', V);
SS:= Copy(V, 1, P-1);
TS:= StrToIntDef(SS, 1);
if ( (APoint.X > (TX - (TS div 2)) - 1)
and (APoint.X < (TX + (TS div 2)) + 1)
and (APoint.Y > (TY - (TS div 2)) - 1)
and (APoint.Y < (TY + (TS div 2)) + 1) ) then
begin
Result.Point:= Point(TX, TY);
Result.Size:= TS;
Result.Active:= True;
Delete(V, 1, P);
Result.Value:= Copy(V, P, Length(V));
end else begin
Result.Point:= APoint;
Result.Active:= False;
Result.Size:= 0;
Result.Value:= Lst[X];
end;
end;
finally
Lst.Free;
end;
end;
end;
{ TNeedles }
constructor TNeedles.Create(AOwner: TComponent);
begin
inherited Create(TNeedle);
fOwner:= AOwner;
end;
function TNeedles.GetOwner: TPersistent;
begin
Result:= fOwner;
end;
function TNeedles.Add: TNeedle;
begin
Result:= Inherited Add as TNeedle;
if assigned(Result) then begin
Result.fOwner:= Self.fOwner;
Result.OnEvent:= NeedleEvent;
Result.OnRedraw:= NeedleRedraw;
NeedleEvent(Self);
end;
end;
procedure TNeedles.NeedleEvent(Sender: TObject);
begin
if assigned(fEvent) then fEvent(Self);
end;
function TNeedles.GetItem(Index: Integer): TNeedle;
begin
Result:= inherited GetItem(Index) as TNeedle;
end;
procedure TNeedles.SetItem(Index: Integer; Value: TNeedle);
begin
inherited SetItem(Index, Value);
end;
procedure TNeedles.Update(Item: TNeedle);
begin
inherited Update(Item);
end;
function TNeedles.Insert(Index: Integer): TNeedle;
begin
Result:= inherited Insert(Index) as TNeedle;
end;
procedure TNeedles.NeedleRedraw(Sender: TObject);
begin
if assigned(Self.fRedraw) then Self.fRedraw(Self);
end;
{ TNeedle }
constructor TNeedle.Create(AOwner: TCollection);
begin
inherited Create(AOwner);
Self.fOwner:= AOwner.Owner;
Self.fTickMarks:= TTickMarks.Create(TNeedle(AOwner).fOwner);
Self.fPicture:= TPicture.Create;
Self.fHotspots:= THotspots.Create;
Self.fLength:= 50;
Self.fWidth:= 3;
Self.fMin:= 0;
Self.fMax:= 100;
Self.fDegreeStart:= 0;
Self.fDegreeStop:= 360;
Self.fColor:= clBlue;
Self.fTransparentColor:= clRed;
Self.fPosition:= 0;
Self.fCanClick:= False;
Self.fSizing:= gnsAuto;
Self.fPassMax:= False;
Self.fVisible:= True;
Self.DoEvent;
end;
destructor TNeedle.Destroy;
begin
if assigned(Self.fPicture) then Self.fPicture.Free;
if assigned(Self.fHotspots) then Self.fHotspots.Free;
if assigned(fTickMarks) then fTickMarks.Free;
inherited Destroy;
end;
procedure TNeedle.SetPicture(Value: TPicture);
begin
fPicture.Assign(Value);
Self.DoEvent;
end;
procedure TNeedle.SetLength(Value: Integer);
begin
fLength:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetWidth(Value: Integer);
begin
fWidth:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetColor(Value: TColor);
begin
fColor:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetTransparentColor(Value: TColor);
begin
fTransparentColor:= Value;
Self.DoEvent;
end;
procedure TNeedle.DoEvent;
begin
TJDNeedleGauge(Self.fOwner).DoRefresh(False);
if assigned(Self.fEvent) then Self.fEvent(Self);
end;
procedure TNeedle.SetStyle(Value: TJDGNeedleStyle);
begin
Self.fStyle:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetCursor(Value: TCursor);
begin
Self.fCursor:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetPosition(Value: Integer);
begin
Self.fPosition:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetMin(Value: Integer);
begin
Self.fMin:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetMax(Value: Integer);
begin
Self.fMax:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetDegreeStart(Value: Integer);
begin
Self.fDegreeStart:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetDegreeStop(Value: Integer);
begin
Self.fDegreeStop:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetTickMarks(Value: TTickMarks);
begin
Self.fTickMarks:= TTickMarks(Value);
Self.DoEvent;
end;
procedure TNeedle.SetSizing(Value: TJDGNeedleSizing);
begin
fSizing:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetPassMax(Value: Bool);
begin
fPassMax:= Value;
Self.DoEvent;
end;
procedure TNeedle.SetVisible(Value: Bool);
begin
Self.fVisible:= Value;
Self.DoEvent;
end;
function TNeedle.GetDisplayName: String;
begin
Result:= 'Needle #'+IntToStr(Self.Index);
end;
procedure TNeedle.SetIndex(Value: Integer);
begin
inherited;
Self.DoEvent;
end;
procedure TNeedle.DoRedraw;
begin
if assigned(Self.fRedraw) then Self.fRedraw(Self);
end;
procedure TNeedle.TickEvent(Sender: TObject);
begin
if assigned(fEvent) then fEvent(Self);
end;
procedure TNeedle.TickRedraw(Sender: TObject);
begin
if assigned(fRedraw) then fRedraw(Self);
end;
{ TTickMarks }
constructor TTickMarks.Create(AOwner: TPersistent);
begin
inherited Create(TTickMark);
fOwner:= TJDNeedleGauge(AOwner);
end;
function TTickMarks.GetOwner: TPersistent;
begin
Result:= inherited GetOwner;
end;
function TTickMarks.Add: TTickMark;
begin
Result:= Inherited Add as TTickMark;
if assigned(Result) then begin
Result.fOwner:= TJDNeedleGauge(Self.fOwner);
Result.OnEvent:= Self.GaugeEvent;
Result.OnRedraw:= Self.GaugeRedraw;
Self.GaugeEvent(Self);
end;
end;
procedure TTickMarks.GaugeEvent(Sender: TObject);
begin
if assigned(fEvent) then fEvent(Self);
end;
function TTickMarks.GetItems(Index: Integer): TTickMark;
begin
Result:= TTickMark(Inherited GetItem(Index));
end;
procedure TTickMarks.SetItems(Index: Integer; Value: TTickMark);
begin
Inherited SetItem(Index, Value);
end;
procedure TTickMarks.GaugeRedraw(Sender: TObject);
begin
if assigned(fRedraw) then fRedraw(Self);
end;
{ TTickMark }
constructor TTickMark.Create(AOwner: TCollection);
begin
inherited Create(AOwner);
Self.fHotspots:= THotspots.Create;
Self.fIncrement:= 10;
Self.fSize:= 5;
Self.fColor:= clGray;
Self.fCanClick:= False;
Self.fVisible:= True;
end;
destructor TTickMark.Destroy;
begin
if assigned(fHotspots) then fHotspots.Free;
inherited Destroy;
end;
procedure TTickMark.SetIncrement(Value: Integer);
begin
Self.fIncrement:= Value;
Self.DoRedraw;
end;
procedure TTickMark.SetSize(Value: Integer);
begin
Self.fSize:= Value;
Self.DoRedraw;
end;
procedure TTickMark.SetColor(Value: TColor);
begin
Self.fColor:= Value;
Self.DoRedraw;
end;
procedure TTickMark.SetCanClick(Value: Bool);
begin
Self.fCanClick:= Value;
Self.DoRedraw;
end;
procedure TTickMark.DoEvent;
begin
if assigned(Self.fEvent) then Self.fEvent(Self);
end;
procedure TTickMark.Assign(Source: TPersistent);
begin
inherited Assign(TPersistent(Source));
end;
procedure TTickMark.DoRedraw;
begin
if assigned(Self.fRedraw) then Self.fRedraw(Self);
end;
procedure TTickMark.SetVisible(Value: Bool);
begin
fVisible:= Value;
Self.DoRedraw;
end;
function TTickMark.GetDisplayName: String;
begin
Result:= 'Tick Marks #'+IntToStr(Self.Index);
end;
{ TJDNeedleGauge }
const
BitmapPixelFormat = pf32bit;
constructor TJDNeedleGauge.Create(AOwner: TComponent);
var
N: TNeedle;
T: TTickMark;
begin
inherited Create(AOwner);
//if (assigned(AOwner)) and (AOwner <> nil) then
Self.Parent:= TWinControl(AOwner);
fPicture:= TPicture.Create;
fBmp:= TBitmap.Create;
fBmp.PixelFormat:= BitmapPixelFormat;
fBmp.TransparentColor:= clFuchsia;
fBmp.Transparent:= True;
fBackground:= TBitmap.Create;
fBackground.PixelFormat:= BitmapPixelFormat;
fBackground.TransparentColor:= clFuchsia;
fBackground.Transparent:= True;
Self.fNeedles:= TNeedles.Create(Self);
fNeedles.fOwner:= TJDNeedleGauge(Self);
fNeedles.OnEvent:= Self.OnNeedleEvent;
fNeedles.OnRedraw:= Self.OnNeedleRedraw;
Self.Width:= 200;
Self.Height:= 200;
Self.fBackColor:= clBlack;
Self.fForeColor:= clNavy;
Self.fFadeStep:= 1;
Self.OnMouseDown:= Self.MouseDown;
Self.OnMouseUp:= Self.MouseUp;
Self.OnMouseMove:= Self.MouseMove;
N:= TNeedle(fNeedles.Add);
N.Min:= 0;
N.Max:= 100;
N.Position:= 0;
T:= TTickMark(N.TickMarks.Add);
Self.DoRefresh(True);
end;
destructor TJDNeedleGauge.Destroy;
begin
if assigned(fNeedles) then fNeedles.Free;
if assigned(fBmp) then fBmp.Free;
if assigned(fBackground) then fBackground.Free;
if assigned(fPicture) then fPicture.Free;
inherited Destroy;
end;
procedure TJDNeedleGauge.DoRefresh(DrawBackground: Bool);
begin
//Refresh entire gauge
if DrawBackground then begin
CreateBackground;
DrawScale;
end;
DisplayGauge;
end;
procedure TJDNeedleGauge.DisplayGauge;
begin
if fBmp.Width <> Width then
fBmp.Width:= Width;
if fBmp.Height <> Height then
fBmp.Height:= Height;
fBmp.Canvas.Brush.Color:= Self.fBackColor;
fBmp.Canvas.FillRect(Rect(0,0,Width,Height));//clFuchsia
fBmp.Canvas.Draw(0,0,fBackground);
DrawNeedles;
if Self.fShowCenter then DrawCenter;
Canvas.Draw(0,0,fBmp);
end;
procedure TJDNeedleGauge.CreateBackground;
var
R, G, B, TR, TG, TB: Integer;
W, H, Sz, L, S, X: Integer;
Count: Integer;
Stop: Single;
begin
//Create background image (fBackground)
W:= Self.Width;
H:= Self.Height;
if W > H then Sz:= H else Sz:= W;
fBackground.Width:= Sz;
fBackground.Height:= Sz;
fBackground.Canvas.Pen.Width:= 1;
fBackground.Canvas.Brush.Color:= fBackColor;
fBackground.Canvas.Pen.Color:= fBackColor;
fBackground.Canvas.FillRect(Rect(0,0,W,H));
if Self.fDoFade then begin
L:= IntRange(Trunc((Sz / 2) - 1), 1, 1000); //Radius
R:= ( fForeColor and $ff); //Red
G:= ((fForeColor and $ff00) shr 8); //Green
B:= ((fForeColor and $ff0000) shr 16); //Blue
Count:= 0; //Set count to 0
Stop:= L / fFadeStep;
fBackground.Canvas.Brush.Color:= fForeColor;
fBackground.Canvas.Pen.Color:= fForeColor;
for X:= 0 to L do begin
if (Count * fFadeStep) >= Stop then begin
Count:= 0;
S:= Trunc((X / L) * 70);
TR:= IntRange(R + S, 0, 255);
TG:= IntRange(G + S, 0, 255);
TB:= IntRange(B + S, 0, 255);
fBackground.Canvas.Brush.Color:= RGB(TR,TG,TB);
fBackground.Canvas.Pen.Color:= RGB(TR,TG,TB);
fBackground.Canvas.Ellipse(5 + X, 5 + X, Sz - 5 - X, Sz - 5 - X);
end else begin
Count:= Count + 1;
end;
end;
end else begin
fBackground.Canvas.Brush.Color:= fForeColor;
fBackground.Canvas.Pen.Color:= fForeColor;
fBackground.Canvas.Ellipse(5, 5, Sz - 5, Sz - 5);
end;
Self.DrawScale;
end;
procedure TJDNeedleGauge.DrawScale;
var
Center, NewPos: TPoint;
D, G, C: Single;
X, Y, Z, Sz, SSize, LSize, TickCount, I, J: Integer;
N: TNeedle;
T: TTickMark;
H: THotspot;
begin
//Draw scale around circle (fScale)
if Width >= Height then Sz:= Height else Sz:= Width;
Center.X:= Sz div 2;
Center.Y:= Sz div 2;
for I:= 0 to fNeedles.Count - 1 do begin
N:= fNeedles.Items[I];
for J:= 0 to N.fTickMarks.Count - 1 do begin
T:= TTickMark(N.fTickMarks.Items[J]);
T.fHotspots.Clear;
TickCount:= (N.fMax - N.fMin) div T.fIncrement;
D:= (Sz / 3) - (T.Size / 2) - 1;
G:= N.fDegreeStart;
fBackground.Canvas.Pen.Color:= T.Color;
fBackground.Canvas.Pen.Style:= psSolid;
fBackground.Canvas.Pen.Width:= T.Size;
if TickCount = 0 then TickCount:= 1;
C:= (N.DegreeStop - N.DegreeStart) / TickCount;
for Z:= 0 to TickCount do begin
NewPos:= NewPosition(Center, Trunc(D), Trunc(G));
fBackground.Canvas.Ellipse(
NewPos.X - (T.fSize div 2),
NewPos.Y - (T.fSize div 2),
NewPos.X + (T.fSize div 2) + 1,
NewPos.Y + (T.fSize div 2) + 1);
if T.fCanClick then begin
for X:= (NewPos.X - (T.fSize div 2)) to (NewPos.X + (T.fSize div 2)) do begin
for Y:= (NewPos.Y - (T.fSize div 2)) to (NewPos.Y + (T.fSize div 2)) do begin
H.Point:= Point(X,Y);
H.Size:= 1;
H.Active:= True;
H.Value:= IntToStr(Z);
T.fHotspots.Hotspot[Point(X,Y)]:= H;
end;
end;
end;
G:= G + C;
end;
end;
end;
end;
procedure TJDNeedleGauge.DrawNeedles;
var
X: Integer;
begin
for X:= 0 to fNeedles.Count - 1 do begin
if fNeedles.Items[X].fVisible then
DrawNeedle(fNeedles.Items[X]);
end;
end;
procedure TJDNeedleGauge.DrawNeedle(ANeedle: TNeedle);
var
Center, NewPos, P: TPoint;
C: Single;
Sz, Deg, L, X, Y, Z, TP: Integer;
N: TBitmap;
H: THotspot;
begin
//Draw needle pointing in proper position (fBmp)
if Self.Width >= Self.Height then Sz:= Self.Height else Sz:= Self.Width;
Center.X:= Sz div 2;
Center.Y:= Sz div 2;
if ANeedle.fPassMax then begin
TP:= ANeedle.fPosition;
end else begin
if ANeedle.fPosition > ANeedle.fMax then
TP:= ANeedle.fMax
else
TP:= ANeedle.fPosition;
end;
Deg:= Trunc((ANeedle.fDegreeStop - ANeedle.fDegreeStart) *
(TP / (ANeedle.fMax - ANeedle.fMin)));
C:= (ANeedle.DegreeStop - ANeedle.DegreeStart);
case ANeedle.fSizing of
gnsAuto: begin
L:= Trunc((Sz / 3) - 10);
end;
gnsPixels: begin
L:= ANeedle.fLength;
end;
gnsPercent: begin
L:= Trunc((Sz / 3) - (Sz * ANeedle.Length));
end;
end;
NewPos:= NewPosition(Center, L, Deg);
fBmp.Canvas.Pen.Width:= ANeedle.fWidth;
fBmp.Canvas.Pen.Color:= ANeedle.fColor;
case ANeedle.fStyle of
gnsLine: begin
//Draw actual line
fBmp.Canvas.MoveTo(Center.X, Center.Y);
fBmp.Canvas.LineTo(NewPos.X, NewPos.Y);
//Create hotspots (Low Performance - Need to tweak)
if ANeedle.fCanClick then begin
ANeedle.fHotspots.Clear;
for Z:= 0 to L - 1 do begin
P:= NewPosition(Center, Z, Deg);
for X:= P.X - (ANeedle.Width div 2) to
P.X + (ANeedle.Width div 2) do
begin
for Y:= P.Y - (ANeedle.Width div 2) to
P.Y + (ANeedle.Width div 2) do
begin
H.Point:= Point(X,Y);
H.Size:= ANeedle.fWidth;
H.Active:= True;
H.Value:= IntToStr(Z);
ANeedle.fHotspots.Hotspot[Point(X,Y)]:= H;
end;
end;
end;
end;
end;
gnsImage: begin
if assigned(ANeedle.fPicture) then begin
N:= TBitmap.Create;
try
//Assign picture to bitmap
finally
N.Free;
end;
end;
end;
end;
end;
procedure TJDNeedleGauge.DrawCenter;
var
R, G, B, TR, TG, TB: Integer;
W, H, L, D, S, X: Integer;
Sz: Integer;
begin
W:= Self.Width;
H:= Self.Height;
if W > H then Sz:= H else Sz:= W;
//Create center piece image (fBmp)
L:= IntRange(Trunc((fCenterSize / 2) - 1), 1, 500);
R:= (fCenterColor and $ff);
G:= ((fCenterColor and $ff00) shr 8);
B:= ((fCenterColor and $ff0000) shr 16);
for X:= ((Sz div 2) - (fCenterSize div 2)) downto L do begin
S:= Trunc((X / L) * 70);
D:= L - X;
TR:= IntRange(R + S, 0, 255);
TG:= IntRange(G + S, 0, 255);
TB:= IntRange(B + S, 0, 255);
fBmp.Canvas.Brush.Color:= RGB(TR,TG,TB);
fBmp.Canvas.Pen.Color:= RGB(TR,TG,TB);
fBmp.Canvas.Ellipse(
(Sz div 2) - fCenterSize + 5 + X,
(Sz div 2) - fCenterSize + 5 + X,
fCenterSize - 5 - X,
fCenterSize - 5 - X);
end;
end;
procedure TJDNeedleGauge.Paint;
begin
inherited Paint;
DoRefresh(True);
end;
procedure TJDNeedleGauge.SetBackColor(Value: TColor);
begin
fBackColor:= Value;
DoRefresh(True);
end;
procedure TJDNeedleGauge.SetForeColor(Value: TColor);
begin
fForeColor:= Value;
DoRefresh(True);
end;
procedure TJDNeedleGauge.SetShowCenter(Value: Bool);
begin
Self.fShowCenter:= Value;
DoRefresh(False);
end;
procedure TJDNeedleGauge.SetCenterColor(Value: TColor);
begin
Self.fCenterColor:= Value;
if Self.fShowCenter then DoRefresh(False);
end;
procedure TJDNeedleGauge.SetCenterSize(Value: Integer);
begin
Self.fCenterSize:= Value;
if Self.fShowCenter then DoRefresh(False);
end;
procedure TJDNeedleGauge.SetLabelTop(Value: String);
begin
Self.fLabelTop:= Value;
Self.DoRefresh(True);
end;
procedure TJDNeedleGauge.SetLabelBottom(Value: String);
begin
Self.fLabelBottom:= Value;
Self.DoRefresh(True);
end;
procedure TJDNeedleGauge.SetFadeStep(Value: Single);
begin
Self.fFadeStep:= Value;
if Value < 0 then Value:= 1;
if Value > 800 then Value:= 800;
Self.DoRefresh(True);
end;
procedure TJDNeedleGauge.OnNeedleEvent(Sender: TObject);
begin
DoRefresh(False);
end;
procedure TJDNeedleGauge.OnNeedleRedraw(Sender: TObject);
begin
DoRefresh(True);
end;
procedure TJDNeedleGauge.MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
I: Integer;
N: TNeedle;
D: Bool;
begin
//Check for hotspots
D:= False;
for I:= 0 to fNeedles.Count - 1 do begin
N:= fNeedles.Items[I];
if N.fCanClick then begin
if N.fHotspots.InHotspot(Point(X,Y)).Active then begin
D:= True;
if assigned(Self.fNeedleMouseDown) then
Self.fNeedleMouseDown(Sender, Button, Shift, X, Y);
end;
end;
end;
if not D then
if assigned(Self.fMouseDown) then
Self.fMouseDown(Sender, Button, Shift, X, Y);
end;
procedure TJDNeedleGauge.MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
I: Integer;
N: TNeedle;
D: Bool;
begin
//Check for hotspots
D:= False;
for I:= 0 to fNeedles.Count - 1 do begin
N:= fNeedles.Items[I];
if N.fCanClick then begin
if N.fHotspots.InHotspot(Point(X,Y)).Active then begin
D:= True;
if assigned(Self.fNeedleMouseUp) then
Self.fNeedleMouseUp(Sender, Button, Shift, X, Y);
end;
end;
end;
if not D then
if assigned(Self.fMouseUp) then
Self.fMouseUp(Sender, Button, Shift, X, Y);
end;
procedure TJDNeedleGauge.MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
var
I: Integer;
N: TNeedle;
D: Bool;
begin
//Check for hotspots
D:= False;
for I:= 0 to fNeedles.Count - 1 do begin
N:= fNeedles.Items[I];
if N.fCanClick then begin
if N.fHotspots.InHotspot(Point(X,Y)).Active then begin
D:= True;
if assigned(Self.fNeedleMouseMove) then
Self.fNeedleMouseMove(Sender, Shift, X, Y);
end;
end;
end;
if not D then
if assigned(Self.fMouseMove) then
Self.fMouseMove(Sender, Shift, X, Y);
end;
procedure TJDNeedleGauge.NeedleMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if assigned(Self.fNeedleMouseDown) then
Self.fNeedleMouseDown(Sender, Button, Shift, X, Y);
end;
procedure TJDNeedleGauge.NeedleMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if assigned(Self.fNeedleMouseUp) then
Self.fNeedleMouseUp(Sender, Button, Shift, X, Y);
end;
procedure TJDNeedleGauge.NeedleMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
begin
if assigned(Self.fNeedleMouseMove) then
Self.fNeedleMouseMove(Sender, Shift, X, Y);
end;
procedure TJDNeedleGauge.SetDoFade(Value: Bool);
begin
Self.fDoFade:= Value;
Self.DoRefresh(True);
end;
end.