Solved

Help building a digital display timer with .net

Posted on 2008-06-25
28
474 Views
Last Modified: 2013-11-26
Experts I am trying to build an application that resembles a digital clock.  My first step was to see if I could find a digital font.  This would have been the easiest solution, as I could update a labels text.  I had no luck finding a font so my next step was to have a series of images from 0 to 9 that would change depending on the time I was passing.  This became cumbersum and not very efficent.  Finally I found this control, which makes use of the drawing class.  This looks to be exactly what I need, but instead of having a clock or timer, I want it to draw the numbers that I pass it.  The entire project is in C# so I am having a harder time following the code.  Here is the project http://www.codeproject.com/KB/selection/DigitalClockControl.aspx.  I dont have a lot of experience with the drawing class so I am not really sure what is going on.  I have included a code snippet of the class that handles the drawing, the project also includes a bitmap file called Digital that has a black background with a red eight, so I am not sure where that is being used.  Can anyone help me to understand what is going on and whether or not I can get this class to draw numbers that I pass it?


using System;
using System.Drawing;
using System.Drawing.Drawing2D;
 
namespace SriClocks
{
	// A digit class which can draw a number on a graphics surface
	internal sealed class DigitalDisplay
	{
		// pens used to draw the digits
		private static Pen pen = new Pen(Color.FromArgb(255,0,0));
		private static Pen dimPen = null;
 
		private float linewidth = 20.0F;
		private Point[] Points; // end point coordinates of lines in the digital display
 
		// for each digit the display bits are set into an int
		// 'A' and 'P' are included for AM and PM display in the clock
		private int[] displayNum = new int[12]{63,12,118,94,77,91,123,14,127,95,
												  111, // to display 'A'
												  103}; // to display 'P'
 
		// Rectangles in which colons are displayed
		private Rectangle colonRect1, colonRect2;
	
		// This function is called by the paint method to display the numbers
		// A set of bits in the 'displayNum' variable define which of the
		// display legs to display
		// Based on this the ones with a '1' are in bright color and the rest
		// with '0's are in a dull color giving the effect of a digital clock
		internal void Draw(int num,  // number to display
			Graphics g) // graphics object for drawing
		{
			int check; // used to check if a leg of digit should be bright or dull
 
			// although pens are global linewidths are specific to each instance
			pen.Width = dimPen.Width = linewidth;
 
			for (int i=0; i<7; i++)
			{
				check = (int)System.Math.Pow(2, i);
				if ((check & displayNum[num])==0)
					g.DrawLine(dimPen, Points[i*2], Points[i*2+1]);
				else
					g.DrawLine(pen, Points[i*2], Points[i*2+1]);
			}
		}
 
		static private void setDimPen()
		{
			if (dimPen == null) dimPen = (Pen)pen.Clone();
			dimPen.Width = pen.Width;
			dimPen.Color = Color.FromArgb(
				pen.Color.R > 0 ? 60:0,
				pen.Color.G > 0 ? 60:0,
				pen.Color.B > 0 ? 60:0);
		}
 
		static internal void SetPenColor(DigitalColor dclr)
		{
			pen.Color = Color.FromArgb(
				(dclr == DigitalColor.RedColor) ? 255:0 ,
				(dclr == DigitalColor.GreenColor) ? 255:0,
				(dclr == DigitalColor.BlueColor) ? 255:0);
			setDimPen();
		}
 
		// function that draws a colon in the middle of the rectangular panel
		// possible modes are circular or rectangular points in the colon
		internal void DrawColon(Graphics g, ColonType type, bool dim)
		{
			pen.Width = dimPen.Width = linewidth;
			Pen p = (dim) ? dimPen : pen; // choose a pen for blinking
			switch(type)
			{
				case ColonType.Circular:
					g.DrawEllipse(p, colonRect1);
					g.DrawEllipse(p, colonRect2);
					break;
				case ColonType.Rectangular:
					g.DrawRectangle(p, colonRect1);
					g.DrawRectangle(p, colonRect2);
					break;
			}
		}
 
		// Draws the complete rectangle in dim shade to give the digital effect :-)
		internal void Draw(Graphics g)
		{
			// althought pens are static, linewidths are specific to each instance
			dimPen.Width = linewidth;
			for (int i=0; i<7; i++)
				g.DrawLine(dimPen, Points[i*2], Points[i*2+1]);
		}
 
		// Overloaded function to display characters 'A' and 'P' for AM and PM
		// Using the same algorithm used to display numbers above
		internal void Draw(char ch, // character to display
						Graphics g) // graphics object for drawing
		{
			// 10 and 11 are indices of A and P in the displayNum array
			switch(Char.ToUpper(ch))
			{
				case 'A':
					Draw(10, g);
					break;
				case 'P':
					Draw(11, g);
					break;
			}
		}
 
		// Constructor takes a rectangle and prepares the end points
		// of the lines to be drawn for the clock
		internal DigitalDisplay(Rectangle rect)
		{
			pen.StartCap = LineCap.Triangle;
			pen.EndCap = LineCap.Triangle;
 
			Points = new Point[14]; // there are 7 lines in a display
			for (int i=0; i<14; i++)
				Points[i] = new Point(0,0);
			CalculateAllParameters(rect);
		}
 
		internal void CalculateAllParameters(Rectangle rect)
		{
			linewidth = (int)(rect.Width/5);
			if (linewidth < 2) linewidth = 2;
			if (linewidth > 20) linewidth = 20;
			pen.Width = linewidth;
			setDimPen();
 
			CalculateLineEnds(rect);
			CalculateColonRectangles(rect);
		}
 
		// Function calculates end points of lines to display
		// The draw function will draw lines using this data
		private void CalculateLineEnds(Rectangle rect)
		{
			// 0,1,2,9,10,11,12 points share the same left edge X coordinate
			Points[0].X = Points[1].X = Points[2].X = Points[9].X = 
				Points[10].X = Points[11].X = Points[12].X = rect.Left;
 
			// points 3,4,5,6,7,8,13 the right edge X coordinate
			Points[3].X = Points[4].X = Points[5].X = Points[6].X =
					Points[7].X = Points[8].X = Points[13].X= rect.Right-(int)linewidth;
 
			// Points 1,2,3,4 are the top most points
			Points[1].Y = Points[2].Y = Points[3].Y = Points[4].Y = (int)(rect.Top);
 
			// Points 0,11,12,13,5,6 are the middle points
			Points[0].Y = Points[11].Y = Points[12].Y = Points[13].Y =
						Points[5].Y = Points[6].Y = 
							rect.Top + (int)((rect.Height-linewidth)/2.0);
			// points 7,8,9,10 are on the bottom edge
			Points[7].Y = Points[8].Y = Points[9].Y = Points[10].Y 
							= rect.Top + (int)(rect.Height-linewidth);
 
			// now adjust the coordinates that were computed, to get the digital look
			AdjustCoordinates();
		}
	
		// This function is necessary to give the lines a digital clock look
		// Push the coordinates a little away so that they look apart
		private void AdjustCoordinates()
		{
			Point swap; // required in case points have to be swapped
			for (int i=0; i<7; i++)
			{
				// Always draw from left to right and top to bottom
				// Adjust the end points accordingly
				if (Points[i*2].X > Points[(i*2)+1].X || Points[i*2].Y > Points[(i*2)+1].Y)
				{
					swap = Points[i*2]; Points[i*2]= Points[(i*2)+1]; Points[(i*2)+1]=swap;
				}
 
				// for horizontal lines adjust the X coord
				if (Points[i*2].X != Points[(i*2)+1].X)
				{
					Points[i*2].X += (int)(linewidth/1.6);
					Points[(i*2)+1].X -= (int)(linewidth/1.6);
				}
				// for vertical lines adjust the y coord
				if (Points[i*2].Y != Points[(i*2)+1].Y)
				{
					Points[i*2].Y += (int)(linewidth/1.6);
					Points[(i*2)+1].Y -= (int)(linewidth/1.6);
				}
			}
		}
 
		// function to calculate the rectangles required to drawn colon dot inside
		private void CalculateColonRectangles(Rectangle rect)
		{
			colonRect1 = colonRect2 = rect;
			colonRect1.X = colonRect2.X = rect.X + (int)((rect.Width - linewidth)/2.0);
			colonRect1.Y = rect.Y + rect.Height/3;
			colonRect2.Y = rect.Y + (rect.Height*2)/3;
			colonRect1.Width = colonRect1.Height = 
				colonRect2.Width = colonRect2.Height = (int) linewidth;
		}
	}
}

Open in new window

0
Comment
Question by:tentavarious
  • 16
  • 12
28 Comments
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21866152
I am pretty sure there are other bits of code that are missing, since you don't have the definitions for the enums, however I have converted it over to VB so that maybe you can understand it better...

When you call the class, you pass in a Rectangle which is the area to be drawn upon.  The procedure then runs off and calculates all the various widths it needs in order to draw the characters at each of the 4 numeric points, plus the colon and AM/PM (A/P) points.

From what I can see in this class, you also need some code in the Paint event, which you don't have here so must be elsewhere in your example.
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
 
