Clock animation : Clock : Drawing 2D C# Examples


C# Examples » Drawing 2D » Clock »

 

Clock animation








    
/*  Quote  from  

Programming  .NET  Windows  Applications

By  Jesse  Liberty,  Dan  Hurwitz
First  Edition  October  2003  
Pages:  1246  (More  details)
*/


using  System;
using  System.Collections;
using  System.ComponentModel;
using  System.Data;
using  System.Drawing;
using  System.Drawing.Drawing2D;
using  System.Timers;
using  System.Windows.Forms;


namespace  Clock3CS
{
    //  Rename  the  class
    public  class  ClockFace  :  System.Windows.Forms.Form
    {
        //  Required  designer  variable.
        private  System.ComponentModel.Container  components  =  null;
    
        private  int  FaceRadius  =  450;        //  size  of  the  clock  face
        private  bool  b24Hours  =  false;        //  24  hour  clock  face?
        private  System.Windows.Forms.Button  btnClockFormat;        
        private  DateTime  currentTime;        //  used  in  more  than  one  method

        //  new
        private  int  xCenter;                //  center  of  the  clock
        private  int  yCenter;
        private  static  int  DateRadius  =  600;  //  outer  circumference  for  date
        private  static  int  Offset  =  0;        //  for  moving  the  text  
        Font  font  =  new  Font("Arial",  40);    //  use  the  same  font  throughout
        private  StringDraw  sdToday;            //  the  text  to  animate

        public  ClockFace()
        {
            //  Required  for  Windows  Form  Designer  support
            InitializeComponent();

            //  use  the  user's  choice  of  colors
            BackColor  =  SystemColors.Window;
            ForeColor  =  SystemColors.WindowText;

        
            //  ***  begin  new
            string  today  =  System.DateTime.Now.ToLongDateString();
            today  =  "  "  +  today.Replace(",","");
            
            //  create  a  new  stringdraw  object  with  today's  date
            sdToday  =  new  StringDraw(today,this);
            currentTime  =  DateTime.Now;


            //  set  the  current  center  based  on  the
            //  client  area
            xCenter  =  Width  /  2;
            yCenter  =  Height  /  2;


            //  ***  end  new


            //  update  the  clock  by  timer
            System.Timers.Timer  timer  =  new  System.Timers.Timer();
            timer.Elapsed  +=  new  System.Timers.ElapsedEventHandler(OnTimer);
            timer.Interval  =  20;    //  shorter  interval  -  more  movement
            timer.Enabled  =  true;


        }

        protected  override  void  OnPaint  (  PaintEventArgs  e  )
        {
            base.OnPaint(e);
            Graphics  g  =  e.Graphics;
            SetScale(g);
            DrawFace(g);
            DrawTime(g,true);    //  force  an  update
        }

        //  every  time  the  timer  event  fires,  update  the  clock
        public  void  OnTimer(Object  source,  ElapsedEventArgs  e)
        {
            Graphics  g  =  this.CreateGraphics();

            SetScale(g);
            DrawFace(g);
            DrawTime(g,false);
            DrawDate(g);
            g.Dispose();        
            
        }


        #region  Windows  Form  Designer  generated  code
        protected  override  void  Dispose(  bool  disposing  )
        {
            if(  disposing  )
            {
                if  (components  !=  null)  
                {
                    components.Dispose();
                }
            }
            base.Dispose(  disposing  );
        }

        
        ///  <summary>
        ///  Required  method  for  Designer  support  -  do  not  modify
        ///  the  contents  of  this  method  with  the  code  editor.
        ///  </summary>
        private  void  InitializeComponent()
        {
            this.btnClockFormat  =  new  System.Windows.Forms.Button();
            this.SuspendLayout();
            //  
            //  btnClockFormat
            //  
            this.btnClockFormat.Location  =  new  System.Drawing.Point(8,  8);
            this.btnClockFormat.Name  =  "btnClockFormat";
            this.btnClockFormat.TabIndex  =  1;
            this.btnClockFormat.Text  =  "24  Hours";
            this.btnClockFormat.Click  +=  new  System.EventHandler(this.btnClockFormat_Click);
            //  
            //  ClockFace
            //  
            this.AutoScaleBaseSize  =  new  System.Drawing.Size(5,  13);
            this.ClientSize  =  new  System.Drawing.Size(292,  266);
            this.Controls.AddRange(new  System.Windows.Forms.Control[]  {
                                                                            this.btnClockFormat});
            this.Name  =  "ClockFace";
            this.Text  =  "Clock3CS";
            this.MouseDown  +=  new  System.Windows.Forms.MouseEventHandler(this.ClockFace_MouseDown);
            this.ResumeLayout(false);

        }
        #endregion

