多年前写的时钟控件,发布出来,供大家参考。

先看效果:

C#时钟控件_System

首先,制作一个从UserControl继承的时钟控件,使用双缓冲绘制。由于是几年前的水平,一些代码写到了属性中,也懒得再改了,感兴趣的,可以改得更规范些。

//ClockControl.cs
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;namespace BrawDraw.Com.PhotoFrame.Net.PublicFunctions
{
public class ClockControl: UserControl
{
DateTime dt;
Pen pen = new Pen(Color.Black, 1);
Pen penSecond = new Pen(Color.Black, 6);
Brush brush = new SolidBrush(Color.Black);
Bitmap m_Bitmap = null;
Graphics g = null;
private Font ClockFont = new Font("Arial", 48, FontStyle.Bold); public ClockControl()
{
SetStyle(ControlStyles.UserPaint | ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw, true); this.UpdateStyles();
Enabled = false;
m_Bitmap = new Bitmap(100, 100);
} public DateTime Time
{
get
{
return dt;
}
set
{
m_Bitmap = new Bitmap(this.ClientRectangle.Width, this.ClientRectangle.Height); g = Graphics.FromImage(m_Bitmap);
g.Clear(Color.White);
InitializeCoordinates(g); DrawDots(g, brush);
DrawHourHand(g, pen);
DrawMinuteHand(g, pen);
DrawNumbers(g); // DrawSecondHand(g, pen);
// if(g != null) g.Dispose();
if (dt.Hour != value.Hour)
{
DrawHourHand(g, pen);
}
if (dt.Minute != value.Minute)
{
DrawHourHand(g, pen);
DrawMinuteHand(g, pen);
}
if (dt.Second != value.Second)
{
DrawMinuteHand(g, pen);
DrawSecondHand(g, pen);
}
if (dt.Millisecond != value.Millisecond)
{
DrawSecondHand(g, pen);
}
dt = value;

Graphics grfx = CreateGraphics();
grfx.DrawImage(m_Bitmap, 0, 0);
this.Validate();
if(grfx != null) grfx.Dispose();
}
} protected override void OnPaint(PaintEventArgs pea)
{
g = pea.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
DrawClock(g); base.OnPaint (pea);
} private void DrawClock(Graphics gg)
{
m_Bitmap = new Bitmap(this.Width, this.Height);
Graphics grfx = Graphics.FromImage(m_Bitmap);
grfx.Clear(Color.White);
InitializeCoordinates(grfx);
DrawDots(grfx, brush);
DrawHourHand(grfx, pen);
DrawMinuteHand(grfx, pen);
DrawSecondHand(grfx, pen);
DrawNumbers(grfx); gg.DrawImage(m_Bitmap, 0, 0);
grfx.Dispose();
} void InitializeCoordinates(Graphics grfx)
{
if (Width == 0 || Height == 0) return; grfx.TranslateTransform(Width / 2, Height / 2);
float fInches = Math.Min(Width / grfx.DpiX, Height / grfx.DpiY);
grfx.ScaleTransform(fInches * grfx.DpiX / 2000,
fInches * grfx.DpiY / 2000);
} void DrawDots(Graphics grfx, Brush brush)
{
for (int i = 0; i < 60; i++)
{
int iSize = i % 5 == 0 ? 100 : 30; grfx.FillEllipse(brush, 0 - iSize / 2, - 860 - iSize / 2, iSize, iSize);
grfx.RotateTransform(6);
}
} protected virtual void DrawHourHand(Graphics grfx, Pen pen)
{
GraphicsState gs = grfx.Save();
grfx.RotateTransform(360f * Time.Hour / 12 + 30f * Time.Minute / 60 + 2); grfx.DrawPolygon(pen, new Point[]
{
new Point(0, 150), new Point( 100, 0),
new Point(0, -600), new Point(-100, 0)
});
grfx.Restore(gs);
} protected virtual void DrawMinuteHand(Graphics grfx, Pen pen)
{
GraphicsState gs = grfx.Save();
grfx.RotateTransform(360f * Time.Minute / 60 +
6f * Time.Second / 60 + 2); grfx.DrawPolygon(pen, new Point[]
{
new Point(0, 200), new Point( 50, 0),
new Point(0, -800), new Point(-50, 0)
});
grfx.Restore(gs);
} protected virtual void DrawSecondHand(Graphics grfx, Pen pen)
{
GraphicsState gs = grfx.Save();
grfx.RotateTransform(360f * Time.Second / 60 + 6f * Time.Millisecond / 1000 + 2.8f); grfx.DrawLine(penSecond, 0, 0, 0, -800);
grfx.Restore(gs);
} private void InitializeComponent()
{
//
// ClockControl
//
this.Name = "ClockControl";
this.Size = new System.Drawing.Size(416, 424); }
protected void DrawNumbers(Graphics grfx)
{
int count = 1;
int r = 1900;
int dx = 25;
int dy = 20;
int offset = 8;
int dr = 300;
GraphicsState gs = grfx.Save();
grfx.TranslateTransform(- r/2 - dx, - r/2 - dy); grfx.DrawEllipse(new Pen(Color.Black, 10), dx / 2 + offset, dy / 2 + offset, r + dx - offset, r + dy - offset);
//grfx.DrawEllipse(new Pen(Color.Black, 2), dx + offset, dy + offset, r - offset, r - offset); grfx.TranslateTransform(dr/3 + 15, dr/3 + 15);
for (double a = 0; a < 2 * Math.PI; a += (2.0* Math.PI/12))
{
double x = (r - dr * 1.2)/2 * Math.Cos(a - Math.PI/3) + (r - dr)/2 + 25;
double y = (r - dr * 1.2)/2 * Math.Sin(a - Math.PI/3)+ (r - dr)/2 + 20;
grfx.DrawString(Convert.ToString(count), ClockFont, Brushes.Black, (float)x,(float)y, new StringFormat());
count++;
}

grfx.Restore(gs);
//grfx.DrawLine(new Pen(Color.Black, 1), 0, -800, 0, 800);
}
}
}