Namespace SriClocks
    ' A digit class which can draw a number on a graphics surface
    Public Enum DigitalColor
        RedColor
        GreenColor
        BlueColor
    End Enum
 
    Public Enum colonType
        Circular
        Rectangular
    End Enum
 
    Class DigitalDisplay
        ' pens used to draw the digits
        Shared pen As Pen = New Pen(Color.FromArgb(255, 0, 0))
        Shared dimPen As Pen = Nothing
 
        Private linewidth As Double = 20.0
        Private Points As Point() ' end point coordinates of lines in the digital display
 
        ' for each digit the display bits are set into an int
        ' 'A' and 'P' are included for AM and PM display in the clock
        Private displayNum As Integer() = {63, 12, 118, 94, 77, 91, 123, 14, 127, 95, 111, 103}
 
        ' Rectangles in which colons are displayed
        Private colonRect1, colonRect2 As Rectangle
 
        ' This function is called by the paint method to display the numbers
        ' A set of bits in the 'displayNum' variable define which of the
        ' display legs to display
        ' Based on this the ones with a '1' are in bright color and the rest
        ' with '0's are in a dull color giving the effect of a digital clock
        Private Sub Draw(ByVal num As Integer, ByVal g As Graphics)
            Dim check As Integer ' used to check if a leg of digit should be bright or dull
 
            ' although pens are global linewidths are specific to each instance
            pen.Width = dimPen.Width = linewidth
 
            For i As Integer = 0 To 6
                check = CType(System.Math.Pow(2, i), Integer)
                If ((check & displayNum(num)) = 0) Then
                    g.DrawLine(dimPen, Points(i * 2), Points(i * 2 + 1))
                Else
                    g.DrawLine(pen, Points(i * 2), Points(i * 2 + 1))
                End If
            Next
        End Sub
 
        Private Shared Sub setDimPen()
            If (dimPen Is Nothing) Then dimPen = CType(pen.Clone(), Pen)
            dimPen.Width = pen.Width
            dimPen.Color = Color.FromArgb( _
             IIf(pen.Color.R > 0, 60, 0), _
             IIf(pen.Color.G > 0, 60, 0), _
             IIf(pen.Color.B > 0, 60, 0))
        End Sub
 
        Private Shared Sub SetPenColor(ByVal dclr As DigitalColor)
            pen.Color = Color.FromArgb( _
             IIf(dclr = DigitalColor.RedColor, 255, 0), _
             IIf(dclr = DigitalColor.GreenColor, 255, 0), _
             IIf(dclr = DigitalColor.BlueColor, 255, 0))
            setDimPen()
        End Sub
 
        ' function that draws a colon in the middle of the rectangular panel
        ' possible modes are circular or rectangular points in the colon
        Private Sub DrawColon(ByVal g As Graphics, ByVal type As ColonType, ByVal bDim As Boolean)
            pen.Width = dimPen.Width = linewidth
            Dim p As Pen = IIf(bDim, dimPen, pen) ' choose a pen for blinking
            Select Case type
                Case ColonType.Circular
                    g.DrawEllipse(p, colonRect1)
                    g.DrawEllipse(p, colonRect2)
                Case ColonType.Rectangular
                    g.DrawRectangle(p, colonRect1)
                    g.DrawRectangle(p, colonRect2)
            End Select
        End Sub
 
        ' Draws the complete rectangle in dim shade to give the digital effect :-)
        Private Sub Draw(ByVal g As Graphics)
            ' althought pens are static, linewidths are specific to each instance
            dimPen.Width = linewidth
            For i As Integer = 0 To 6
                g.DrawLine(dimPen, Points(i * 2), Points(i * 2 + 1))
            Next
        End Sub
 
        ' Overloaded function to display characters 'A' and 'P' for AM and PM
        ' Using the same algorithm used to display numbers above
        Private Sub Draw(ByVal ch As Char, ByVal g As Graphics)
            ' 10 and 11 are indices of A and P in the displayNum array
            Select Case Char.ToUpper(ch)
                Case "A"
                    Draw(10, g)
                Case "P"
                    Draw(11, g)
            End Select
        End Sub
 
        ' Constructor takes a rectangle and prepares the end points
        ' of the lines to be drawn for the clock
        Sub DigitalDisplay(ByVal rect As Rectangle)
            pen.StartCap = LineCap.Triangle
            pen.EndCap = LineCap.Triangle
 
            ReDim Points(14) ' there are 7 lines in a display
            For i As Integer = 0 To 13
                Points(i) = New Point(0, 0)
            Next
            CalculateAllParameters(rect)
        End Sub
 
        Sub CalculateAllParameters(ByVal rect As Rectangle)
            linewidth = CType((rect.Width / 5), Integer)
            If (linewidth < 2) Then linewidth = 2
            If (linewidth > 20) Then linewidth = 20
 
            pen.Width = linewidth
            setDimPen()
 
            CalculateLineEnds(rect)
            CalculateColonRectangles(rect)
        End Sub
 
        ' Function calculates end points of lines to display
        ' The draw function will draw lines using this data
        Private Sub CalculateLineEnds(ByVal rect As Rectangle)
            ' 0,1,2,9,10,11,12 points share the same left edge X coordinate
            Points(0).X = rect.Left
            Points(1).X = Points(0).X
            Points(2).X = Points(0).X
            Points(9).X = Points(0).X
            Points(10).X = Points(0).X
            Points(11).X = Points(0).X
            Points(12).X = Points(0).X
 
            ' points 3,4,5,6,7,8,13 the right edge X coordinate
            Points(3).X = rect.Right - CType(linewidth, Integer)
            Points(4).X = Points(3).X
            Points(5).X = Points(3).X
            Points(6).X = Points(3).X
            Points(7).X = Points(3).X
            Points(8).X = Points(3).X
            Points(13).X = Points(3).X
 
            ' Points 1,2,3,4 are the top most points
            Points(1).Y = CType(rect.Top, Integer)
            Points(2).Y = Points(1).Y
            Points(3).Y = Points(1).Y
            Points(4).Y = Points(1).Y
 
            ' Points 0,11,12,13,5,6 are the middle points
            Points(0).Y = rect.Top + CType(((rect.Height - linewidth) / 2.0), Integer)
            Points(11).Y = Points(0).Y
            Points(12).Y = Points(0).Y
            Points(13).Y = Points(0).Y
            Points(5).Y = Points(0).Y
            Points(6).Y = Points(0).Y
 
            ' points 7,8,9,10 are on the bottom edge
            Points(7).Y = rect.Top + CType((rect.Height - linewidth), Integer)
            Points(8).Y = Points(7).Y
            Points(9).Y = Points(7).Y
            Points(10).Y = Points(7).Y
 
            ' now adjust the coordinates that were computed, to get the digital look
            AdjustCoordinates()
        End Sub
 
        ' This function is necessary to give the lines a digital clock look
        ' Push the coordinates a little away so that they look apart
        Private Sub AdjustCoordinates()
            Dim swap As Point  ' required in case points have to be swapped
            For i As Integer = 0 To 6
                ' Always draw from left to right and top to bottom
                ' Adjust the end points accordingly
                If (Points(i * 2).X > Points((i * 2) + 1).X Or Points(i * 2).Y > Points((i * 2) + 1).Y) Then
                    swap = Points(i * 2)
                    Points(i * 2) = Points((i * 2) + 1)
                    Points((i * 2) + 1) = swap
                End If
 
                ' for horizontal lines adjust the X coord
                If (Points(i * 2).X <> Points((i * 2) + 1).X) Then
                    Points(i * 2).X += CType((linewidth / 1.6), Integer)
                    Points((i * 2) + 1).X -= CType((linewidth / 1.6), Integer)
                End If
                ' for vertical lines adjust the y coord
                If (Points(i * 2).Y <> Points((i * 2) + 1).Y) Then
                    Points(i * 2).Y += CType((linewidth / 1.6), Integer)
                    Points((i * 2) + 1).Y -= CType((linewidth / 1.6), Integer)
                End If
            Next
        End Sub
 
        ' function to calculate the rectangles required to drawn colon dot inside
        Private Sub CalculateColonRectangles(ByVal rect As Rectangle)
            colonRect2 = rect
            colonRect1 = rect
            colonRect1.X = colonRect2.X = rect.X + CType(((rect.Width - linewidth) / 2.0), Integer)
            colonRect1.Y = rect.Y + rect.Height / 3
            colonRect2.Y = rect.Y + (rect.Height * 2) / 3
            colonRect1.Width = CType(linewidth, Integer)
            colonRect1.Height = CType(linewidth, Integer)
            colonRect2.Width = CType(linewidth, Integer)
            colonRect2.Height = CType(linewidth, Integer)
        End Sub
    End Class
End Namespace

Open in new window

0
 

Author Comment

by:tentavarious
ID: 21868447
I have included the usercontrols code that uses the above class as well as the bitmap.  I still dont know why the bitmap is needed because, I thought the class draws the numbers from scratch.  Anyway my goal is to pass the rectangle and the numbers that need to be drawn to this class.  So basically if I pass 08:00, that is what will be drawn.
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
 
namespace SriClocks
{
	public enum ColonType { Circular, Rectangular };
	public enum ClockType {DigitalClock, StopWatch, CountDown, Freeze };
	public enum DigitalColor {RedColor, BlueColor, GreenColor };
	// Clock format. For 12 hour format display 'A' (AM) or 'P' (PM)
	public enum ClockFormat { TwentyFourHourFormat, TwelveHourFormat };
 
	// DigitalClockCtrl is a control which displays a clock
	// Possible displays include a normal digital clock,
	//   a stop watch and a count down clock
	[ToolboxBitmap("Digital.bmp")]
	public class DigitalClockCtrl : System.Windows.Forms.UserControl
	{
		private System.ComponentModel.IContainer components;
 
		private Color digitsColor = Color.Red; // color of the digits displayed
		private Color countdownColor = Color.White; // background color after count down expires
		private ClockFormat clockDisplayFormat = ClockFormat.TwelveHourFormat;
 
		private DigitalDisplay[] DigitDisplay = null; // panels on which digits are displayed
		private DigitalDisplay[] ColonDisplay = null; // panels for displaying colons
		private DigitalDisplay AmPmDisplay = null; // panel for AM/PM display
		private DigitalDisplay MicroSecDisplay = null; // panel for displaying 1/10 of a second
 
		// ShowTimer to refresh the time display
		private System.Windows.Forms.Timer ShowTimer;
		// ColonTimer to blink the colons between the digits
		private System.Windows.Forms.Timer ColonTimer;
		// type of clock to display (a normal clock, stop watch or count down)
		private ClockType clockType = ClockType.DigitalClock;
 
		// date time used to display stopwatch, count begins from this variable
		private DateTime stopwatchBegin = DateTime.Now;
		// count down in milli seconds, default of 10 seconds
		int countDownMilliSeconds = 10000;
		// whenever count down starts this time is set to Now + countDownMilliSeconds
		private DateTime countDownTo;
 
		// currently displayed numbers on the clock, useful to freeze
		int hour, min, sec, ms;
		char am_pm;
 
		// delegates called when the count down is finished
		public delegate void CountDown();
		public event CountDown CountDownDone = null;
 
		// delegates called when an alarm is set
		public delegate void Alarm();
		public event Alarm RaiseAlarm = null;
		private ArrayList AlarmTimes = new ArrayList();
 
		// graphics surface for the control on which the clock is displayed
		private static Graphics graphics;
 
		public DigitalClockCtrl()
		{
			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();
		}
 
		// set count down time in milli seconds
		public int CountDownTime
		{
			get { return countDownMilliSeconds; }
			set 
			{ 
				if (value < 1000)
					MessageBox.Show("Count down time cannot be less than 1000", "Error");
				else
					countDownMilliSeconds = value; 
			}
		}
 
		// set the alarm time
		public DateTime AlarmTime
		{
			set 
			{
				if (value < DateTime.Now)
					MessageBox.Show("Alarm time cannot be earlier.", "Error");
				else
					AlarmTimes.Add(value);
			}
		}
 
		// set the display format, 12 Hr or 24 Hr
		public ClockFormat ClockDisplayFormat
		{
			set { this.clockDisplayFormat = value; }
		}
 
		// setting clock type
		// DigitalClock and StopWatch will automatically start the clock
		// For CountDown the number of seconds should be set before calling this property
		public ClockType SetClockType
		{
			get { return clockType; }
			set 
			{ 
				clockType = value;
				switch(clockType)
				{
					case ClockType.StopWatch:
						stopwatchBegin = DateTime.Now; // start stopwatch clock
						break;
					case ClockType.CountDown:
						countDownTo = DateTime.Now.AddMilliseconds(countDownMilliSeconds);
						break;
				}
			}
		}
 