        [STAThread]
        static  void  Main()  
        {
            Application.Run(new  ClockFace());
        }

        private  void  SetScale(Graphics  g)
        {
            //  if  the  form  is  too  small,  do  nothing
            if  (  Width  ==  0  ||  Height  ==  0  )
                return;

            //  set  the  origin  at  the  center
            g.TranslateTransform(xCenter,  yCenter);    //  use  the  members  vars

            //  set  inches  to  the  minimum  of  the  width  
            //  or  height  dividedby  the  dots  per  inch    
            float  inches  =  Math.Min(Width  /  g.DpiX,  Height  /  g.DpiX);

            //  set  the  scale  to  a  grid  of  2000  by  2000  units
            g.ScaleTransform(
                inches  *  g.DpiX  /  2000,  inches  *  g.DpiY  /  2000);
        }

        private  void  DrawFace(Graphics  g)
        {
            //  numbers  are  in  forecolor  except  flash  number  in  green
            //  as  the  seconds  go  by.
            Brush  brush  =  new  SolidBrush(ForeColor);
            float  x,  y;

            //  new  code
            int  numHours  =  b24Hours  ?  24  :  12;
            int  deg  =  360  /  numHours;
            
            //  for  each  of  the  hours  on  the  clock  face
            for  (int  i  =  1;  i  <=  numHours;  i++)
            {
                //  i  =  hour    30  degrees  =  offset  per  hour    
                //  +90  to  make  12  straight  up
                x  =  GetCos(i*deg  +  90)  *  FaceRadius;
                y  =  GetSin(i*deg  +  90)  *  FaceRadius;

                StringFormat  format  =  new  StringFormat();
                format.Alignment  =  StringAlignment.Center;
                format.LineAlignment  =  StringAlignment.Center;

                g.DrawString(
                    i.ToString(),  font,  brush,  -x,  -y,format);
            
            }    //  end  for  loop
        }        //  end  drawFace


