Project ProjectIcon

 

Project Clock

The main window (and only window) in project Clock is shown below:

image from book
Figure 21-1: Clock project

A listing of the code that generates this clock is shown at the end of this section. The complete project is located at Visual Studio 2005\Projects\ DemosSourceCode\Clock.

This is how the project is created in the IDE:

  1. A new project named Clock is created in the IDE and the main window template is set to a size of 600 x 600 (which is about as large as a main window can be, unless it is created as full screen). The Start Position property is set to Center Screen .

  2. This window requires painting, so, while the window template is highlighted, the programmer must move to the Properties window, click on the Events icon, and click on the Appearance | Paint entry to produce an event handler named Form1_Paint in the Form1.cs source code. A second handler is also required. Click on Behavior | Load to produce a Form1_Load event handler in the Form1.cs source code.

  3. A Quit button is placed at the lower-right corner of the window. Its event handler is created by double-clicking on the button, and the statement Close() is placed in that event handler.

  4. With the main window highlighted (and the main window properties present in the Properties window), the Toolbox is selected and the Timer icon is clicked. The window template is then clicked to produce a timer1 rectangle at the bottom of the IDE (showing that the timer is now a part of this project). The timer rectangle is highlighted so its properties will appear in the Properties window. All you have to do to create its default event handler is double-click on the timer1 rectangle at the bottom of the IDE screen.

    Note  

    In the timer1 properties, one of the Behavior properties is Interval, and the default setting is 100. We have asked several Microsoft people what this timer interval = 100 has to do with the timer.interval setting in line XC027 of the Clock project, but so far we have received no answer. This timer interval (the one in Behavior properties) has an enabled/disabled setting above the timer interval number, but nothing changes if the item is enabled or disabled, or if the 100 is changed to another value. For now, we will ignore this setting in Behavior properties.

  5. As an added feature (totally apart from clock control), an icon named DateTimePicker is clicked in the Toolbox and brought over to the window template. This places a DateTime window in the upper left of the template (and it works with no further actions by the programmer). This DateTimePicker is not required to create the clock.

Everything else that appears on the clock is painted onto the surface; no more window template work is required.

This is how Clock works:

  1. A timer is placed in the declaration of Form1 (in lines XC025-XC028). Line XC026 ties the timer (which is created in XC025) to event handler timer1_Tick. Line XC027 sets the timer interval at 1000 nanoseconds, causing the timer to emit a tick every 1 second.

    You may want to reset this number from 1000 to 100 and note the effect it has on the clock, since a timer.Interval setting of 100 causes the clock mechanism to sample DateTime.Now at a rate of 10 times per second. This causes the display to shake since the refresh time of the clock is so fast.

    If you reset the timer.Interval number to 10000, the clock mechanism samples DateTime.Now every 10 seconds. This causes the hands of the clock to jump every 10 seconds. Since a timer.Interval number of 100 causes the clock face to jitter, and a timer interval of 10000 causes the clock face to remain stationary for several seconds, then jump to the next position, it appears that the timer.Interval setting of 1000 in line XC027 is best.

    Line XC028 starts the timer. This timer is turned off only when the project is exited.

  2. The computations to create the face of the clock are made in lines XC042-XC046 of the Form1_Load event handler when the window is created. The X and Y coordinates are used in the event handler Form1_Paint later.

  3. Line XC048 invokes DateTime for the first time, giving the Form1_Paint event handler an input set to use the first time the clock operation begins. The program works correctly even if line XC048 is eliminated.

  4. Once the timer starts (and calls event handler timer1_Tick one time a second) the DateTime.Now data is generated fast enough to move the clock hands smoothly. Event handler Form1_Paint is called automatically by the operating system at a rate of about 30 times per second (so the image on the screen will not flicker when viewed by the user ).

  5. Inside event handler Form1_Paint these events occur:

    1. Lines XC063-XC067 set up the four colored pens and the Arial font.

    2. Lines XC068-XC070 paint the outer edge of the clock.

    3. Lines XC071-XC072 paint the numbers 12 and 1 through 11 on the clock face.

    4. Lines XC073-XC074 paint an X in the middle of the clock.

    5. Lines XC075-XC079 compute the coordinates of the outer end of the second hand (the end not at the center of the clock).

    6. Lines XC080-XC084 compute the coordinates of the end of the minute hand.

    7. Lines XC085-XC089 compute the coordinates of the end of the hour hand.

    8. Lines XC090-XC092 draw the second, minute, and hour hands (second hand in blue, minute hand in green, and hour hand in red).

  1. Event handler timer1_Tick performs the task of acquiring DateTime.Now and spreading the data out into its individual elements. The Invalidate() statement in line XC115 is extremely important: It commands the repainting of the screen using the latest data. If you turn this statement off, the clock stops.