		// set the color in which the digits are displayed
		public DigitalColor SetDigitalColor
		{
			set 
			{
				this.Invalidate();
				DigitalDisplay.SetPenColor(value);
			}
		}
 
		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				ShowTimer.Stop();
				ColonTimer.Stop();
				if( components != null )
					components.Dispose();
			}
			base.Dispose( disposing );
			ShowTimer.Dispose();
			ColonTimer.Dispose();
		}
 
		#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.ShowTimer = new System.Windows.Forms.Timer(this.components);
			this.ColonTimer = new System.Windows.Forms.Timer(this.components);
			// 
			// ShowTimer
			// 
			this.ShowTimer.Tick += new System.EventHandler(this.OnClockTimer);
			// 
			// ColonTimer
			// 
			this.ColonTimer.Tick += new System.EventHandler(this.OnColonTimer);
			// 
			// DigitalClockCtrl
			// 
			this.BackColor = System.Drawing.Color.Black;
			this.Name = "DigitalClockCtrl";
			this.Size = new System.Drawing.Size(354, 70);
			this.Load += new System.EventHandler(this.OnLoad);
			this.Paint += new System.Windows.Forms.PaintEventHandler(this.OnPaint);
 
		}
		#endregion
 
		// OnPaint - called when regions of clock are invalidated
		private void OnPaint(object sender, System.Windows.Forms.PaintEventArgs e)
		{
			lock(this)
			{
				DisplayTime(e.Graphics);
			}
		}
 
		// This function is aware which panel should display what number
		// and also the colons and PM and AM displays
		private bool blink = false; // toggle for blinking effect of colons
		private void DisplayTime(Graphics g)
		{
			DateTime dt = DateTime.Now;
			if (clockType != ClockType.Freeze)
			{
				hour=dt.Hour; 
				min=dt.Minute; 
				sec=dt.Second; 
				ms=dt.Millisecond;
				am_pm = ' ';
			}
			TimeSpan ts = TimeSpan.Zero;
 
			// check if alarms are set, raise them
			for (int i=0; i<AlarmTimes.Count; i++)
			{
				if (dt > (DateTime)AlarmTimes[i] && RaiseAlarm != null)
				{
					AlarmTimes.RemoveAt(i);
					RaiseAlarm();
				}
			}
			switch(clockType)
			{
				case ClockType.DigitalClock:
					if (clockDisplayFormat == ClockFormat.TwelveHourFormat)
						hour = dt.Hour % 12;
					if (hour == 0) hour = 12;
					switch(clockDisplayFormat)
					{
						case ClockFormat.TwentyFourHourFormat:
							break;
						case ClockFormat.TwelveHourFormat:
							am_pm = (dt.Hour/12 > 0) ? 'P' : 'A';
							break;
					}
					break;
				case ClockType.CountDown:
					ts = countDownTo.Subtract(dt);
					if (ts < TimeSpan.Zero)
					{
						clockType = ClockType.DigitalClock;
						ts = TimeSpan.Zero;
						if (CountDownDone != null)
							CountDownDone();
					}
					break;
				case ClockType.StopWatch:
					ts = dt.Subtract(this.stopwatchBegin);
					break;
				case ClockType.Freeze:
					break;
			}
			if (clockType != ClockType.DigitalClock && 
				clockType != ClockType.Freeze) // ts used for stopwatch or countdown
			{
				hour = ts.Hours;
				min = ts.Minutes;
				sec = ts.Seconds;
				ms = ts.Milliseconds;
			}
			DigitDisplay[0].Draw(hour/10, g);
			DigitDisplay[1].Draw(hour%10, g);
			DigitDisplay[2].Draw(min/10, g);
			DigitDisplay[3].Draw(min%10, g);
			DigitDisplay[4].Draw(sec/10, g);
			DigitDisplay[5].Draw(sec%10, g);
			MicroSecDisplay.Draw(ms/100, g);
			if (am_pm == ' ')
				AmPmDisplay.Draw(g);
			else
				AmPmDisplay.Draw(am_pm, g);
		}
 
		// Timer used to refresh clock display
		private void OnClockTimer(object sender, System.EventArgs e)
		{
			DisplayTime(graphics);
		}
 
		// Keeping the colon timer, gives a special effect of colon blinking
		// independent of the seconds or 1/10 seconds display
		private void OnColonTimer(object sender, System.EventArgs e)
		{
			//display the 2 colons between the hours-minutes and minutes-seconds
			ColonDisplay[0].DrawColon(graphics, ColonType.Rectangular, blink);
			ColonDisplay[1].DrawColon(graphics, ColonType.Rectangular, blink);
			if (clockType == ClockType.Freeze)
				blink = false;
			else
				blink = !blink;
		}
 
		private void OnLoad(object sender, System.EventArgs e)
		{
			graphics = Graphics.FromHwnd(this.Handle);
			PreparePanels();
			ShowTimer.Interval = 100;
			ShowTimer.Start();  // digits are refreshed on timer count
			ColonTimer.Interval = 1000;
			ColonTimer.Start(); // this will blink the colon
 
			// adding the resize handler here so that it will be called
			// only after graphics variable is created
			this.Resize += new System.EventHandler(this.OnResize); 
		}
 
		// function to prepare the digital clock panels by dividing the rectangle
		// It is assumed that the height of each digit is double that of it's width
		// Spacing betweent the digits is 10% of the width
		// The colon characters occupy 50% of width of the digits
		private void PreparePanels()
		{
			// from the above assumptions for height and width
			// the height should be 2.4 units and width 8.8 units :-)
			// check height and width whichever is dominant and adjust the other
			// and set up margins
			Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
 
			// widths, spacings and margins
			// height of colon display is same as a digit
			int DigitWidth, DigitHeight, ColonWidth, Spacing;
			float HMargin=0, // left and right margin
					VMargin=0; // top and bottom margin
 
			// Calculate a digit width (which is our unit) from the above metrics
			// and settle for the least value
			int WidthUnit = (int)(rect.Width/8.8F);
			int HeightUnit = (int)(rect.Height/2.4F);
			DigitWidth = (WidthUnit < HeightUnit) ? WidthUnit : HeightUnit;
 
			DigitHeight = 2 * DigitWidth;  // height is twice of width
			ColonWidth = DigitWidth/2;  // colon width is half of a digit
			Spacing = DigitWidth/10;
			if (Spacing < 1) Spacing = 1; // atleast a spacing of 1 is required
			HMargin = (rect.Width - (8.8F * DigitWidth))/2;
			VMargin = (rect.Height - DigitHeight)/2;
 
			// This is the basic rectangle, offset it as required
			Rectangle basicRect = new Rectangle(0, 0, (int)DigitWidth, (int)DigitHeight);
			int XOffset, YOffset;
			Rectangle calcRect;  // calculated rectangle for a panel
			// Y offset is same for all elements, expcept 1/10 second and AM/PM display
			YOffset = (int)(VMargin);
 
			// create digit panels.  6 digits
			if (DigitDisplay == null)
				DigitDisplay = new DigitalDisplay[6];
			for (int i=0; i<6; i++)
			{
				calcRect = basicRect;
				XOffset = (int)(HMargin + (Spacing * (i+2+(i/2))) + (i * DigitWidth) + ((i/2) * ColonWidth));
				calcRect.Offset(XOffset, YOffset);
				if (DigitDisplay[i] == null)
					DigitDisplay[i] = new DigitalDisplay(calcRect);
				else
					DigitDisplay[i].CalculateAllParameters(calcRect);
			}
 
			if (ColonDisplay == null)
				ColonDisplay = new DigitalDisplay[2];
			// for first colon
			calcRect = basicRect;
			calcRect.Width = (int)ColonWidth;
			XOffset = (int)(HMargin + 3*Spacing + 2*DigitWidth);
			calcRect.Offset(XOffset, YOffset);
			if (ColonDisplay[0] == null)
				ColonDisplay[0] = new DigitalDisplay(calcRect);
			else
				ColonDisplay[0].CalculateAllParameters(calcRect);
			
			// for second colon
			calcRect = basicRect;
			calcRect.Width = (int)ColonWidth;
			XOffset = (int)((6*Spacing) + (4*DigitWidth) + ColonWidth + HMargin);
			calcRect.Offset(XOffset, YOffset);
			if (ColonDisplay[1] == null)
				ColonDisplay[1] = new DigitalDisplay(calcRect);
			else
				ColonDisplay[1].CalculateAllParameters(calcRect);
 
			// for displaying 'A'(AM) or 'P' (PM)
			calcRect = basicRect;
			calcRect.Width = (int)ColonWidth;
			calcRect.Height = calcRect.Height/2;
			XOffset = (int)((10*Spacing)+(6*DigitWidth)+(2*ColonWidth)+HMargin);
			calcRect.Offset(XOffset, (int)(YOffset + DigitHeight/2.0 + 1));
			if (AmPmDisplay == null)
				AmPmDisplay = new DigitalDisplay(calcRect);
			else
				AmPmDisplay.CalculateAllParameters(calcRect);
 
			// for displaying 1/10 of a second
			// reuse AM/PM display panel rectangle
			// only change Y coordinate, shift upwards
			calcRect.Y = YOffset-1; // just to keep it apart from AM/PM display
			if (MicroSecDisplay == null)
				MicroSecDisplay = new DigitalDisplay(calcRect);
			else
				MicroSecDisplay.CalculateAllParameters(calcRect);
		}
 
		// On resize of control recalculate the rectangles for display
		// Also recreate the graphics so that the clipping region is updated
		private void OnResize(object sender, System.EventArgs e)
		{
			lock(this)
			{
				PreparePanels();
				graphics.Dispose();
				graphics = Graphics.FromHwnd(this.Handle);
				graphics.Clear(BackColor);
			}
		}
	}
}

Open in new window

Digital.bmp
0
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21870057
OK.  First off, the bitmap is needed to be used for display only on the form via the [ToolboxBitmap("Digital.bmp")] line.

Now, to display a specific time, rather than current time, you would take the DisplayTime function and modify it as such:


		private void DisplayTime(Graphics g)
		{
			DateTime dt = DateTime.Now;
			if (clockType != ClockType.Freeze)
			{
				hour=dt.Hour; 
				min=dt.Minute; 
				sec=dt.Second; 
				ms=dt.Millisecond;
				am_pm = ' ';
			}
			TimeSpan ts = TimeSpan.Zero;
 
			// check if alarms are set, raise them
			for (int i=0; i<AlarmTimes.Count; i++)
			{
				if (dt > (DateTime)AlarmTimes[i] && RaiseAlarm != null)
				{
					AlarmTimes.RemoveAt(i);
					RaiseAlarm();
				}
			}
 
			switch(clockType)
			{
				case ClockType.DigitalClock:
					if (clockDisplayFormat == ClockFormat.TwelveHourFormat)
						hour = dt.Hour % 12;
					if (hour == 0) hour = 12;
					switch(clockDisplayFormat)
					{
						case ClockFormat.TwentyFourHourFormat:
							break;
						case ClockFormat.TwelveHourFormat:
							am_pm = (dt.Hour/12 > 0) ? 'P' : 'A';
							break;
					}
					break;
				case ClockType.CountDown:
					ts = countDownTo.Subtract(dt);
					if (ts < TimeSpan.Zero)
					{
						clockType = ClockType.DigitalClock;
						ts = TimeSpan.Zero;
						if (CountDownDone != null)
							CountDownDone();
					}
					break;
				case ClockType.StopWatch:
					ts = dt.Subtract(this.stopwatchBegin);
					break;
				case ClockType.Freeze:
					break;
			}
			if (clockType != ClockType.DigitalClock && 
				clockType != ClockType.Freeze) // ts used for stopwatch or countdown
			{
				hour = ts.Hours;
				min = ts.Minutes;
				sec = ts.Seconds;
				ms = ts.Milliseconds;
			}
 
			DrawTime(g);
		}
		
		private void DrawTime(Grahics g)
		{
			DigitDisplay[0].Draw(hour/10, g);
			DigitDisplay[1].Draw(hour%10, g);
			DigitDisplay[2].Draw(min/10, g);
			DigitDisplay[3].Draw(min%10, g);
			DigitDisplay[4].Draw(sec/10, g);
			DigitDisplay[5].Draw(sec%10, g);
			MicroSecDisplay.Draw(ms/100, g);
			if (am_pm == ' ')
				AmPmDisplay.Draw(g);
			else
				AmPmDisplay.Draw(am_pm, g);
		}
		
		public void DisplayTime(Graphics g, int p_hour, int p_min, int p_sec, int p_ms, char p_am_pm)
		{
			hour = p_hour;
			min = p_min;
			sec = p_sec;
			ms = p_ms;
			am_pm = p_am_pm;
			
			DrawTime(g);
		}

Open in new window

0
How our DevOps Teams Maximize Uptime

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us. Read the use case whitepaper.

 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21870075
Oh, and you might need to add a different clock type if you are after specifying a specific time, because the OnPaint routine would switch back to using Clock, Stopwatch or Countdown.
0
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21870127
Here's the updated version that includes a ClockType.Static and utilises that:


		public enum ClockType {DigitalClock, StopWatch, CountDown, Freeze, Static };
		
		private void DisplayTime(Graphics g)
		{
			DateTime dt = DateTime.Now;
			if (clockType != ClockType.Freeze && clockType != ClockType.Static)
			{
				hour=dt.Hour; 
				min=dt.Minute; 
				sec=dt.Second; 
				ms=dt.Millisecond;
				am_pm = ' ';
			}
			TimeSpan ts = TimeSpan.Zero;
 
			CheckAlarms(dt);
			
			switch(clockType)
			{
				case ClockType.DigitalClock:
					if (clockDisplayFormat == ClockFormat.TwelveHourFormat)
						hour = dt.Hour % 12;
					if (hour == 0) hour = 12;
					switch(clockDisplayFormat)
					{
						case ClockFormat.TwentyFourHourFormat:
							break;
						case ClockFormat.TwelveHourFormat:
							am_pm = (dt.Hour/12 > 0) ? 'P' : 'A';
							break;
					}
					break;
				case ClockType.CountDown:
					ts = countDownTo.Subtract(dt);
					if (ts < TimeSpan.Zero)
					{
						clockType = ClockType.DigitalClock;
						ts = TimeSpan.Zero;
						if (CountDownDone != null)
							CountDownDone();
					}
					break;
				case ClockType.StopWatch:
					ts = dt.Subtract(this.stopwatchBegin);
					break;
				case ClockType.Freeze:
					break;
				case ClockType.Static:
					break;
			}
			if (clockType != ClockType.DigitalClock && 
				clockType != ClockType.Static &&
				clockType != ClockType.Freeze) // ts used for stopwatch or countdown
			{
				hour = ts.Hours;
				min = ts.Minutes;
				sec = ts.Seconds;
				ms = ts.Milliseconds;
			}
 
			DrawTime(g);
		}
		
		private void DrawTime(Grahics g)
		{
			DigitDisplay[0].Draw(hour/10, g);
			DigitDisplay[1].Draw(hour%10, g);
			DigitDisplay[2].Draw(min/10, g);
			DigitDisplay[3].Draw(min%10, g);
			DigitDisplay[4].Draw(sec/10, g);
			DigitDisplay[5].Draw(sec%10, g);
			MicroSecDisplay.Draw(ms/100, g);
			if (am_pm == ' ')
				AmPmDisplay.Draw(g);
			else
				AmPmDisplay.Draw(am_pm, g);
		}
		
		private void CheckAlarms(DateTime dt)
		{
			// check if alarms are set, raise them
			for (int i=0; i<AlarmTimes.Count; i++)
			{
				if (dt > (DateTime)AlarmTimes[i] && RaiseAlarm != null)
				{
					AlarmTimes.RemoveAt(i);
					RaiseAlarm();
				}
			}
		}
 
		// This function displays time in a static fashion
		public void DisplayTime(Graphics g, int p_hour, int p_min, int p_sec, int p_ms, char p_am_pm)
		{
			clockType = ClockType.Static;
			
			hour = p_hour;
			min = p_min;
			sec = p_sec;
			ms = p_ms;
			am_pm = p_am_pm;
 
			// Comment out the following if you don't want to raise Alarm events on the current time
			CheckAlarms(DateTime.Now);
			DrawTime(g);
		}

Open in new window

0
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21870145
Oh, and if you are having trouble with getting the correct Graphics object to pass in, you could cheat and replace the DrawTime with a this.Invalidate(); which should force OnPaint to be called anyway.  I just think it would be neater to call it with the correct object rather than firing off yet more events.
0
 

Author Comment