        private  void  DrawTime(Graphics  g,  bool  forceDraw)
        {

            //    length  of  the  hands
            float  hourLength  =  FaceRadius  *  0.5f;
            float  minuteLength  =  FaceRadius  *  0.7f;
            float  secondLength  =  FaceRadius  *  0.9f;

            //  set  to  back  color  to  erase  old  hands  first
            Pen  hourPen  =  new  Pen(BackColor);
            Pen  minutePen  =  new  Pen(BackColor);
            Pen  secondPen  =  new  Pen(BackColor);

            //  set  the  arrow  heads
            hourPen.EndCap  =  LineCap.ArrowAnchor;
            minutePen.EndCap  =  LineCap.ArrowAnchor;

            //  hour  hand  is  thicker
            hourPen.Width  =  30;
            minutePen.Width  =  20;

            //  second  hand  
            Brush  secondBrush  =  new  SolidBrush(BackColor);
            const  int  EllipseSize  =  50;

            GraphicsState  state;    //  to  to  protect  and  to  serve


            //  1  -  delete  the  old  time

            //  delete  the  old  second  hand
            //  figure  out  how  far  around  to  rotate  to  draw  the  second  hand
            //  save  the  current  state,  rotate,  draw  and  then  restore  the  state
            float  rotation  =  GetSecondRotation();
            state  =  g.Save();
            g.RotateTransform(rotation);
            g.FillEllipse(
                secondBrush,
                -(EllipseSize/2),
                -secondLength,
                EllipseSize,
                EllipseSize);
            g.Restore(state);

            DateTime  newTime  =  DateTime.Now;
            bool  newMin  =  false;    //  has  the  minute  changed?

            //  if  the  minute  has  changed,  set  the  flag
            if  (  newTime.Minute  !=  currentTime.Minute  )
                newMin  =  true;


            //  if  the  minute  has  changed  or  you  must  draw  anyway  then  you  
            //  must  first  delete  the  old  minute  and  hour  hand
            if  (  newMin    ||  forceDraw  )
            {

                //  figure  out  how  far  around  to  rotate  to  draw  the  minute  hand
                //  save  the  current  state,  rotate,  draw  and  then  restore  the  state
                rotation  =  GetMinuteRotation();
                state  =  g.Save();
                g.RotateTransform(rotation);
                g.DrawLine(minutePen,0,0,0,-minuteLength);
                g.Restore(state);

                //  figure  out  how  far  around  to  rotate  to  draw  the  hour  hand
                //  save  the  current  state,  rotate,  draw  and  then  restore  the  state
                rotation  =  GetHourRotation();
                state  =  g.Save();
                g.RotateTransform(rotation);
                g.DrawLine(hourPen,0,0,0,-hourLength);
                g.Restore(state);
            }

            //  step  2  -  draw  the  new  time
            currentTime  =  newTime;

            hourPen.Color  =  Color.Red;
            minutePen.Color  =  Color.Blue;
            secondPen.Color  =  Color.Green;
            secondBrush  =  new  SolidBrush(Color.Green);

            //  draw  the  new  second  hand
            //  figure  out  how  far  around  to  rotate  to  draw  the  second  hand
            //  save  the  current  state,  rotate,  draw  and  then  restore  the  state
            state  =  g.Save();
            rotation  =  GetSecondRotation();
            g.RotateTransform(rotation);
            g.FillEllipse(
                secondBrush,
                -(EllipseSize/2),
                -secondLength,
                EllipseSize,
                EllipseSize);
            g.Restore(state);

            //  if  the  minute  has  changed  or  you  must  draw  anyway  then  you  
            //  must  draw  the  new  minute  and  hour  hand
            if  (  newMin  ||  forceDraw  )
            {

                //  figure  out  how  far  around  to  rotate  to  draw  the  minute  hand
                //  save  the  current  state,  rotate,  draw  and  then  restore  the  state
                state  =  g.Save();
                rotation  =  GetMinuteRotation();
                g.RotateTransform(rotation);
                g.DrawLine(minutePen,0,0,0,-minuteLength);
                g.Restore(state);

                //  figure  out  how  far  around  to  rotate  to  draw  the  hour  hand
                //  save  the  current  state,  rotate,  draw  and  then  restore  the  state
                state  =  g.Save();
                rotation  =  GetHourRotation();
                g.RotateTransform(rotation);
                g.DrawLine(hourPen,0,0,0,-hourLength);
                g.Restore(state);
            }
        }

        //  determine  the  rotation  to  draw  the  hour  hand
        private  float  GetHourRotation()
        {
            //  degrees  depend  on  24  vs.  12  hour  clock
            float  deg  =  b24Hours  ?  15  :  30;
            float  numHours  =  b24Hours  ?  24  :  12;
            return(  360f  *  currentTime.Hour  /  numHours  +
                deg  *  currentTime.Minute  /  60f);
        }

        private  float  GetMinuteRotation()
        {
            return(  360f  *  currentTime.Minute  /  60f  );  
        }

        private  float  GetSecondRotation()
        {
            return(360f  *  currentTime.Second  /  60f);
        }

        private  static  float  GetSin(float  degAngle)
        {
            return  (float)  Math.Sin(Math.PI  *  degAngle  /  180f);
        }

        private  static  float  GetCos(float  degAngle)
        {
            return  (float)  Math.Cos(Math.PI  *  degAngle  /  180f);
        }

        private  void  btnClockFormat_Click(object  sender,  System.EventArgs  e)
        {
            btnClockFormat.Text  =  b24Hours  ?  "24  Hour"  :  "12  Hour";
            b24Hours  =  !  b24Hours;
            this.Invalidate();
        }

        private  void  DrawDate(Graphics  g)
        {
            Brush  brush  =  new  SolidBrush(ForeColor);
            sdToday.DrawString(g,brush);
        }

        private  void  ClockFace_MouseDown(
            object  sender,  System.Windows.Forms.MouseEventArgs  e)
        {
            xCenter  =  e.X;
            yCenter  =  e.Y;
            this.Invalidate();
        
        }