This particular clock is a slave to DateTime.Now. That is, it gets all its data from the PC in which it is working, and makes no effort to compute time on its own. The only time the position of a second, minute, or hour hand changes is when DateTime.Now changes. With the Tick Count described in the next part of this chapter it would be possible to call DateTime.Now one time to get the current time, then compute all clock movements from that point on using tick counts. Or you could devise a program where the user sets the current time manually and starts the clock. But why bother?

Clock (XC) Listing

 Form1.cs: XC002:        using System; XC003:        using System.Collections.Generic; XC004:        using System.ComponentModel; XC005:        using System.Data; XC006:        using System.Drawing; XC007:        using System.Windows.Forms; XC009:        namespace Clock XC010:        { XC011:          partial class Form1 : Form XC012:          { XC013:            DateTime dt, dtNow; XC014:            int[] X = new int[12]; XC015:            int[] Y = new int[12]; XC016:            int[] PtX = new int[] { 300, 320, 300, 280 }; XC017:            int[] PtY = new int[] { 240, 260, 280, 260 };                   // Set center of clock: XC018:            int CtrPtX = 300; XC019:            int CtrPtY = 260; XC020:            int[] NumX = new int[] {280,405,490,520,490,405,285,170,87,50,80,165}; XC021:            int[] NumY = new int[] {10,40,125,240,360,445,475,445,360,240,130,40}; XC022:            string[] strHours = new string[12] {"12","1","2","3","4","5","6","7",                                                       "8","9","10","11"}; XC023:            public Form1() XC024:            { XC025:              Timer timer = new Timer(); XC026:            timer.Tick += new EventHandler(timer1_Tick); XC027:            timer.Interval = 1000; // 1 sample per second. XC028:            timer.Start(); XC029:            InitializeComponent(); XC030:          } //-----------------------------------------------------------------------------------------// XC040:          private void Form1_Load(object sender, EventArgs e) XC041:          { // Configure clock face.                   // Compute coords for clock face outer edge: XC042:            for(int jj = 0; jj < 12; jj++) XC043:            { // Angle in radians: XC044:              double AiR = (15.0 + 30.0 * jj) * 3.1416 / 180.0; XC045:              X[jj] = 300 + (int) Math.Round((258.8 * Math.Sin(AiR)), 0); XC046:              Y[jj] = 260 - (int) Math.Round ((258.8 * Math.Cos(AiR)), 0); XC047:            } XC048:          dtNow = DateTime.Now; XC049:          } //-----------------------------------------------------------------------------------------// XC060:            private void Form1_Paint(object sender, PaintEventArgs e) XC061:            { // Paint the window. XC062:              Graphics grfx = e.Graphics; XC063:              Pen blackPen = new Pen(Color.Black, 2); XC064:              Pen bluePen = new Pen(Color.Blue, 3); XC065:              Pen greenPen = new Pen(Color.Green, 4); XC066:              Pen redPen = new Pen(Color.Red, 6); XC067:              Font font1 = new Font("Arial", 24);                     // Paint the outer edge of the clock. XC068:              for(int kk = 0; kk < 11; kk++) XC069:              grfx.DrawLine(blackPen, X[kk], Y[kk], X[kk+1], Y[kk+1]); XC070:              grfx.DrawLine(blackPen, X[11], Y[11], X[0], Y[0]);                     // Paint hours: 12,1,2,3,4,5,6,7,8,9,10,11. XC071:              for(int mm = 0; mm < 12; mm++) XC072:              grfx.DrawString(strHours[mm],font1,Brushes.Black,NumX[mm],NumY[mm]);                     // Paint an 'X' in the center of the clock. XC073:              grfx.DrawLine(blackPen, PtX[0], PtY[0], PtX[2], PtY[2]); XC074:              grfx.DrawLine(blackPen, PtX[1], PtY[1], PtX[3], PtY[3]);                     // Paint the second, minute, and hour hands.                     // Set the second hand. XC075:              double SHAngle = (dtNow.Second / 60.0) * 6.2832; XC076:              double RadiansSin = Math.Sin(SHAngle); XC077:              double RadiansCos = Math.Cos(SHAngle); XC078:              int SHPX = 300 + (int) Math.Round(250.0 * RadiansSin,0); XC079:              int SHPY = 260 - (int) Math.Round(250.0 * RadiansCos,0);                     // Set the minute hand. XC080:              SHAngle = (dtNow.Minute / 60.0) * 6.2832; XC081:              RadiansSin = Math.Sin(SHAngle); XC082:              RadiansCos = Math.Cos(SHAngle); XC083:              int MHPX = 300 + (int) Math.Round(240.0 * RadiansSin,0); XC084:              int MHPY = 260 - (int) Math.Round(240.0 * RadiansCos,0);                     // Set the hour hand. XC085:              SHAngle = (dtNow.Hour/12.0) * 6.2832 + ((dtNow.Minute/60.0) *                                6.2832 / 12.0); XC086:              RadiansSin = Math.Sin(SHAngle); XC087:              RadiansCos = Math.Cos(SHAngle); XC088:              int HHPX = 300 + (int) Math.Round(150.0 * RadiansSin,0); XC089:              int HHPY = 260 - (int) Math.Round(150.0 * RadiansCos,0);                     // Draw second hand. XC090:              grfx.DrawLine(bluePen, CtrPtX, CtrPtY, SHPX, SHPY);                     // Draw minute hand. XC091:              grfx.DrawLine(greenPen, CtrPtX, CtrPtY, MHPX, MHPY);                     // Draw hour hand. XC092:              grfx.DrawLine(redPen, CtrPtX, CtrPtY, HHPX, HHPY); XC093:            } //-----------------------------------------------------------------------------------------// XC100:            private void button1_Click(object sender, EventArgs e) XC101:            { // Quit. XC102:              Close(); XC103:            } //-----------------------------------------------------------------------------------------// XC110:            private void timer1_Tick(object sender, EventArgs e) XC111:            { // Get current time. XC112:              dtNow = DateTime.Now; XC113:              dtNow = new DateTime(dtNow.Year, dtNow.Month, dtNow.Day, dtNow.Hour,                                          dtNow.Minute, dtNow.Second); XC114:              if(dtNow != dt) dt = dtNow;                     // This next statement is extremely important! Turn it off and                     // see what happens. XC115:              Invalidate(); XC116:            } XC117:          } XC118:        } //=========================================================================================// Form1.Designer.cs: XC140:        namespace Clock XC141:        { XC142:          partial class Form1 XC143:          {                   // Required designer variable. XC144:            private System.ComponentModel.IContainer components = null;                   // Clean up any resources being used. XC145:            protected override void Dispose(bool disposing) XC146:            { XC147:              if (disposing && (components != null)) components.Dispose(); XC148:              base.Dispose(disposing); XC149:            } XC150:            #region Windows Form Designer generated code                   // Required method for Designer support. XC151:            private void InitializeComponent() XC152:            { XC153:              this.components = new System.ComponentModel.Container(); XC154:              this.button1 = new System.Windows.Forms.Button(); XC155:              this.dateTimePicker1 = new System.Windows.Forms.DateTimePicker(); XC156:              this.timer1 = new System.Windows.Forms.Timer(this.components); XC157:              this.SuspendLayout();                     //                     // button1                     // XC158:              this.button1.Location = new System.Drawing.Point(476, 483); XC159:              this.button1.Name = "button1"; XC160:              this.button1.Size = new System.Drawing.Size(75, 25); XC161:              this.button1.TabIndex = 0; XC162:              this.button1.Text = "Quit"; XC163:              this.button1.Click += new System.EventHandler(this.button1_Click);                     //                     // dateTimePicker1                     // XC164:              this.dateTimePicker1.Location = new System.Drawing.Point(2, 3); XC165:              this.dateTimePicker1.Name = "dateTimePicker1"; XC166:              this.dateTimePicker1.TabIndex = 1;                     //                     // timer1                     // XC167:              this.timer1.Tick += new System.EventHandler(this.timer1_Tick);                     //                     // Form1                     // XC168:              this.AutoScaleDimensions = new System.Drawing.SizeF(5F, 13F); XC169:              this.ClientSize = new System.Drawing.Size(584, 532); XC170:              this.Controls.Add(this.dateTimePicker1); XC171:              this.Controls.Add(this.button1); XC172:              this.Name = "Form1"; XC173:              this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; XC174:              this.Text = "Clock"; XC175:              this.Paint += new System.Windows.Forms.PaintEventHandler                                   (this.Form1_Paint); XC176:              this.Load += new System.EventHandler(this.Form1_Load); XC177:              this.ResumeLayout(false); XC178:            } XC179:            #endregion XC180:            private System.Windows.Forms.Button button1; XC181:            private System.Windows.Forms.DateTimePicker dateTimePicker1; XC182:            private System.Windows.Forms.Timer timer1; XC183:          } XC184:        } 
 


Unlocking Microsoft C# V 2.0 Programming Secrets
Unlocking Microsoft C# V 2.0 Programming Secrets (Wordware Applications Library)
ISBN: 1556220979
EAN: 2147483647
Year: 2005
Pages: 129

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net