by:tentavarious
ID: 21874259
Is it possible to convert this to vb.net?  Also how can I make this simple, I don't need to use any of the clock functions or date time functions I just want to draw the numbers I pass it.  I like the how the numbers look and how they resemble a digital clock, so for example: if I just pass 9999, thats what I  want drawn.  My problem, is I don't have experience with the drawing class, but I want to take that digitaldisplay class apart to make use of the drawing functions.  One more thing what does this line of code do:[ToolboxBitmap("Digital.bmp")].
0
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21874515
This should provide for the simple version of the UserControl from there you can modify it to work how you want it to....
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
 
Namespace SriClocks
    ' A digit class which can draw a number on a graphics surface
    Public Enum DigitalColor
        RedColor
        GreenColor
        BlueColor
    End Enum
 
    Public Enum colonType
        Circular
        Rectangular
    End Enum
 
    Class DigitalDisplay
        ' pens used to draw the digits
        Shared pen As Pen = New Pen(Color.FromArgb(255, 0, 0))
        Shared dimPen As Pen = Nothing
 
        Private linewidth As Double = 20.0
        Private Points As Point() ' end point coordinates of lines in the digital display
 
        ' for each digit the display bits are set into an int
        ' 'A' and 'P' are included for AM and PM display in the clock
        Private displayNum As Integer() = {63, 12, 118, 94, 77, 91, 123, 14, 127, 95, 111, 103}
 
        ' Rectangles in which colons are displayed
        Private colonRect1, colonRect2 As Rectangle
 
        ' This function is called by the paint method to display the numbers
        ' A set of bits in the 'displayNum' variable define which of the
        ' display legs to display
        ' Based on this the ones with a '1' are in bright color and the rest
        ' with '0's are in a dull color giving the effect of a digital clock
        Protected Friend Sub Draw(ByVal num As Integer, ByVal g As Graphics)
            Dim check As Integer ' used to check if a leg of digit should be bright or dull
 
            ' although pens are global linewidths are specific to each instance
            pen.Width = dimPen.Width = linewidth
 
            For i As Integer = 0 To 6
                check = CType(System.Math.Pow(2, i), Integer)
                If ((check & displayNum(num)) = 0) Then
                    g.DrawLine(dimPen, Points(i * 2), Points(i * 2 + 1))
                Else
                    g.DrawLine(pen, Points(i * 2), Points(i * 2 + 1))
                End If
            Next
        End Sub
 
        Private Shared Sub setDimPen()
            If (dimPen Is Nothing) Then dimPen = CType(pen.Clone(), Pen)
            dimPen.Width = pen.Width
            dimPen.Color = Color.FromArgb( _
             IIf(pen.Color.R > 0, 60, 0), _
             IIf(pen.Color.G > 0, 60, 0), _
             IIf(pen.Color.B > 0, 60, 0))
        End Sub
 
        Private Shared Sub SetPenColor(ByVal dclr As DigitalColor)
            pen.Color = Color.FromArgb( _
             IIf(dclr = DigitalColor.RedColor, 255, 0), _
             IIf(dclr = DigitalColor.GreenColor, 255, 0), _
             IIf(dclr = DigitalColor.BlueColor, 255, 0))
            setDimPen()
        End Sub
 
        ' function that draws a colon in the middle of the rectangular panel
        ' possible modes are circular or rectangular points in the colon
        Private Sub DrawColon(ByVal g As Graphics, ByVal type As ColonType, ByVal bDim As Boolean)
            pen.Width = dimPen.Width = linewidth
            Dim p As Pen = IIf(bDim, dimPen, pen) ' choose a pen for blinking
            Select Case type
                Case ColonType.Circular
                    g.DrawEllipse(p, colonRect1)
                    g.DrawEllipse(p, colonRect2)
                Case ColonType.Rectangular
                    g.DrawRectangle(p, colonRect1)
                    g.DrawRectangle(p, colonRect2)
            End Select
        End Sub
 
        ' Draws the complete rectangle in dim shade to give the digital effect :-)
        Protected Friend Sub Draw(ByVal g As Graphics)
            ' althought pens are static, linewidths are specific to each instance
            dimPen.Width = linewidth
            For i As Integer = 0 To 6
                g.DrawLine(dimPen, Points(i * 2), Points(i * 2 + 1))
            Next
        End Sub
 
        ' Overloaded function to display characters 'A' and 'P' for AM and PM
        ' Using the same algorithm used to display numbers above
        Protected Friend Sub Draw(ByVal ch As Char, ByVal g As Graphics)
            ' 10 and 11 are indices of A and P in the displayNum array
            Select Case Char.ToUpper(ch)
                Case "A"
                    Draw(10, g)
                Case "P"
                    Draw(11, g)
            End Select
        End Sub
 
        ' Constructor takes a rectangle and prepares the end points
        ' of the lines to be drawn for the clock
        Sub DigitalDisplay(ByVal rect As Rectangle)
            pen.StartCap = LineCap.Triangle
            pen.EndCap = LineCap.Triangle
 
            ReDim Points(14) ' there are 7 lines in a display
            For i As Integer = 0 To 13
                Points(i) = New Point(0, 0)
            Next
            CalculateAllParameters(rect)
        End Sub
 
        Sub CalculateAllParameters(ByVal rect As Rectangle)
            linewidth = CType((rect.Width / 5), Integer)
            If (linewidth < 2) Then linewidth = 2
            If (linewidth > 20) Then linewidth = 20
 
            pen.Width = linewidth
            setDimPen()
 
            CalculateLineEnds(rect)
            CalculateColonRectangles(rect)
        End Sub
 
        ' Function calculates end points of lines to display
        ' The draw function will draw lines using this data
        Private Sub CalculateLineEnds(ByVal rect As Rectangle)
            ' 0,1,2,9,10,11,12 points share the same left edge X coordinate
            Points(0).X = rect.Left
            Points(1).X = Points(0).X
            Points(2).X = Points(0).X
            Points(9).X = Points(0).X
            Points(10).X = Points(0).X
            Points(11).X = Points(0).X
            Points(12).X = Points(0).X
 
            ' points 3,4,5,6,7,8,13 the right edge X coordinate
            Points(3).X = rect.Right - CType(linewidth, Integer)
            Points(4).X = Points(3).X
            Points(5).X = Points(3).X
            Points(6).X = Points(3).X
            Points(7).X = Points(3).X
            Points(8).X = Points(3).X
            Points(13).X = Points(3).X
 
            ' Points 1,2,3,4 are the top most points
            Points(1).Y = CType(rect.Top, Integer)
            Points(2).Y = Points(1).Y
            Points(3).Y = Points(1).Y
            Points(4).Y = Points(1).Y
 
            ' Points 0,11,12,13,5,6 are the middle points
            Points(0).Y = rect.Top + CType(((rect.Height - linewidth) / 2.0), Integer)
            Points(11).Y = Points(0).Y
            Points(12).Y = Points(0).Y
            Points(13).Y = Points(0).Y
            Points(5).Y = Points(0).Y
            Points(6).Y = Points(0).Y
 
            ' points 7,8,9,10 are on the bottom edge
            Points(7).Y = rect.Top + CType((rect.Height - linewidth), Integer)
            Points(8).Y = Points(7).Y
            Points(9).Y = Points(7).Y
            Points(10).Y = Points(7).Y
 
            ' now adjust the coordinates that were computed, to get the digital look
            AdjustCoordinates()
        End Sub
 
        ' This function is necessary to give the lines a digital clock look
        ' Push the coordinates a little away so that they look apart
        Private Sub AdjustCoordinates()
            Dim swap As Point  ' required in case points have to be swapped
            For i As Integer = 0 To 6
                ' Always draw from left to right and top to bottom
                ' Adjust the end points accordingly
                If (Points(i * 2).X > Points((i * 2) + 1).X Or Points(i * 2).Y > Points((i * 2) + 1).Y) Then
                    swap = Points(i * 2)
                    Points(i * 2) = Points((i * 2) + 1)
                    Points((i * 2) + 1) = swap
                End If
 
                ' for horizontal lines adjust the X coord
                If (Points(i * 2).X <> Points((i * 2) + 1).X) Then
                    Points(i * 2).X += CType((linewidth / 1.6), Integer)
                    Points((i * 2) + 1).X -= CType((linewidth / 1.6), Integer)
                End If
                ' for vertical lines adjust the y coord
                If (Points(i * 2).Y <> Points((i * 2) + 1).Y) Then
                    Points(i * 2).Y += CType((linewidth / 1.6), Integer)
                    Points((i * 2) + 1).Y -= CType((linewidth / 1.6), Integer)
                End If
            Next
        End Sub
 
        ' function to calculate the rectangles required to drawn colon dot inside
        Private Sub CalculateColonRectangles(ByVal rect As Rectangle)
            colonRect2 = rect
            colonRect1 = rect
            colonRect1.X = colonRect2.X = rect.X + CType(((rect.Width - linewidth) / 2.0), Integer)
            colonRect1.Y = rect.Y + rect.Height / 3
            colonRect2.Y = rect.Y + (rect.Height * 2) / 3
            colonRect1.Width = CType(linewidth, Integer)
            colonRect1.Height = CType(linewidth, Integer)
            colonRect2.Width = CType(linewidth, Integer)
            colonRect2.Height = CType(linewidth, Integer)
        End Sub
    End Class
 
    <ToolboxBitmap("Digital.bmp")> _
    Class DigitalClock
        Inherits System.Windows.Forms.UserControl
 
        Private DigitDisplay As DigitalDisplay() = Nothing ' panels on which digits are displayed
        Private ColonDisplay As DigitalDisplay() = Nothing ' panels for displaying colons
        Private AmPmDisplay As DigitalDisplay = Nothing  ' panel for AM/PM display
        Private MicroSecDisplay As DigitalDisplay = Nothing ' panel for displaying 1/10 of a second
 
        ' This function displays time in a static fashion
        Public Sub DisplayTime(ByVal g As Graphics, ByVal hour As Integer, ByVal min As Integer, ByVal sec As Integer, ByVal ms As Integer, ByVal am_pm As Char)
            DigitDisplay(0).Draw(hour / 10, g)
            DigitDisplay(1).Draw(hour Mod 10, g)
            DigitDisplay(2).Draw(min / 10, g)
            DigitDisplay(3).Draw(min Mod 10, g)
            DigitDisplay(4).Draw(sec / 10, g)
            DigitDisplay(5).Draw(sec Mod 10, g)
            MicroSecDisplay.Draw(ms / 100, g)
            If (am_pm = " ") Then
                AmPmDisplay.Draw(g)
            Else
                AmPmDisplay.Draw(am_pm, g)
            End If
        End Sub
    End Class
End Namespace

Open in new window

0
 

Author Comment

by:tentavarious
ID: 21874801
This is a dumb question, but what do I pass for the graphics argument?  The form i want it displayed on?
0
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21874857
I have updated the solution once more, to now have a GetGraphics() property (readonly) and correctly initialise the class to work out its dimensions, etc.  Plus, you now have DisplayTime(string) which will accept a numeric string of upto six numbers and display this on screen.  You might notice some real estate not being used by the class coz I have left in the rest of the panels within the PreparePanels() section.
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
 