        //  each  letter  in  the  outer  string  knows  how  to  draw  itself
        private  class  LtrDraw
        {
            char  myChar;        //  the  actual  letter  i  draw
            float  x;            //  current  x  coordinate
            float  y;            //  current  y  coordinate
            float  oldx;            //  old  x  coordinate  (to  delete)
            float  oldy;            //  old  y  coordinate  (to  delete)
            

            //  constructor
            public  LtrDraw(char  c)
            {
                myChar  =  c;
            }

            //  property  for  X  coordinate
            public  float  X
            {
                get  {  return  x;  }
                set  {  oldx  =  x;  x  =  value;  }
            }

            //  property  for  Y  coordinate
            public  float  Y
            {
                get  {  return  y;  }
                set  {  oldy  =  y;  y  =  value;  }
            }

            //  get  total  width  of  the  string
            public  float  GetWidth(Graphics  g,  Font  font)
            {
                SizeF  stringSize  =  g.MeasureString(myChar.ToString(),font);
                return  stringSize.Width;
            }

            //  get  total  height  of  the  string
            public  float  GetHeight(Graphics  g,  Font  font)
            {
                SizeF  stringSize  =  g.MeasureString(myChar.ToString(),font);
                return  stringSize.Height;
            }


            //  get  the  font  from  the  control  and  draw  the  current  character
            //  First  delete  the  old  and  then  draw  the  new
            public  void  DrawString(Graphics  g,  Brush  brush,  ClockFace  cf)
            {
                Font  font  =  cf.font;
                Brush  blankBrush  =  new  SolidBrush(cf.BackColor);
                g.DrawString(myChar.ToString(),font,blankBrush,oldx,oldy);
                g.DrawString(myChar.ToString(),font,brush,x,y);
            }

        }

        //  holds  an  array  of  LtrDraw  objects
        //  and  knows  how  to  tell  them  to  draw
        private  class  StringDraw
        {
            ArrayList  theString  =  new  ArrayList();
            LtrDraw  l;
            ClockFace  theControl;

            //  constructor  takes  a  string,  populates  the  array
            //  and  stashes  away  the  calling  control  (ClockFace)
            public  StringDraw(string  s,  ClockFace  theControl)
            {
                this.theControl  =  theControl;
                foreach  (char  c  in  s)
                {
                    l  =  new  LtrDraw(c);
                    theString.Add(l);
                }
            }

            //  divide  the  circle  by  the  number  of  letters
            //  and  draw  each  letter  in  position
            public  void  DrawString(Graphics  g,  Brush  brush)
            {
                int  angle  =  360  /  theString.Count;
                int  counter  =  0;

                foreach  (LtrDraw  theLtr  in  theString)
                {
                    //  1.  To  find  the  X  coordinate,  take  the  Cosine  of  the  angle
                    //  and  multiply  by  the  radius.
                    //  2.  To  compute  the  angle,  start  with  the  base  angle  
                    //  (360  divided  by  the  number  of  letters)
                    //  and  multiply  by  letter  position.
                    //  Thus  if  each  letter  is  10  degrees,  and  this  is  the  third
                    //  letter,  you  get  30  degrees.  Add  90  to  start  at  12  O'clock.
                    //  Each  time  through,  subtract  the  clockFace  offset  to  move  
                    //  the  entire  string  around  the  clock  on  each  timer  call
                    float  newX  =  GetCos(angle    *  counter  +  90  -  ClockFace.Offset)  *  ClockFace.DateRadius  ;
                    float  newY  =  GetSin(angle  *  counter  +  90  -  ClockFace.Offset)  *  ClockFace.DateRadius  ;
                    theLtr.X  =  
                        newX  -  (theLtr.GetWidth(g,theControl.font)  /  2);
                    theLtr.Y  =  
                        newY  -  (theLtr.GetHeight(g,theControl.font)  /  2);
                    counter++;
                    theLtr.DrawString(g,brush,theControl);
                }
                ClockFace.Offset  +=  1;    //  rotate  the  entire  string
            }
        }

    }    //  end  class
}        //  end  namespace
    
   
  
   




HTML code for linking to this page:

Follow Navioo On Twitter

C# Examples

 Navioo Drawing 2D
» Clock