/*
Code revised from chapter 4
GDI+ Custom Controls with Visual C# 2005
By Iulian Serban, Dragos Brezoi, Tiberiu Radu, Adam Ward
Language English
Paperback 272 pages [191mm x 235mm]
Release date July 2006
ISBN 1904811604
Sample chapter
http://www.packtpub.com/files/1604_CustomControls_SampleChapter.pdf
For More info on GDI+ Custom Control with Microsoft Visual C# book
visit website www.packtpub.com
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
namespace ClockTest00
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.clock1 = new ClockTest00.Clock();
this.SuspendLayout();
//
// clock1
//
this.clock1.BackColor = System.Drawing.SystemColors.ControlLightLight;
this.clock1.HourColor = System.Drawing.Color.Black;
this.clock1.Location = new System.Drawing.Point(67, 49);
this.clock1.MinuteColor = System.Drawing.Color.Black;
this.clock1.Name = "clock1";
this.clock1.SecondColor = System.Drawing.Color.Black;
this.clock1.Size = new System.Drawing.Size(150, 150);
this.clock1.TabIndex = 0;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.clock1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private Clock clock1;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public partial class Clock : UserControl
{
public Clock()
{
//Sets the rendering mode of the control to double buffer to stop flickering
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
InitializeComponent();
//Enables the timer so the clock refreshes every second
timer.Enabled = true;
MakeRound();
}
private Color hourColor = Color.Black;
private Color minuteColor = Color.Black;
private Color secondColor = Color.Black;
public Color HourColor
{
get
{
return hourColor;
}
set
{
if (hourColor != value)
{
hourColor = value;
Invalidate();
}
}
}
public Color MinuteColor
{
get
{
return minuteColor;
}
set
{
if (minuteColor != value)
{
minuteColor = value;
Invalidate();
}
}
}
public Color SecondColor
{
get
{
return secondColor;
}
set
{
if (secondColor != value)
{
secondColor = value;
Invalidate();
}
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
//Smooths out the appearance of the control
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
//The center of the control, that is used as center for the clock
PointF center = new PointF(this.Width / 2, this.Height / 2);
//The distace of the text from the center
float textRadius = (Math.Min(Width, Height) - Font.Height) / 2;
//The distance of the margin points from the center
float outerRadius = Math.Min(Width, Height) / 2 - Font.Height;
//The length of the hour line
float hourRadius = outerRadius * 6 / 9;
//The length of the minute line
float minuteRadius = outerRadius * 7 / 9;
//The length of the second line
float secondRadius = outerRadius * 8 / 9;
for (int i = 1; i <= 60; i++)
{
//Gets the angle of the outer dot
float angle = GetAngle(i / 5f, 12);
//Gets the location of the outer dot
PointF dotPoint = GetPoint(center, outerRadius, angle);
//Indicates the size of the point
int pointSize = 2;
//Is true when a large dot needs to be rendered
if (i % 5 == 0)
{
//Sets the size of the point to make it bigger
pointSize = 4;
//The hour number
string text = (i / 5).ToString();
SizeF sz = e.Graphics.MeasureString(text, Font);
//The point where the text should be rendered
PointF textPoint = GetPoint(center, textRadius, angle);
//Offsets the text location so it is centered in that point.
textPoint.X -= sz.Width / 2;
textPoint.Y -= sz.Height / 2;
//Draws the hour number
e.Graphics.DrawString(text, Font, new SolidBrush(this.ForeColor), textPoint);
}
Pen pen = new Pen(new SolidBrush(this.ForeColor), 1);
//Draws the outer dot of the clock
e.Graphics.DrawEllipse(pen, dotPoint.X - pointSize / 2, dotPoint.Y - pointSize / 2, pointSize, pointSize);
pen.Dispose();
}
//Gets the system time
DateTime dt = DateTime.Now;
//Calculates the hour offset from the large outer dot
float min = ((float)dt.Minute) / 60;
//Calculates the angle of the hour line
float hourAngle = GetAngle(dt.Hour + min, 12);
//Calculates the angle of the minute line
float minuteAngle = GetAngle(dt.Minute, 60);
//Calculates the angle of the second line
float secondAngle = GetAngle(dt.Second, 60);
//Draws the clock lines
DrawLine(e.Graphics, this.secondColor, 1, center, secondRadius, secondAngle);
DrawLine(e.Graphics, this.minuteColor, 2, center, minuteRadius, minuteAngle);
DrawLine(e.Graphics, this.hourColor, 3, center, hourRadius, hourAngle);
e.Graphics.ResetTransform();
}
private PointF GetPoint(PointF center, float radius, float angle)
{
//Calculates the X coordinate of the point
float x = (float)Math.Cos(2 * Math.PI * angle / 360) * radius + center.X;
//Calculates the Y coordinate of the point
float y = -(float)Math.Sin(2 * Math.PI * angle / 360) * radius + center.Y;
return new PointF(x, y);
}
private void DrawLine(Graphics g, Color color, int penWidth, PointF center, float radius, float angle)
{
//Calculates the end point of the line
PointF endPoint = GetPoint(center, radius, angle);
//Creates the pen used to render the line
Pen pen = new Pen(new SolidBrush(color), penWidth);
//Renders the line
g.DrawLine(pen, center, endPoint);
pen.Dispose();
}
private void MakeRound()
{
GraphicsPath gp = new GraphicsPath();
float min = Math.Min(Width, Height);
//Creates the ellipse shape
gp.AddEllipse((Width - min) / 2, (Height - min) / 2, min, min);
//Creates the ellipse region
Region rgn = new Region(gp);
//Sets the ellipse region to the control
this.Region = rgn;
}
private float GetAngle(float clockValue, float divisions)
{
//Calculates the angle
return 360 - (360 * (clockValue) / divisions) + 90;
}
private void timer_Tick(object sender, EventArgs e)
{
Invalidate();
}
private void Clock_SizeChanged(object sender, EventArgs e)
{
MakeRound();
Invalidate();
}
private void Clock_Paint(object sender, PaintEventArgs e)
{
}
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// timer
//
this.timer.Interval = 1000;
this.timer.Tick += new System.EventHandler(this.timer_Tick);
//
// Clock
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Name = "Clock";
this.Paint += new System.Windows.Forms.PaintEventHandler(this.Clock_Paint);
this.SizeChanged += new System.EventHandler(this.Clock_SizeChanged);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Timer timer;
}
}