Namespace SriClocks
    ' A digit class which can draw a number on a graphics surface
    Public Enum DigitalColor
        RedColor
        GreenColor
        BlueColor
    End Enum
 
    Public Enum colonType
        Circular
        Rectangular
    End Enum
 
    Class DigitalDisplay
        ' pens used to draw the digits
        Shared pen As Pen = New Pen(Color.FromArgb(255, 0, 0))
        Shared dimPen As Pen = Nothing
 
        Private linewidth As Double = 20.0
        Private Points As Point() ' end point coordinates of lines in the digital display
 
        ' for each digit the display bits are set into an int
        ' 'A' and 'P' are included for AM and PM display in the clock
        Private displayNum As Integer() = {63, 12, 118, 94, 77, 91, 123, 14, 127, 95, 111, 103}
 
        ' Rectangles in which colons are displayed
        Private colonRect1, colonRect2 As Rectangle
 
        ' This function is called by the paint method to display the numbers
        ' A set of bits in the 'displayNum' variable define which of the
        ' display legs to display
        ' Based on this the ones with a '1' are in bright color and the rest
        ' with '0's are in a dull color giving the effect of a digital clock
        Protected Friend Sub Draw(ByVal num As Integer, ByVal g As Graphics)
            Dim check As Integer ' used to check if a leg of digit should be bright or dull
 
            ' although pens are global linewidths are specific to each instance
            pen.Width = dimPen.Width = linewidth
 
            For i As Integer = 0 To 6
                check = CType(System.Math.Pow(2, i), Integer)
                If ((check & displayNum(num)) = 0) Then
                    g.DrawLine(dimPen, Points(i * 2), Points(i * 2 + 1))
                Else
                    g.DrawLine(pen, Points(i * 2), Points(i * 2 + 1))
                End If
            Next
        End Sub
 
        Private Shared Sub setDimPen()
            If (dimPen Is Nothing) Then dimPen = CType(pen.Clone(), Pen)
            dimPen.Width = pen.Width
            dimPen.Color = Color.FromArgb( _
             IIf(pen.Color.R > 0, 60, 0), _
             IIf(pen.Color.G > 0, 60, 0), _
             IIf(pen.Color.B > 0, 60, 0))
        End Sub
 
        Private Shared Sub SetPenColor(ByVal dclr As DigitalColor)
            pen.Color = Color.FromArgb( _
             IIf(dclr = DigitalColor.RedColor, 255, 0), _
             IIf(dclr = DigitalColor.GreenColor, 255, 0), _
             IIf(dclr = DigitalColor.BlueColor, 255, 0))
            setDimPen()
        End Sub
 
        ' function that draws a colon in the middle of the rectangular panel
        ' possible modes are circular or rectangular points in the colon
        Private Sub DrawColon(ByVal g As Graphics, ByVal type As ColonType, ByVal bDim As Boolean)
            pen.Width = dimPen.Width = linewidth
            Dim p As Pen = IIf(bDim, dimPen, pen) ' choose a pen for blinking
            Select Case type
                Case ColonType.Circular
                    g.DrawEllipse(p, colonRect1)
                    g.DrawEllipse(p, colonRect2)
                Case ColonType.Rectangular
                    g.DrawRectangle(p, colonRect1)
                    g.DrawRectangle(p, colonRect2)
            End Select
        End Sub
 
        ' Draws the complete rectangle in dim shade to give the digital effect :-)
        Protected Friend Sub Draw(ByVal g As Graphics)
            ' althought pens are static, linewidths are specific to each instance
            dimPen.Width = linewidth
            For i As Integer = 0 To 6
                g.DrawLine(dimPen, Points(i * 2), Points(i * 2 + 1))
            Next
        End Sub
 
        ' Overloaded function to display characters 'A' and 'P' for AM and PM
        ' Using the same algorithm used to display numbers above
        Protected Friend Sub Draw(ByVal ch As Char, ByVal g As Graphics)
            ' 10 and 11 are indices of A and P in the displayNum array
            Select Case Char.ToUpper(ch)
                Case "A"
                    Draw(10, g)
                Case "P"
                    Draw(11, g)
            End Select
        End Sub
 
        ' Constructor takes a rectangle and prepares the end points
        ' of the lines to be drawn for the clock
        Public Sub New(ByVal rect As Rectangle)
            pen.StartCap = LineCap.Triangle
            pen.EndCap = LineCap.Triangle
 
            ReDim Points(14) ' there are 7 lines in a display
            For i As Integer = 0 To 13
                Points(i) = New Point(0, 0)
            Next
            CalculateAllParameters(rect)
        End Sub
 
        Sub CalculateAllParameters(ByVal rect As Rectangle)
            linewidth = CType((rect.Width / 5), Integer)
            If (linewidth < 2) Then linewidth = 2
            If (linewidth > 20) Then linewidth = 20
 
            pen.Width = linewidth
            setDimPen()
 
            CalculateLineEnds(rect)
            CalculateColonRectangles(rect)
        End Sub
 
        ' Function calculates end points of lines to display
        ' The draw function will draw lines using this data
        Private Sub CalculateLineEnds(ByVal rect As Rectangle)
            ' 0,1,2,9,10,11,12 points share the same left edge X coordinate
            Points(0).X = rect.Left
            Points(1).X = Points(0).X
            Points(2).X = Points(0).X
            Points(9).X = Points(0).X
            Points(10).X = Points(0).X
            Points(11).X = Points(0).X
            Points(12).X = Points(0).X
 
            ' points 3,4,5,6,7,8,13 the right edge X coordinate
            Points(3).X = rect.Right - CType(linewidth, Integer)
            Points(4).X = Points(3).X
            Points(5).X = Points(3).X
            Points(6).X = Points(3).X
            Points(7).X = Points(3).X
            Points(8).X = Points(3).X
            Points(13).X = Points(3).X
 
            ' Points 1,2,3,4 are the top most points
            Points(1).Y = CType(rect.Top, Integer)
            Points(2).Y = Points(1).Y
            Points(3).Y = Points(1).Y
            Points(4).Y = Points(1).Y
 
            ' Points 0,11,12,13,5,6 are the middle points
            Points(0).Y = rect.Top + CType(((rect.Height - linewidth) / 2.0), Integer)
            Points(11).Y = Points(0).Y
            Points(12).Y = Points(0).Y
            Points(13).Y = Points(0).Y
            Points(5).Y = Points(0).Y
            Points(6).Y = Points(0).Y
 
            ' points 7,8,9,10 are on the bottom edge
            Points(7).Y = rect.Top + CType((rect.Height - linewidth), Integer)
            Points(8).Y = Points(7).Y
            Points(9).Y = Points(7).Y
            Points(10).Y = Points(7).Y
 
            ' now adjust the coordinates that were computed, to get the digital look
            AdjustCoordinates()
        End Sub
 
        ' This function is necessary to give the lines a digital clock look
        ' Push the coordinates a little away so that they look apart
        Private Sub AdjustCoordinates()
            Dim swap As Point  ' required in case points have to be swapped
            For i As Integer = 0 To 6
                ' Always draw from left to right and top to bottom
                ' Adjust the end points accordingly
                If (Points(i * 2).X > Points((i * 2) + 1).X Or Points(i * 2).Y > Points((i * 2) + 1).Y) Then
                    swap = Points(i * 2)
                    Points(i * 2) = Points((i * 2) + 1)
                    Points((i * 2) + 1) = swap
                End If
 
                ' for horizontal lines adjust the X coord
                If (Points(i * 2).X <> Points((i * 2) + 1).X) Then
                    Points(i * 2).X += CType((linewidth / 1.6), Integer)
                    Points((i * 2) + 1).X -= CType((linewidth / 1.6), Integer)
                End If
                ' for vertical lines adjust the y coord
                If (Points(i * 2).Y <> Points((i * 2) + 1).Y) Then
                    Points(i * 2).Y += CType((linewidth / 1.6), Integer)
                    Points((i * 2) + 1).Y -= CType((linewidth / 1.6), Integer)
                End If
            Next
        End Sub
 
        ' function to calculate the rectangles required to drawn colon dot inside
        Private Sub CalculateColonRectangles(ByVal rect As Rectangle)
            colonRect2 = rect
            colonRect1 = rect
            colonRect1.X = colonRect2.X = rect.X + CType(((rect.Width - linewidth) / 2.0), Integer)
            colonRect1.Y = rect.Y + rect.Height / 3
            colonRect2.Y = rect.Y + (rect.Height * 2) / 3
            colonRect1.Width = CType(linewidth, Integer)
            colonRect1.Height = CType(linewidth, Integer)
            colonRect2.Width = CType(linewidth, Integer)
            colonRect2.Height = CType(linewidth, Integer)
        End Sub
    End Class
 
    <ToolboxBitmap("Digital.bmp")> _
    Class DigitalClock
        Inherits System.Windows.Forms.UserControl
 
        Private DigitDisplay As DigitalDisplay() = Nothing ' panels on which digits are displayed
        Private ColonDisplay As DigitalDisplay() = Nothing ' panels for displaying colons
        Private AmPmDisplay As DigitalDisplay = Nothing  ' panel for AM/PM display
        Private MicroSecDisplay As DigitalDisplay = Nothing ' panel for displaying 1/10 of a second
        Private MyGraphics As Graphics
 
        ' This function displays time in a static fashion
        Public Sub DisplayTime(ByVal numString As String)
            Dim intNumber As Integer
            If Integer.TryParse(numString, intNumber) Then
                Dim strNumber As String = intNumber.ToString()
                Dim intDigit As Integer
 
                For intLoop As Integer = 0 To 5
                    If strNumber.Length < intLoop AndAlso _
                        Integer.TryParse(strNumber(intLoop), intDigit) Then
                        DigitDisplay(intLoop).Draw(intDigit, MyGraphics)
                    Else
                        DigitDisplay(intLoop).Draw(MyGraphics)
                    End If
                Next
            Else
                Throw New ArgumentException("String was not a number", "numString")
            End If
        End Sub
 
        Public Sub DisplayTime(ByVal hour As Integer, ByVal min As Integer, ByVal sec As Integer, ByVal ms As Integer, ByVal am_pm As Char)
            DisplayTime(Me.GetGraphics(), hour, min, sec, ms, am_pm)
        End Sub
 
        Public Sub DisplayTime(ByVal g As Graphics, ByVal hour As Integer, ByVal min As Integer, ByVal sec As Integer, ByVal ms As Integer, ByVal am_pm As Char)
            DigitDisplay(0).Draw(hour / 10, g)
            DigitDisplay(1).Draw(hour Mod 10, g)
            DigitDisplay(2).Draw(min / 10, g)
            DigitDisplay(3).Draw(min Mod 10, g)
            DigitDisplay(4).Draw(sec / 10, g)
            DigitDisplay(5).Draw(sec Mod 10, g)
            MicroSecDisplay.Draw(ms / 100, g)
            If (am_pm = " ") Then
                AmPmDisplay.Draw(g)
            Else
                AmPmDisplay.Draw(am_pm, g)
            End If
        End Sub
 
        Public ReadOnly Property GetGraphics() As Graphics
            Get
                Return MyGraphics
            End Get
        End Property
 
        ' function to prepare the digital clock panels by dividing the rectangle
        ' It is assumed that the height of each digit is double that of it's width
        ' Spacing betweent the digits is 10% of the width
        ' The colon characters occupy 50% of width of the digits
        Private Sub PreparePanels()
            ' from the above assumptions for height and width
            ' the height should be 2.4 units and width 8.8 units :-)
            ' check height and width whichever is dominant and adjust the other
            ' and set up margins
            Dim rect As Rectangle = New Rectangle(0, 0, Me.Width, Me.Height)
 
            ' widths, spacings and margins
            ' height of colon display is same as a digit
            Dim DigitWidth, DigitHeight, ColonWidth, Spacing As Integer
            Dim HMargin As Double = 0 ' left and right margin
            Dim VMargin As Double = 0 ' top and bottom margin
 
            ' Calculate a digit width (which is our unit) from the above metrics
            ' and settle for the least value
            Dim WidthUnit As Integer = CType(rect.Width / 8.8F, Integer)
            Dim HeightUnit As Integer = CType((rect.Height / 2.4F), Integer)
            DigitWidth = IIf(WidthUnit < HeightUnit, WidthUnit, HeightUnit)
 
            DigitHeight = 2 * DigitWidth ' height is twice of width
            ColonWidth = DigitWidth / 2 'colon width is half of a digit
            Spacing = DigitWidth / 10
            If (Spacing < 1) Then Spacing = 1 ' atleast a spacing of 1 is required
            HMargin = (rect.Width - (8.8F * DigitWidth)) / 2
            VMargin = (rect.Height - DigitHeight) / 2
 
            ' This is the basic rectangle, offset it as required
            Dim basicRect As Rectangle = New Rectangle(0, 0, CType(DigitWidth, Integer), CType(DigitHeight, Integer))
            Dim XOffset, YOffset As Integer
            Dim calcRect As Rectangle   ' calculated rectangle for a panel
            ' Y offset is same for all elements, expcept 1/10 second and AM/PM display
            YOffset = CType(VMargin, Integer)
 
            ' create digit panels.  6 digits
            If (DigitDisplay Is Nothing) Then
                ReDim DigitDisplay(6)
            End If
 
            For i As Integer = 0 To 5
                calcRect = basicRect
                XOffset = CType((HMargin + (Spacing * (i + 2 + (i / 2))) + (i * DigitWidth) + ((i / 2) * ColonWidth)), Integer)
                calcRect.Offset(XOffset, YOffset)
                If (DigitDisplay(i) Is Nothing) Then
                    DigitDisplay(i) = New DigitalDisplay(calcRect)
                Else
                    DigitDisplay(i).CalculateAllParameters(calcRect)
                End If
            Next
 
            If (ColonDisplay Is Nothing) Then
                ReDim ColonDisplay(2)
            End If
 
            ' for first colon
            calcRect = basicRect
            calcRect.Width = CType(ColonWidth, Integer)
            XOffset = CType((HMargin + 3 * Spacing + 2 * DigitWidth), Integer)
            calcRect.Offset(XOffset, YOffset)
            If (ColonDisplay(0) Is Nothing) Then
                ColonDisplay(0) = New DigitalDisplay(calcRect)
            Else
                ColonDisplay(0).CalculateAllParameters(calcRect)
            End If
 
            ' for second colon
            calcRect = basicRect
            calcRect.Width = CType(ColonWidth, Integer)
            XOffset = CType(((6 * Spacing) + (4 * DigitWidth) + ColonWidth + HMargin), Integer)
            calcRect.Offset(XOffset, YOffset)
            If (ColonDisplay(1) Is Nothing) Then
                ColonDisplay(1) = New DigitalDisplay(calcRect)
            Else
                ColonDisplay(1).CalculateAllParameters(calcRect)
            End If
 
            ' for displaying 'A'(AM) or 'P' (PM)
            calcRect = basicRect
            calcRect.Width = CType(ColonWidth, Integer)
            calcRect.Height = calcRect.Height / 2
            XOffset = CType(((10 * Spacing) + (6 * DigitWidth) + (2 * ColonWidth) + HMargin), Integer)
            calcRect.Offset(XOffset, CType((YOffset + DigitHeight / 2.0 + 1), Integer))
            If (AmPmDisplay Is Nothing) Then
                AmPmDisplay = New DigitalDisplay(calcRect)
            Else
                AmPmDisplay.CalculateAllParameters(calcRect)
            End If
 
            ' for displaying 1/10 of a second
            ' reuse AM/PM display panel rectangle
            ' only change Y coordinate, shift upwards
            calcRect.Y = YOffset - 1 ' just to keep it apart from AM/PM display
            If (MicroSecDisplay Is Nothing) Then
                MicroSecDisplay = New DigitalDisplay(calcRect)
            Else
                MicroSecDisplay.CalculateAllParameters(calcRect)
            End If
        End Sub
 
        ' On resize of control recalculate the rectangles for display
        ' Also recreate the graphics so that the clipping region is updated
        Private Sub DigitalClock_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
            SyncLock (Me)
                PreparePanels()
                MyGraphics.Dispose()
                MyGraphics = Graphics.FromHwnd(Me.Handle)
                MyGraphics.Clear(BackColor)
            End SyncLock
        End Sub
 
        Private Sub DigitalClock_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            MyGraphics = Graphics.FromHwnd(Me.Handle)
            PreparePanels()
        End Sub
    End Class