接着再从BezierClockControl再从 ClockControl控件继承,由于绘制方式不同,因此最后显示的效果也不同:

C#时钟控件_System_02

//BezierClockControl.cs

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;namespace BrawDraw.Com.PhotoFrame.Net.PublicFunctions
{
public class BezierClockControl: ClockControl
{
protected override void DrawHourHand(Graphics grfx, Pen pen)
{
GraphicsState gs = grfx.Save();
grfx.RotateTransform(360f * Time.Hour / 12 +
30f * Time.Minute / 60);
GraphicsPath gp = new GraphicsPath();
Point[] points = new Point[]
{
new Point( 0, -600), new Point( 0, -300),
new Point(200, -300), new Point( 50, -200),
new Point( 50, -200), new Point( 50, 0),
new Point( 50, 0), new Point( 50, 75),
new Point(-50, 75), new Point( -50, 0),
new Point(-50, 0), new Point( -50, -200),
new Point(-50, -200), new Point(-200, -300),
new Point( 0, -300), new Point( 0, -600)
};
gp.AddBeziers(points);
//grfx.DrawBeziers(pen, points);
grfx.FillPath(new SolidBrush(Color.Red), gp);
grfx.Restore(gs);
gp.Dispose();
} private void InitializeComponent()
{
//
// BezierClockControl
//
this.Name = "BezierClockControl";
this.Size = new System.Drawing.Size(448, 376); }
protected override void DrawMinuteHand(Graphics grfx, Pen pen)
{
GraphicsState gs = grfx.Save();
grfx.RotateTransform(360f * Time.Minute / 60 +
6f * Time.Second / 60);
GraphicsPath gp = new GraphicsPath();
Point[] points = new Point[]
{
new Point( 0, -800), new Point( 0, -750),
new Point( 0, -700), new Point( 25, -600),
new Point( 25, -600), new Point( 25, 0),
new Point( 25, 0), new Point( 25, 50),
new Point(-25, 50), new Point( -25, 0),
new Point(-25, 0), new Point( -25, -600),
new Point(-25, -600), new Point( 0, -700),
new Point( 0, -750), new Point( 0, -800)
};
gp.AddBeziers(points);
grfx.FillPath(new SolidBrush(Color.Green), gp);
//grfx.DrawBeziers(pen, points);
grfx.Restore(gs);
gp.Dispose();
}
}
}

 

最后,我们来测试一下:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;namespace BrawDraw.Com.PhotoFrame.Net.PublicFunctions
{
/// <summary>
/// BezierClock 的摘要说明。
/// </summary>
public class BezierClock : System.Windows.Forms.Form
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
//ClockControl clkctl;
BezierClockControl clkctl; public BezierClock()
{
InitializeComponent();
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true); Text = "Bezier Clock";
//clkctl = new ClockControl();
clkctl = new BezierClockControl(); clkctl.Parent = this;
clkctl.Time = DateTime.Now;
clkctl.Dock = DockStyle.Fill;
clkctl.BackColor = Color.Black;
clkctl.ForeColor = Color.White; Timer timer = new Timer();
timer.Interval = 1000;
timer.Tick += new EventHandler(OnTimerTick);
timer.Start();
} void OnTimerTick(object obj, EventArgs ea)
{
clkctl.Time = DateTime.Now;
}

/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
} #region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
//
// BezierClock
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(432, 421);
this.Name = "BezierClock";
this.Text = "BezierClock"; }
#endregion /// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new BezierClock());
}
}
}