This is a Graphical Timer control I made for C# Winforms, which taught me quite a bit (it is my first Custom Control). The code below is a fully working application with the Graphical Timer, some buttons to control it, and a listbox showing the sweeping angle of the pie (for debugging purposes). Being my first control I have no idea how messy the code is, if it conforms to guidelines, etc. Hopefully I will get some good feedback about improvements that can be made, but other than that, it works perfectly in all my tests!
using System;
using System.Drawing;
using System.Windows.Forms;
namespace TestCustomControl
{
class GraphicalTimer : Control
{
public event EventHandler Timeout;
public Color TimerBack { get; set; }
public Color TimerFront { get; set; }
private Color TimerEmptying { get; set; }
public Color TimerFull { get; set; }
public Color TimerHalfEmpty { get; set; }
public Color TimerQuarterEmpty { get; set; }
public Color BorderColor { get; set; }
private Timer t;
public int MaxTime { get; set; }
public bool AutoReset { get; set; }
private int timeElapsed = 0;
public GraphicalTimer()
{
DoubleBuffered = true;
//Default values for properties
TimerBack = Color.White;
TimerFront = Color.Black;
TimerEmptying = Color.LightGreen;
TimerFull = Color.LightGreen;
TimerHalfEmpty = Color.Orange;
TimerQuarterEmpty = Color.Red;
BorderColor = Color.Black;
MaxTime = 60;
AutoReset = true;
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
BackColor = Color.Transparent;
t = new Timer();
t.Interval = 1000;
t.Tick += t_Tick;
}
protected virtual void OnTimeout(EventArgs e)
{
if (Timeout != null)
Timeout(this, e);
}
public void Start()
{
t.Start();
}
public void Stop()
{
t.Stop();
}
public void Reset()
{
timeElapsed = 0;
Invalidate();
}
void t_Tick(object sender, EventArgs e)
{
timeElapsed += 1;
if (timeElapsed >= MaxTime*0.75)
{
TimerEmptying = TimerQuarterEmpty;
}
else if (timeElapsed >= MaxTime * 0.5)
{
TimerEmptying = TimerHalfEmpty;
}
else
{
TimerEmptying = TimerFull;
}
if (timeElapsed == MaxTime)
{
t.Dispose();
}
Invalidate();
if (timeElapsed == MaxTime)
{
OnTimeout(new EventArgs());
if (AutoReset)
Reset();
}
}
private float getAngleFromTime()
{
if (timeElapsed == 0)
{
return 0;
}
else
{
MainWindow.lb.Items.Add((360.0 / ((float)MaxTime / (float)timeElapsed)).ToString());
return ((360 * timeElapsed) / MaxTime);
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
Rectangle rc = ClientRectangle;
g.FillEllipse(new SolidBrush(TimerBack), (int)rc.Left + 5, (int)rc.Top + 5, (int)rc.Width - 10, (int)rc.Height - 10);
g.FillPie(new SolidBrush(TimerEmptying), (int)rc.Left + 5, (int)rc.Top + 5, (int)rc.Width - 10, (int)rc.Height - 10, -90, getAngleFromTime());
g.DrawEllipse(new Pen(BorderColor, 4), (int)rc.Left + 5, (int)rc.Top + 5, (int)rc.Width - 10, (int)rc.Height - 10);
Font font = new Font("Arial", (float)rc.Height * 0.4f, FontStyle.Bold, GraphicsUnit.Pixel);
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
g.DrawString((MaxTime - timeElapsed).ToString("D2"), font, new SolidBrush(TimerFront), ClientRectangle, sf);
}
}
class MainWindow : Form
{
GraphicalTimer gt;
Button startButton;
Button stopButton;
Button resetButton;
Button setButton;
TextBox timerValue;
public static ListBox lb;
public MainWindow()
{
this.Text = "Test Application";
gt = new GraphicalTimer();
gt.MaxTime = 30;
gt.Top = 10;
gt.Left = 10;
gt.Width = 50;
gt.Height = 50;
gt.AutoReset = false;
gt.Timeout += gt_Timeout;
this.Controls.Add(gt);
startButton = new Button();
startButton.Top = 10;
startButton.Left = gt.Right + 10;
startButton.AutoSize = true;
startButton.Text = "Start Timer";
startButton.Click += startButton_Click;
this.Controls.Add(startButton);
stopButton = new Button();
stopButton.Top = 10;
stopButton.Left = startButton.Right + 10;
stopButton.AutoSize = true;
stopButton.Text = "Stop Timer";
stopButton.Click += stopButton_Click;
this.Controls.Add(stopButton);
resetButton = new Button();
resetButton.Top = startButton.Bottom + 10;
resetButton.Left = gt.Right + 10;
resetButton.AutoSize = true;
resetButton.Text = "Reset Timer";
resetButton.Click += resetButton_Click;
this.Controls.Add(resetButton);
timerValue = new TextBox();
timerValue.Top = startButton.Bottom + 10;
timerValue.Left = resetButton.Right + 10;
timerValue.Font = new Font("arial", 12);
timerValue.Width = (stopButton.Width / 2);
this.Controls.Add(timerValue);
setButton = new Button();
setButton.Top = stopButton.Bottom + 10;
setButton.Left = timerValue.Right + 10;
setButton.Text = "Set";
setButton.Click += setButton_Click;
this.Controls.Add(setButton);
lb = new ListBox();
lb.Top = resetButton.Bottom + 10;
lb.Left = 10;
lb.Width = this.ClientSize.Width - 20;
lb.Height = this.ClientSize.Height - lb.Top - 10;
this.Controls.Add(lb);
}
void gt_Timeout(object sender, EventArgs e)
{
MessageBox.Show("Time has run out");
}
void setButton_Click(object sender, EventArgs e)
{
gt.MaxTime = int.Parse(timerValue.Text);
}
void resetButton_Click(object sender, EventArgs e)
{
gt.Reset();
}
void stopButton_Click(object sender, EventArgs e)
{
gt.Stop();
}
void startButton_Click(object sender, EventArgs e)
{
gt.Start();
}
}
class StartClass
{
static void Main()
{
MainWindow form = new MainWindow();
Application.EnableVisualStyles();
Application.Run(form);
}
}
}