End Namespace

Open in new window

0
 

Author Comment

by:tentavarious
ID: 21875141
Ok, I am having some problems getting this to work.  I keep getting an error saying Object reference not set to an instance of an object.
This error happens when I tried to display some numbers in the DisplayTime function.  I removed the am/pm argument since I won't be using this as an actual clock.  I think the problem is when I initialize the Sriclocks.DigitalDisplay class
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
<ToolboxBitmap("Digital.bmp")> _
Public Class Form2
    Inherits System.Windows.Forms.Form
    Private DigitDisplay As SriClocks.DigitalDisplay() = Nothing ' panels on which digits are displayed
    Private ColonDisplay As SriClocks.DigitalDisplay() = Nothing ' panels for displaying colons
    Private AmPmDisplay As SriClocks.DigitalDisplay = Nothing  ' panel for AM/PM display
    Private MicroSecDisplay As SriClocks.DigitalDisplay = Nothing ' panel for displaying 1/10 of a second
    Private MyGraphics As Graphics
 
    ' This function displays time in a static fashion
    
    Public Sub DisplayTime(ByVal hour As Integer, ByVal min As Integer, ByVal sec As Integer, ByVal ms As Integer)
        DisplayTime(Me.GetGraphics(), hour, min, sec, ms)
    End Sub
 
    Public Sub DisplayTime(ByVal g As Graphics, ByVal hour As Integer, ByVal min As Integer, ByVal sec As Integer, ByVal ms As Integer)
        DigitDisplay(0).Draw(hour / 10, g)
        DigitDisplay(1).Draw(hour Mod 10, g)
        DigitDisplay(2).Draw(min / 10, g)
        DigitDisplay(3).Draw(min Mod 10, g)
        DigitDisplay(4).Draw(sec / 10, g)
        DigitDisplay(5).Draw(sec Mod 10, g)
        MicroSecDisplay.Draw(ms / 100, g)
    End Sub
 
    Public ReadOnly Property GetGraphics() As Graphics
        Get
            Return MyGraphics
        End Get
    End Property
 
    ' function to prepare the digital clock panels by dividing the rectangle
    ' It is assumed that the height of each digit is double that of it's width
    ' Spacing betweent the digits is 10% of the width
    ' The colon characters occupy 50% of width of the digits
    Private Sub PreparePanels()
        ' from the above assumptions for height and width
        ' the height should be 2.4 units and width 8.8 units :-)
        ' check height and width whichever is dominant and adjust the other
        ' and set up margins
        Dim rect As Rectangle = New Rectangle(0, 0, Me.Width, Me.Height)
 
        ' widths, spacings and margins
        ' height of colon display is same as a digit
        Dim DigitWidth, DigitHeight, ColonWidth, Spacing As Integer
        Dim HMargin As Double = 0 ' left and right margin
        Dim VMargin As Double = 0 ' top and bottom margin
 
        ' Calculate a digit width (which is our unit) from the above metrics
        ' and settle for the least value
        Dim WidthUnit As Integer = CType(rect.Width / 8.8F, Integer)
        Dim HeightUnit As Integer = CType((rect.Height / 2.4F), Integer)
        DigitWidth = IIf(WidthUnit < HeightUnit, WidthUnit, HeightUnit)
 
        DigitHeight = 2 * DigitWidth ' height is twice of width
        ColonWidth = DigitWidth / 2 'colon width is half of a digit
        Spacing = DigitWidth / 10
        If (Spacing < 1) Then Spacing = 1 ' atleast a spacing of 1 is required
        HMargin = (rect.Width - (8.8F * DigitWidth)) / 2
        VMargin = (rect.Height - DigitHeight) / 2
 
        ' This is the basic rectangle, offset it as required
        Dim basicRect As Rectangle = New Rectangle(0, 0, CType(DigitWidth, Integer), CType(DigitHeight, Integer))
        Dim XOffset, YOffset As Integer
        Dim calcRect As Rectangle   ' calculated rectangle for a panel
        ' Y offset is same for all elements, expcept 1/10 second and AM/PM display
        YOffset = CType(VMargin, Integer)
 
        ' create digit panels.  6 digits
        If (DigitDisplay Is Nothing) Then
            ReDim DigitDisplay(6)
        End If
 
        For i As Integer = 0 To 5
            calcRect = basicRect
            XOffset = CType((HMargin + (Spacing * (i + 2 + (i / 2))) + (i * DigitWidth) + ((i / 2) * ColonWidth)), Integer)
            calcRect.Offset(XOffset, YOffset)
            If (DigitDisplay(i) Is Nothing) Then
                DigitDisplay(i) = New SriClocks.DigitalDisplay(calcRect)
            Else
                DigitDisplay(i).CalculateAllParameters(calcRect)
            End If
        Next
 
        If (ColonDisplay Is Nothing) Then
            ReDim ColonDisplay(2)
        End If
 
        ' for first colon
        calcRect = basicRect
        calcRect.Width = CType(ColonWidth, Integer)
        XOffset = CType((HMargin + 3 * Spacing + 2 * DigitWidth), Integer)
        calcRect.Offset(XOffset, YOffset)
        If (ColonDisplay(0) Is Nothing) Then
            ColonDisplay(0) = New SriClocks.DigitalDisplay(calcRect)
        Else
            ColonDisplay(0).CalculateAllParameters(calcRect)
        End If
 
        ' for second colon
        calcRect = basicRect
        calcRect.Width = CType(ColonWidth, Integer)
        XOffset = CType(((6 * Spacing) + (4 * DigitWidth) + ColonWidth + HMargin), Integer)
        calcRect.Offset(XOffset, YOffset)
        If (ColonDisplay(1) Is Nothing) Then
            ColonDisplay(1) = New SriClocks.DigitalDisplay(calcRect)
        Else
            ColonDisplay(1).CalculateAllParameters(calcRect)
        End If
 
        ' for displaying 'A'(AM) or 'P' (PM)
        calcRect = basicRect
        calcRect.Width = CType(ColonWidth, Integer)
        calcRect.Height = calcRect.Height / 2
        XOffset = CType(((10 * Spacing) + (6 * DigitWidth) + (2 * ColonWidth) + HMargin), Integer)
        calcRect.Offset(XOffset, CType((YOffset + DigitHeight / 2.0 + 1), Integer))
        If (AmPmDisplay Is Nothing) Then
            AmPmDisplay = New SriClocks.DigitalDisplay(calcRect)
        Else
            AmPmDisplay.CalculateAllParameters(calcRect)
        End If
 
        ' for displaying 1/10 of a second
        ' reuse AM/PM display panel rectangle
        ' only change Y coordinate, shift upwards
        calcRect.Y = YOffset - 1 ' just to keep it apart from AM/PM display
        If (MicroSecDisplay Is Nothing) Then
            MicroSecDisplay = New SriClocks.DigitalDisplay(calcRect)
        Else
            MicroSecDisplay.CalculateAllParameters(calcRect)
        End If
    End Sub
 
    ' On resize of control recalculate the rectangles for display
    ' Also recreate the graphics so that the clipping region is updated
    Private Sub DigitalClock_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Resize
        SyncLock (Me)
            PreparePanels()
            MyGraphics.Dispose()
            MyGraphics = Graphics.FromHwnd(Me.Handle)
            MyGraphics.Clear(BackColor)
        End SyncLock
    End Sub
 
    Private Sub DigitalClock_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        MyGraphics = Graphics.FromHwnd(Me.Handle)
        PreparePanels()
        DisplayTime(9, 3, 0, 12)
    End Sub

Open in new window

0
 

Author Comment

by:tentavarious
ID: 21875461
Ok, I got it working by calling the DisplayTime procedure from your PreparePanels procedure, but when I run it, nothing happens I just get a blank form.  Right now I am using the form as the drawing area and I set the background to black, but after running through the code the form's back ground color gets set to control and it gets resized.  What am I forgetting to do?  I just wanna draw these values on my form 9,3,0,12?

DisplayTime(9, 3, 0, 12)
0
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21875926
Zip up and attach the example code you have and I will see if I can update it to work.  It would be better than playing around with half guesses.
0
 

Author Comment

by:tentavarious
ID: 21876006
Its not allowing me to attach the file because of the .vb extenstion.  I will just attach a code snippet of the form I am using in which I am trying to draw.
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
<ToolboxBitmap("Digital.bmp")> _
Public Class Form2
    Inherits System.Windows.Forms.Form
    Public DigitDisplay As SriClocks.DigitalDisplay() = Nothing ' panels on which digits are displayed
    Public ColonDisplay As SriClocks.DigitalDisplay() = Nothing ' panels for displaying colons
    Public AmPmDisplay As SriClocks.DigitalDisplay = Nothing  ' panel for AM/PM display
    Public MicroSecDisplay As SriClocks.DigitalDisplay = Nothing ' panel for displaying 1/10 of a second
    Private MyGraphics As Graphics
 
    ' This function displays time in a static fashion
    
    Public Sub DisplayTime(ByVal hour As Integer, ByVal min As Integer, ByVal sec As Integer, ByVal ms As Integer)
        DisplayTime(Me.GetGraphics(), hour, min, sec, ms)
    End Sub
 
    Public Sub DisplayTime(ByVal g As Graphics, ByVal hour As Integer, ByVal min As Integer, ByVal sec As Integer, ByVal ms As Integer) 
        DigitDisplay(0).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(1).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(2).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(3).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(4).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(5).SetPenColor(SriClocks.DigitalColor.GreenColor)
 
        DigitDisplay(0).Draw(hour / 10, g)
        DigitDisplay(1).Draw(hour Mod 10, g)
        DigitDisplay(2).Draw(min / 10, g)
        DigitDisplay(3).Draw(min Mod 10, g)
        DigitDisplay(4).Draw(sec / 10, g)
        DigitDisplay(5).Draw(sec Mod 10, g)
        MicroSecDisplay.Draw(ms / 100, g)
    End Sub
 
    Public ReadOnly Property GetGraphics() As Graphics
        Get
            Return MyGraphics
        End Get
    End Property
 
    ' function to prepare the digital clock panels by dividing the rectangle
    ' It is assumed that the height of each digit is double that of it's width
    ' Spacing betweent the digits is 10% of the width
    ' The colon characters occupy 50% of width of the digits
    Private Sub PreparePanels()
        ' from the above assumptions for height and width
        ' the height should be 2.4 units and width 8.8 units :-)
        ' check height and width whichever is dominant and adjust the other
        ' and set up margins
        Dim rect As Rectangle = New Rectangle(0, 0, Me.Width, Me.Height)
 
        ' widths, spacings and margins
        ' height of colon display is same as a digit
        Dim DigitWidth, DigitHeight, ColonWidth, Spacing As Integer
        Dim HMargin As Double = 0 ' left and right margin
        Dim VMargin As Double = 0 ' top and bottom margin
 
        ' Calculate a digit width (which is our unit) from the above metrics
        ' and settle for the least value
        Dim WidthUnit As Integer = CType(rect.Width / 8.8F, Integer)
        Dim HeightUnit As Integer = CType((rect.Height / 2.4F), Integer)
        DigitWidth = IIf(WidthUnit < HeightUnit, WidthUnit, HeightUnit)
 
        DigitHeight = 2 * DigitWidth ' height is twice of width
        ColonWidth = DigitWidth / 2 'colon width is half of a digit
        Spacing = DigitWidth / 10
        If (Spacing < 1) Then Spacing = 1 ' atleast a spacing of 1 is required
        HMargin = (rect.Width - (8.8F * DigitWidth)) / 2
        VMargin = (rect.Height - DigitHeight) / 2
 
        ' This is the basic rectangle, offset it as required
        Dim basicRect As Rectangle = New Rectangle(0, 0, CType(DigitWidth, Integer), CType(DigitHeight, Integer))
        Dim XOffset, YOffset As Integer
        Dim calcRect As Rectangle   ' calculated rectangle for a panel
        ' Y offset is same for all elements, expcept 1/10 second and AM/PM display
        YOffset = CType(VMargin, Integer)
 
        ' create digit panels.  6 digits
        If (DigitDisplay Is Nothing) Then
            ReDim DigitDisplay(6)
        End If
 
        For i As Integer = 0 To 5
            calcRect = basicRect
            XOffset = CType((HMargin + (Spacing * (i + 2 + (i / 2))) + (i * DigitWidth) + ((i / 2) * ColonWidth)), Integer)
            calcRect.Offset(XOffset, YOffset)
            If (DigitDisplay(i) Is Nothing) Then
                DigitDisplay(i) = New SriClocks.DigitalDisplay(calcRect)
            Else
                DigitDisplay(i).CalculateAllParameters(calcRect)
            End If
        Next
 
        If (ColonDisplay Is Nothing) Then
            ReDim ColonDisplay(2)
        End If
 
        ' for first colon
        calcRect = basicRect
        calcRect.Width = CType(ColonWidth, Integer)
        XOffset = CType((HMargin + 3 * Spacing + 2 * DigitWidth), Integer)
        calcRect.Offset(XOffset, YOffset)
        If (ColonDisplay(0) Is Nothing) Then
            ColonDisplay(0) = New SriClocks.DigitalDisplay(calcRect)
        Else
            ColonDisplay(0).CalculateAllParameters(calcRect)
        End If
 
        ' for second colon
        calcRect = basicRect
        calcRect.Width = CType(ColonWidth, Integer)
        XOffset = CType(((6 * Spacing) + (4 * DigitWidth) + ColonWidth + HMargin), Integer)
        calcRect.Offset(XOffset, YOffset)
        If (ColonDisplay(1) Is Nothing) Then
            ColonDisplay(1) = New SriClocks.DigitalDisplay(calcRect)
        Else
            ColonDisplay(1).CalculateAllParameters(calcRect)
        End If
 
        ' for displaying 'A'(AM) or 'P' (PM)
        calcRect = basicRect
        calcRect.Width = CType(ColonWidth, Integer)
        calcRect.Height = calcRect.Height / 2
        XOffset = CType(((10 * Spacing) + (6 * DigitWidth) + (2 * ColonWidth) + HMargin), Integer)
        calcRect.Offset(XOffset, CType((YOffset + DigitHeight / 2.0 + 1), Integer))
        If (AmPmDisplay Is Nothing) Then
            AmPmDisplay = New SriClocks.DigitalDisplay(calcRect)
        Else
            AmPmDisplay.CalculateAllParameters(calcRect)
        End If
 
        ' for displaying 1/10 of a second
        ' reuse AM/PM display panel rectangle
        ' only change Y coordinate, shift upwards
        calcRect.Y = YOffset - 1 ' just to keep it apart from AM/PM display
        If (MicroSecDisplay Is Nothing) Then
            MicroSecDisplay = New SriClocks.DigitalDisplay(calcRect)
        Else
            MicroSecDisplay.CalculateAllParameters(calcRect)
        End If
        DisplayTime(Now.Hour, Now.Minute, Now.Second, 2)
    End Sub
 
    ' On resize of control recalculate the rectangles for display
    ' Also recreate the graphics so that the clipping region is updated
    Private Sub DigitalClock_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Resize
        SyncLock (Me)
            PreparePanels()
            MyGraphics.Dispose()
            MyGraphics = Graphics.FromHwnd(Me.Handle)
            MyGraphics.Clear(BackColor)
        End SyncLock
    End Sub
 
    Private Sub InitializeComponent()
        '
        'Form2
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.BackColor = System.Drawing.Color.Black
        Me.ClientSize = New System.Drawing.Size(376, 86)
        Me.ForeColor = System.Drawing.Color.Black
        Me.Name = "Form2"
        Me.Text = "Takt_Time"
 
    End Sub
 
    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        MyGraphics = Graphics.FromHwnd(Me.Handle)
        PreparePanels()
    End Sub
End Class

Open in new window

0
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21876213
Try zipping up the folder containing the project, not just the one VB file, so that all the classes are available.  It could be a minor issue elsewhere that is causing it but its far easier to work out if I can step through it.  The coding 'appears' fine when I am glancing at it.
0
 

Author Comment

by:tentavarious
ID: 21876285
I zipped the entire folder, but it still didnt like it.  Let me see if I can try again
0
 

Author Comment

by:tentavarious
ID: 21876296
Yep I get this message: The extension of one or more files in the archive is not in the list of allowed extensions: Takt_Time/AssemblyInfo.vb
0
 

Author Comment

by:tentavarious
ID: 21876433
This is not working, it doesnt like a lot of the file exstensions.  The uploader must loop through all files and check extensions in a zipped folder.  Can't you just make a new project and use the code from the DigitalDisplay class, to create a new class plus my form2 code to make a new form?  I have already included the bitmap file and that is pretty much everything I have.  The uploader doesn't like vb,exe,resx or sln file extensions.  
0
 

Author Comment

by:tentavarious
ID: 21883429
Any luck?  Basically what I want to do is get rid of the user control and just use it directly with Form2, I wouldn't think it would be that hard.
0
 

Author Comment

by:tentavarious
ID: 21883697
Ok, something is wrong with this part, when I added this line <ToolboxBitmap("Digital.bmp")> _ my forms properties dont work, they default back to its normal settings.  So what is going on when I add that line.

<ToolboxBitmap("Digital.bmp")> _
Class Form2
end Class
0
 

Author Comment

by:tentavarious
ID: 21884199
Ok, nevermind my last comments, I got the draw to work, but for some reason it only draws 8's and it doesnt look right.  I have attached my form code and the drawing class also a bitmap if what is going on
'Form Code
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
<ToolboxBitmap("Digital.bmp")> _
Public Class test
    Inherits System.Windows.Forms.Form
 
#Region " Windows Form Designer generated code "
 
    Public Sub New()
        MyBase.New()
 
        'This call is required by the Windows Form Designer.
        InitializeComponent()
 
        'Add any initialization after the InitializeComponent() call
 
    End Sub
 
    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub
 
    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer
 
    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents Button1 As System.Windows.Forms.Button
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.BackColor = System.Drawing.SystemColors.Control
        Me.Button1.Location = New System.Drawing.Point(288, 40)
        Me.Button1.Name = "Button1"
        Me.Button1.TabIndex = 1
        Me.Button1.Text = "Button1"
        '
        'test
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.BackColor = System.Drawing.SystemColors.ControlText
        Me.ClientSize = New System.Drawing.Size(384, 94)
        Me.Controls.Add(Me.Button1)
        Me.Name = "test"
        Me.Text = "test"
        Me.ResumeLayout(False)
 
    End Sub
 
#End Region
    Public DigitDisplay As SriClocks.DigitalDisplay() = Nothing ' panels on which digits are displayed
    Public ColonDisplay As SriClocks.DigitalDisplay() = Nothing ' panels for displaying colons
    Public AmPmDisplay As SriClocks.DigitalDisplay = Nothing  ' panel for AM/PM display
    Public MicroSecDisplay As SriClocks.DigitalDisplay = Nothing ' panel for displaying 1/10 of a second
    Private MyGraphics As Graphics
    Public clockval As SriClocks.colonType = SriClocks.colonType.Circular
    Private Sub test_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        GetGraphics = Graphics.FromHwnd(Me.Handle)
        PreparePanels()
    End Sub
    Public Sub DisplayTime(ByVal hour As Integer, ByVal min As Integer, ByVal sec As Integer, ByVal ms As Integer)
        DisplayTime(Me.GetGraphics(), hour, min, sec, ms)
    End Sub
    Public Sub DisplayTime(ByVal g As Graphics, ByVal hour As Integer, ByVal min As Integer, ByVal sec As Integer, ByVal ms As Integer)
        DigitDisplay(0).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(1).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(2).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(3).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(4).SetPenColor(SriClocks.DigitalColor.GreenColor)
        DigitDisplay(5).SetPenColor(SriClocks.DigitalColor.GreenColor)
 
        DigitDisplay(0).Draw(hour / 10, g)
        DigitDisplay(1).Draw(hour Mod 10, g)
        DigitDisplay(2).Draw(min / 10, g)
        DigitDisplay(3).Draw(min Mod 10, g)
        DigitDisplay(4).Draw(sec / 10, g)
        DigitDisplay(5).Draw(sec Mod 10, g)
        MicroSecDisplay.Draw(ms / 100, g)
    End Sub
    Public Property GetGraphics() As Graphics
        Get
            Return MyGraphics
        End Get
        Set(ByVal Value As Graphics)
            MyGraphics = Value
        End Set
    End Property
    Private Sub PreparePanels()
        ' from the above assumptions for height and width
        ' the height should be 2.4 units and width 8.8 units :-)
        ' check height and width whichever is dominant and adjust the other
        ' and set up margins
        Dim rect As Rectangle = New Rectangle(0, 0, Me.Width, Me.Height)
 
        ' widths, spacings and margins
        ' height of colon display is same as a digit
        Dim DigitWidth, DigitHeight, ColonWidth, Spacing As Integer
        Dim HMargin As Double = 0 ' left and right margin
        Dim VMargin As Double = 0 ' top and bottom margin
 
        ' Calculate a digit width (which is our unit) from the above metrics
        ' and settle for the least value
        Dim WidthUnit As Integer = CType(rect.Width / 8.8F, Integer)
        Dim HeightUnit As Integer = CType((rect.Height / 2.4F), Integer)
        DigitWidth = IIf(WidthUnit < HeightUnit, WidthUnit, HeightUnit)
 
        DigitHeight = 2 * DigitWidth ' height is twice of width
        ColonWidth = DigitWidth / 2 'colon width is half of a digit
        Spacing = DigitWidth / 10
        If (Spacing < 1) Then Spacing = 1 ' atleast a spacing of 1 is required
        HMargin = (rect.Width - (8.8F * DigitWidth)) / 2
        VMargin = (rect.Height - DigitHeight) / 2
 
        ' This is the basic rectangle, offset it as required
        Dim basicRect As Rectangle = New Rectangle(0, 0, CType(DigitWidth, Integer), CType(DigitHeight, Integer))
        Dim XOffset, YOffset As Integer
        Dim calcRect As Rectangle   ' calculated rectangle for a panel
        ' Y offset is same for all elements, expcept 1/10 second and AM/PM display
        YOffset = CType(VMargin, Integer)
 
        ' create digit panels.  6 digits
        If (DigitDisplay Is Nothing) Then
            ReDim DigitDisplay(6)
        End If
 
        For i As Integer = 0 To 5
            calcRect = basicRect
            XOffset = CType((HMargin + (Spacing * (i + 2 + (i / 2))) + (i * DigitWidth) + ((i / 2) * ColonWidth)), Integer)
            calcRect.Offset(XOffset, YOffset)
            If (DigitDisplay(i) Is Nothing) Then
                DigitDisplay(i) = New SriClocks.DigitalDisplay(calcRect)
            Else
                DigitDisplay(i).CalculateAllParameters(calcRect)
            End If
        Next
 
        If (ColonDisplay Is Nothing) Then
            ReDim ColonDisplay(2)
        End If
 
        ' for first colon
        calcRect = basicRect
        calcRect.Width = CType(ColonWidth, Integer)
        XOffset = CType((HMargin + 3 * Spacing + 2 * DigitWidth), Integer)
        calcRect.Offset(XOffset, YOffset)
        If (ColonDisplay(0) Is Nothing) Then
            ColonDisplay(0) = New SriClocks.DigitalDisplay(calcRect)
        Else
            ColonDisplay(0).CalculateAllParameters(calcRect)
        End If
 
        ' for second colon
        calcRect = basicRect
        calcRect.Width = CType(ColonWidth, Integer)
        XOffset = CType(((6 * Spacing) + (4 * DigitWidth) + ColonWidth + HMargin), Integer)
        calcRect.Offset(XOffset, YOffset)
        If (ColonDisplay(1) Is Nothing) Then
            ColonDisplay(1) = New SriClocks.DigitalDisplay(calcRect)
        Else
            ColonDisplay(1).CalculateAllParameters(calcRect)
        End If
 
        ' for displaying 'A'(AM) or 'P' (PM)
        calcRect = basicRect
        calcRect.Width = CType(ColonWidth, Integer)
        calcRect.Height = calcRect.Height / 2
        XOffset = CType(((10 * Spacing) + (6 * DigitWidth) + (2 * ColonWidth) + HMargin), Integer)
        calcRect.Offset(XOffset, CType((YOffset + DigitHeight / 2.0 + 1), Integer))
        If (AmPmDisplay Is Nothing) Then
            AmPmDisplay = New SriClocks.DigitalDisplay(calcRect)
        Else
            AmPmDisplay.CalculateAllParameters(calcRect)
        End If
 
        ' for displaying 1/10 of a second
        ' reuse AM/PM display panel rectangle
        ' only change Y coordinate, shift upwards
        calcRect.Y = YOffset - 1 ' just to keep it apart from AM/PM display
        If (MicroSecDisplay Is Nothing) Then
            MicroSecDisplay = New SriClocks.DigitalDisplay(calcRect)
        Else
            MicroSecDisplay.CalculateAllParameters(calcRect)
        End If
        DisplayTime(Now.Hour, Now.Minute, Now.Second, 1)
    End Sub
 
    Private Sub test_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Resize
        SyncLock (Me)
            GetGraphics = Graphics.FromHwnd(Me.Handle)
            PreparePanels()
            GetGraphics.Dispose()
            MyGraphics = Graphics.FromHwnd(Me.Handle)
            MyGraphics.Clear(Color.Black)
        End SyncLock
    End Sub
 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        GetGraphics = Graphics.FromHwnd(Me.Handle)
        PreparePanels()
    End Sub
End Class
 
 
''The Class that handles all of the drawing
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
 
Namespace SriClocks
    ' A digit class which can draw a number on a graphics surface
    Public Enum DigitalColor
        RedColor
        GreenColor
        BlueColor
    End Enum
 
    Public Enum colonType
        Circular
        Rectangular
    End Enum
 
    Public Class DigitalDisplay
        ' pens used to draw the digits
        Shared pen As pen = New pen(Color.FromArgb(255, 0, 0))
        Shared dimPen As pen = Nothing
 
        Private linewidth As Double = 20.0F
 
        Private Points As Point() ' end point coordinates of lines in the digital display
 
        ' for each digit the display bits are set into an int
        ' 'A' and 'P' are included for AM and PM display in the clock
        Private displayNum As Integer() = {63, 12, 118, 94, 77, 91, 123, 14, 127, 95, 111, 103}
 
        ' Rectangles in which colons are displayed
        Private colonRect1, colonRect2 As Rectangle
 
        ' This function is called by the paint method to display the numbers
        ' A set of bits in the 'displayNum' variable define which of the
        ' display legs to display
        ' Based on this the ones with a '1' are in bright color and the rest
        ' with '0's are in a dull color giving the effect of a digital clock
        Protected Friend Sub Draw(ByVal num As Integer, ByVal g As Graphics)
            Dim check As Integer ' used to check if a leg of digit should be bright or dull
 
            ' although pens are global linewidths are specific to each instance
            pen.Width = dimPen.Width = linewidth
 
            For i As Integer = 0 To 6
                check = CType(System.Math.Pow(2, i), Integer)
                If ((check & displayNum(num)) = 0) Then
                    g.DrawLine(dimPen, Points(i * 2), Points(i * 2 + 1))
                Else
                    g.DrawLine(pen, Points(i * 2), Points(i * 2 + 1))
                End If
            Next
 
        End Sub
 
        Private Shared Sub setDimPen()
            If (dimPen Is Nothing) Then dimPen = CType(pen.Clone(), Pen)
            dimPen.Width = pen.Width
            dimPen.Color = Color.FromArgb( _
             IIf(pen.Color.R > 0, 60, 0), _
             IIf(pen.Color.G > 0, 60, 0), _
             IIf(pen.Color.B > 0, 60, 0))
        End Sub
 
        Public Shared Sub SetPenColor(ByVal dclr As DigitalColor)
            pen.Color = Color.FromArgb( _
             IIf(dclr = DigitalColor.RedColor, 255, 0), _
             IIf(dclr = DigitalColor.GreenColor, 255, 0), _
             IIf(dclr = DigitalColor.BlueColor, 255, 0))
            setDimPen()
        End Sub
 
        ' function that draws a colon in the middle of the rectangular panel
        ' possible modes are circular or rectangular points in the colon
        Private Sub DrawColon(ByVal g As Graphics, ByVal type As colonType, ByVal bDim As Boolean)
            pen.Width = dimPen.Width = linewidth
            Dim p As Pen = IIf(bDim, dimPen, pen) ' choose a pen for blinking
            Select Case type
                Case colonType.Circular
                    g.DrawEllipse(p, colonRect1)
                    g.DrawEllipse(p, colonRect2)
                Case colonType.Rectangular
                    g.DrawRectangle(p, colonRect1)
                    g.DrawRectangle(p, colonRect2)
            End Select
        End Sub
 
        ' Draws the complete rectangle in dim shade to give the digital effect :-)
        Protected Friend Sub Draw(ByVal g As Graphics)
            ' althought pens are static, linewidths are specific to each instance
            dimPen.Width = linewidth
            For i As Integer = 0 To 6
                g.DrawLine(dimPen, Points(i * 2), Points(i * 2 + 1))
            Next
        End Sub
 
        ' Overloaded function to display characters 'A' and 'P' for AM and PM
        ' Using the same algorithm used to display numbers above
        Protected Friend Sub Draw(ByVal ch As Char, ByVal g As Graphics)
            ' 10 and 11 are indices of A and P in the displayNum array
            Select Case Char.ToUpper(ch)
                Case "A"
                    Draw(10, g)
                Case "P"
                    Draw(11, g)
            End Select
        End Sub
 
        ' Constructor takes a rectangle and prepares the end points
        ' of the lines to be drawn for the clock
        Public Sub New(ByVal rect As Rectangle)
            pen.StartCap = LineCap.Triangle
            pen.EndCap = LineCap.Triangle
 
            ReDim Points(14) ' there are 7 lines in a display
            For i As Integer = 0 To 13
                Points(i) = New Point(0, 0)
            Next
            CalculateAllParameters(rect)
        End Sub
 
        Sub CalculateAllParameters(ByVal rect As Rectangle)
            linewidth = CType((rect.Width / 5), Integer)
            If (linewidth < 2) Then linewidth = 2
            If (linewidth > 20) Then linewidth = 20
 
            pen.Width = linewidth
            setDimPen()
 
            CalculateLineEnds(rect)
            CalculateColonRectangles(rect)
        End Sub
 
        ' Function calculates end points of lines to display
        ' The draw function will draw lines using this data
        Private Sub CalculateLineEnds(ByVal rect As Rectangle)
            ' 0,1,2,9,10,11,12 points share the same left edge X coordinate
            Points(0).X = rect.Left
            Points(1).X = Points(0).X
            Points(2).X = Points(0).X
            Points(9).X = Points(0).X
            Points(10).X = Points(0).X
            Points(11).X = Points(0).X
            Points(12).X = Points(0).X
 
            ' points 3,4,5,6,7,8,13 the right edge X coordinate
            Points(3).X = rect.Right - CType(linewidth, Integer)
            Points(4).X = Points(3).X
            Points(5).X = Points(3).X
            Points(6).X = Points(3).X
            Points(7).X = Points(3).X
            Points(8).X = Points(3).X
            Points(13).X = Points(3).X
 
            ' Points 1,2,3,4 are the top most points
            Points(1).Y = CType(rect.Top, Integer)
            Points(2).Y = Points(1).Y
            Points(3).Y = Points(1).Y
            Points(4).Y = Points(1).Y
 
            ' Points 0,11,12,13,5,6 are the middle points
            Points(0).Y = rect.Top + CType(((rect.Height - linewidth) / 2.0), Integer)
            Points(11).Y = Points(0).Y
            Points(12).Y = Points(0).Y
            Points(13).Y = Points(0).Y
            Points(5).Y = Points(0).Y
            Points(6).Y = Points(0).Y
 
            ' points 7,8,9,10 are on the bottom edge
            Points(7).Y = rect.Top + CType((rect.Height - linewidth), Integer)
            Points(8).Y = Points(7).Y
            Points(9).Y = Points(7).Y
            Points(10).Y = Points(7).Y
 
            ' now adjust the coordinates that were computed, to get the digital look
            AdjustCoordinates()
        End Sub
 
        ' This function is necessary to give the lines a digital clock look
        ' Push the coordinates a little away so that they look apart
        Private Sub AdjustCoordinates()
            Dim swap As Point  ' required in case points have to be swapped
            For i As Integer = 0 To 6
                ' Always draw from left to right and top to bottom
                ' Adjust the end points accordingly
                If (Points(i * 2).X > Points((i * 2) + 1).X Or Points(i * 2).Y > Points((i * 2) + 1).Y) Then
                    swap = Points(i * 2)
                    Points(i * 2) = Points((i * 2) + 1)
                    Points((i * 2) + 1) = swap
                End If
 
                ' for horizontal lines adjust the X coord
                If (Points(i * 2).X <> Points((i * 2) + 1).X) Then
                    Points(i * 2).X += CType((linewidth / 1.6), Integer)
                    Points((i * 2) + 1).X -= CType((linewidth / 1.6), Integer)
                End If
                ' for vertical lines adjust the y coord
                If (Points(i * 2).Y <> Points((i * 2) + 1).Y) Then
                    Points(i * 2).Y += CType((linewidth / 1.6), Integer)
                    Points((i * 2) + 1).Y -= CType((linewidth / 1.6), Integer)
                End If
            Next
        End Sub
 
        ' function to calculate the rectangles required to drawn colon dot inside
        Private Sub CalculateColonRectangles(ByVal rect As Rectangle)
            colonRect2 = rect
            colonRect1 = rect
            colonRect1.X = colonRect2.X = rect.X + CType(((rect.Width - linewidth) / 2.0), Integer)
            colonRect1.Y = rect.Y + rect.Height / 3
            colonRect2.Y = rect.Y + (rect.Height * 2) / 3
            colonRect1.Width = CType(linewidth, Integer)
            colonRect1.Height = CType(linewidth, Integer)
            colonRect2.Width = CType(linewidth, Integer)
            colonRect2.Height = CType(linewidth, Integer)
        End Sub
    End Class
 
End Namespace

Open in new window

test-Draw.gif
0
 

Author Comment

by:tentavarious
ID: 21885531
ok, I am getting most of this figured out, the characters have the right size and thickness but I am still showing all 8's
test-Draw.gif
0
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21894613
Apologies, I've been in the middle of a crucial Firewall switch and it's taken a lot of time and effort to get it right :-)

I'll take a look at this tomorrow, hopefully. Good to see you've managed to make progress!
0
 

Author Comment

by:tentavarious
ID: 21910799
Ok, I got the user control to work with my app, but now I need help with the stop watch feature.  The demo app can be downloaded from this site:http://www.codeproject.com/KB/selection/DigitalClockControl.aspx.   The problem I am having with the stop watch feature is that I want to start it a specified timed, right now if I click the stop watch it automatically resets to all 0's.  I need to have it start, then if I switch to something else and switch back it will start back where it left off.
0
 
LVL 3

Expert Comment

by:GHCS_Mark
ID: 21915977
Which code are you using now, the demo or a modified version of it. or the control we had above?
0
 

Author Comment

by:tentavarious
ID: 21916124
I am using, the demo's usercontrol and trying to modified.
0
 
LVL 3

Accepted Solution

by:
GHCS_Mark earned 500 total points
ID: 21917150
OK, in the demo project is has SetClockType() in DigitalClockCtrl.cs and when it sets the type to StopWatch it has a line that reads:

stopwatchBegin = DateTime.Now

What you will need to do, is when you want to freeze the clock, find the difference as a TimeSpan between stopwatchBegin and DateTime.Now.  Then, when you come to "unfreeze" the time, you simply subtract the TimeSpan from the current DateTime.Now value as you are setting it.

You will need to differentiate between starting the start watch and stop it. So therefore, maybe have function as so (untested so may need fixing up):

void StartStopWatch()
{
    stopwatchBegin = DateTime.Now;
    clockType = ClockType.StopWatch;
}

void ContinueStopWatch(ts Timespan)
{
    stopwatchBegin = (DateTime.Now - ts)
}
0
 

Author Closing Comment

by:tentavarious
ID: 31470561
Thank you, I modified the code a little to get the same results.  Works great now thanks again.
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In my previous two articles we discussed Binary Serialization (http://www.experts-exchange.com/A_4362.html) and XML Serialization (http://www.experts-exchange.com/A_4425.html). In this article we will try to know more about SOAP (Simple Object Acces…
This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

756 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question