locked
How can I make a running clock / timer ?

    Question

  • To the Community,

     

    I've been very fortunate to use the expertise of this community for help recently, and now I have my own question which I hope you all can help me with.

     

    As part of a program I am writing, I want to have a running clock. Basically, this is the way I want it to function:

     

    On the form to begin with will be text, maybe a label that reads "00:00".

    After the user clicks a button reading "start/pause" they will see the seconds start ticking on the clock.

    If they click "start/pause" again, the time will pause on whatever the time was when they clicked.

    If they click "start/pause" again, the time will start where it left off at the last click.

    Another button reading "reset" will reset the clock back to "00:00".

     

    If anyone can lend a hand, it would be much appreciated!

    --MLT34

    Saturday, December 06, 2008 3:51 AM

Answers

  • I remembered that there is another Timer in System.Windows.Forms that is designed for a single-threaded environment.

    No need for the Dispatcher.BeginInvoke method.

     

    Code Snippet

    using System;

    using System.Windows;

     

    namespace WpfApplication1

    {

    public partial class Window1 : Window

    {

    private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();

    private TimeSpan time = new TimeSpan();

     

    public Window1()

    {

    InitializeComponent();

     

    timer.Interval = 100;

    timer.Tick += new EventHandler(timer_Tick);

    }

     

    void timer_Tick(object sender, EventArgs e)

    {

    time = time.Add(TimeSpan.FromMilliseconds(100));

    timeTextBlock.Text = string.Format("{0}:{1}", time.Minutes, time.Seconds);

    }

     

    private void startStopButton_Click(object sender, RoutedEventArgs e)

    {

    if (timer.Enabled)

    timer.Enabled = false;

    else

    timer.Enabled = true;

    }

     

    private void resetButton_Click(object sender, RoutedEventArgs e)

    {

    time = TimeSpan.FromMilliseconds(0);

    timeTextBlock.Text = "0:0";

    }

    }

    }

     

     

    I noticed that this stopwatch counts a little slower than an actual clock due to the cummulative error.

    You will have to fix that.

    Saturday, December 06, 2008 3:56 PM

All replies

  • Note that the following code uses the WPF API (not Windows Forms).

     

    Code Snippet

    using System;

    using System.Timers;

    using System.Windows;

    using System.Windows.Threading;

     

    namespace WpfApplication1

    {

    public partial class Window1 : Window

    {

    private Timer timer = new Timer(100);

    private TimeSpan time = new TimeSpan();

     

    private delegate void LabelUpdaterDelegete();

     

    public Window1()

    {

    InitializeComponent();

    timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

    }

     

    private void timer_Elapsed(object sender, ElapsedEventArgs e)

    {

    time = time.Add(TimeSpan.FromMilliseconds(100));

    this.Dispatcher.BeginInvoke(new LabelUpdaterDelegete(UpdateLabel), DispatcherPriority.Normal);

    }

     

    private void UpdateLabel()

    {

    timeLabel.Content = string.Format("{0}:{1}", time.Minutes, time.Seconds);

    }

     

    private void startStopButton_Click(object sender, RoutedEventArgs e)

    {

    if (timer.Enabled)

    timer.Enabled = false;

    else

    timer.Enabled = true;

    }

     

    private void resetButton_Click(object sender, RoutedEventArgs e)

    {

    time = TimeSpan.FromMilliseconds(0);

    }

    }

    }

     

    timeLabel can only be accessed by the thread that created it. But the timer_Elapsed event handler is executed in another thread. So you need it to update the Label's Content in a thread safe manner. This is what the Dispatcher.BeginInvoke method is for.

     

    I have no idea how to do the same thing using Windows Forms.

    Saturday, December 06, 2008 9:18 AM
  • I remembered that there is another Timer in System.Windows.Forms that is designed for a single-threaded environment.

    No need for the Dispatcher.BeginInvoke method.

     

    Code Snippet

    using System;

    using System.Windows;

     

    namespace WpfApplication1

    {

    public partial class Window1 : Window

    {

    private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();

    private TimeSpan time = new TimeSpan();

     

    public Window1()

    {

    InitializeComponent();

     

    timer.Interval = 100;

    timer.Tick += new EventHandler(timer_Tick);

    }

     

    void timer_Tick(object sender, EventArgs e)

    {

    time = time.Add(TimeSpan.FromMilliseconds(100));

    timeTextBlock.Text = string.Format("{0}:{1}", time.Minutes, time.Seconds);

    }

     

    private void startStopButton_Click(object sender, RoutedEventArgs e)

    {

    if (timer.Enabled)

    timer.Enabled = false;

    else

    timer.Enabled = true;

    }

     

    private void resetButton_Click(object sender, RoutedEventArgs e)

    {

    time = TimeSpan.FromMilliseconds(0);

    timeTextBlock.Text = "0:0";

    }

    }

    }

     

     

    I noticed that this stopwatch counts a little slower than an actual clock due to the cummulative error.

    You will have to fix that.

    Saturday, December 06, 2008 3:56 PM
  • Thank you for your help. I'm a little new at visual c# programming, so I dont' know all the nitty gritty yet. What is a wpf or an api? Will I be able to copy and paste the code you wrote directly into my windows application I am making in visual c#? Thanks
    --MLT34
    Saturday, December 06, 2008 4:55 PM
  • What I wrote is a "code snippet", not a complete program.

    My second code snippet will not need any significant modification to work with Windows Forms.

    You will need some understanding of what I am doing to be able to copy and paste correctly.

    Saturday, December 06, 2008 6:36 PM
  • Thanks! I have a fair amount of C++ and Matlab programming experience, and am just delving into visual c#. I pretty much understand your second snippet of code, I'll just need to change some names to integrate it with what I have so far. Thanks again.
    --MLT34
    Saturday, December 06, 2008 7:36 PM
  •  MLT34 wrote:
    Thanks! I have a fair amount of C++ and Matlab programming experience, and am just delving into visual c#. I pretty much understand your second snippet of code, I'll just need to change some names to integrate it with what I have so far. Thanks again.
    --MLT34

     

    You are welcome.

    I did not write the code snippets for Windows Forms because I have partially no experience with Windows Forms.

    Saturday, December 06, 2008 7:55 PM
  • Hi-
    Here is the code which does the task for you. It can create an application that can run as a simple stopclock/timer with
    Start/Pause/Reset options. It displays the timer in Hours, Minutes, Seconds and Milliseconds format and you can
    always add enhancements to it to perform more functions.

    Here is how it looks like:
    http://cid-55ab8d8379ce0155.skydrive.live.com/self.aspx/.Public/Public%20Folder/Img%2001.JPG
    http://cid-55ab8d8379ce0155.skydrive.live.com/self.aspx/.Public/Public%20Folder/Img%2002.JPG

    StopWatch.cs

    using System;
    using System.Drawing;
    using System.Windows.Forms;

    namespace Timer
    {
        public partial class Stopwatch : Form
        {
            int MilliSeconds;
            int Seconds;
            int Minutes;
            int Hours;
            string resetToZero = "00";
            DateTime currentDateTime;       

            public Stopwatch()
            {           
                InitializeComponent();
                ClockReset();
            }

            private void btnStartPause_Click(object sender, EventArgs e)
            {
                if (myTimer.Enabled)
                {
                    btnStartPause.BackColor = Color.Green;
                    btnStartPause.Text = "Start";
                    MilliSeconds = Convert.ToInt32(tbMilliSeconds.Text);
                    Seconds = Convert.ToInt32(tbSeconds.Text);
                    Minutes = Convert.ToInt32(tbMinutes.Text);
                    Hours = Convert.ToInt32(tbHours.Text);
                    myTimer.Stop();               
                }
                else
                {
                    currentDateTime = DateTime.Now;
                    btnStartPause.BackColor = Color.Red;
                    btnStartPause.Text = "Pause";
                    myTimer.Start();              
                }
            }

            private void btnReset_Click(object sender, EventArgs e)
            {           
                if (MessageBox.Show("Do you really want to reset?", "Confirm Reset", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    ClockReset();               
                }
            }              

            private void myTimer_Tick(object sender, EventArgs e)
            {
                TimeSpan currentTimeSpan = DateTime.Now.Subtract(currentDateTime);
                tbMilliSeconds.Text = (MilliSeconds + currentTimeSpan.Milliseconds).ToString();
                tbSeconds.Text = (Seconds+ currentTimeSpan.Seconds).ToString();
                tbMinutes.Text = (Minutes + currentTimeSpan.Minutes).ToString();
                tbHours.Text = (Hours + currentTimeSpan.Hours).ToString();
            }

            private void ClockReset()
            {
                btnStartPause.BackColor = Color.Green;
                btnStartPause.Text = "Start";
                myTimer.Stop();
                tbMilliSeconds.Text = resetToZero;
                tbMinutes.Text = resetToZero;
                tbSeconds.Text = resetToZero;
                tbHours.Text = resetToZero;
                MilliSeconds = 0;
                Seconds = 0;
                Minutes = 0;
                Hours = 0;
            }
        }
    }

    And here is the StopWatch.Designer.cs for this application that i created

    namespace Timer
    {
        partial class Stopwatch
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;

            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }

            #region Windows Form 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.btnStartPause = new System.Windows.Forms.Button();
                this.btnReset = new System.Windows.Forms.Button();
                this.myTimer = new System.Windows.Forms.Timer(this.components);
                this.groupBox1 = new System.Windows.Forms.GroupBox();
                this.lblSeconds = new System.Windows.Forms.Label();
                this.lblMinutes = new System.Windows.Forms.Label();
                this.lblHours = new System.Windows.Forms.Label();
                this.lblMilliSeconds = new System.Windows.Forms.Label();
                this.label1 = new System.Windows.Forms.Label();
                this.tbMilliSeconds = new System.Windows.Forms.TextBox();
                this.lblColon2 = new System.Windows.Forms.Label();
                this.lblColon1 = new System.Windows.Forms.Label();
                this.tbHours = new System.Windows.Forms.TextBox();
                this.tbMinutes = new System.Windows.Forms.TextBox();
                this.tbSeconds = new System.Windows.Forms.TextBox();
                this.groupBox1.SuspendLayout();
                this.SuspendLayout();
                //
                // btnStartPause
                //
                this.btnStartPause.BackColor = System.Drawing.Color.Green;
                this.btnStartPause.FlatAppearance.BorderColor = System.Drawing.Color.White;
                this.btnStartPause.FlatAppearance.BorderSize = 3;
                this.btnStartPause.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
                this.btnStartPause.Font = new System.Drawing.Font("Georgia", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.btnStartPause.ForeColor = System.Drawing.SystemColors.ControlText;
                this.btnStartPause.Location = new System.Drawing.Point(360, 119);
                this.btnStartPause.Name = "btnStartPause";
                this.btnStartPause.Size = new System.Drawing.Size(75, 23);
                this.btnStartPause.TabIndex = 0;
                this.btnStartPause.Text = "Start";
                this.btnStartPause.UseVisualStyleBackColor = false;
                this.btnStartPause.Click += new System.EventHandler(this.btnStartPause_Click);
                //
                // btnReset
                //
                this.btnReset.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
                this.btnReset.Font = new System.Drawing.Font("Georgia", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.btnReset.ForeColor = System.Drawing.SystemColors.ControlText;
                this.btnReset.Location = new System.Drawing.Point(453, 119);
                this.btnReset.Name = "btnReset";
                this.btnReset.Size = new System.Drawing.Size(75, 23);
                this.btnReset.TabIndex = 1;
                this.btnReset.Text = "Reset";
                this.btnReset.UseVisualStyleBackColor = false;
                this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
                //
                // myTimer
                //
                this.myTimer.Enabled = true;
                this.myTimer.Interval = 1;
                this.myTimer.Tick += new System.EventHandler(this.myTimer_Tick);
                //
                // groupBox1
                //
                this.groupBox1.BackColor = System.Drawing.SystemColors.MenuBar;
                this.groupBox1.Controls.Add(this.lblSeconds);
                this.groupBox1.Controls.Add(this.lblMinutes);
                this.groupBox1.Controls.Add(this.lblHours);
                this.groupBox1.Controls.Add(this.lblMilliSeconds);
                this.groupBox1.Controls.Add(this.label1);
                this.groupBox1.Controls.Add(this.tbMilliSeconds);
                this.groupBox1.Controls.Add(this.lblColon2);
                this.groupBox1.Controls.Add(this.lblColon1);
                this.groupBox1.Controls.Add(this.tbHours);
                this.groupBox1.Controls.Add(this.tbMinutes);
                this.groupBox1.Controls.Add(this.tbSeconds);
                this.groupBox1.Location = new System.Drawing.Point(12, -2);
                this.groupBox1.Name = "groupBox1";
                this.groupBox1.Size = new System.Drawing.Size(517, 115);
                this.groupBox1.TabIndex = 2;
                this.groupBox1.TabStop = false;
                this.groupBox1.Text = "Timer";
                //
                // lblSeconds
                //
                this.lblSeconds.AutoSize = true;
                this.lblSeconds.Font = new System.Drawing.Font("Times New Roman", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.lblSeconds.Location = new System.Drawing.Point(301, 98);
                this.lblSeconds.Name = "lblSeconds";
                this.lblSeconds.Size = new System.Drawing.Size(43, 14);
                this.lblSeconds.TabIndex = 10;
                this.lblSeconds.Text = "Seconds";
                //
                // lblMinutes
                //
                this.lblMinutes.AutoSize = true;
                this.lblMinutes.Font = new System.Drawing.Font("Times New Roman", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.lblMinutes.Location = new System.Drawing.Point(173, 98);
                this.lblMinutes.Name = "lblMinutes";
                this.lblMinutes.Size = new System.Drawing.Size(44, 14);
                this.lblMinutes.TabIndex = 9;
                this.lblMinutes.Text = "Minutes";
                //
                // lblHours
                //
                this.lblHours.AutoSize = true;
                this.lblHours.Font = new System.Drawing.Font("Times New Roman", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.lblHours.Location = new System.Drawing.Point(49, 98);
                this.lblHours.Name = "lblHours";
                this.lblHours.Size = new System.Drawing.Size(34, 14);
                this.lblHours.TabIndex = 8;
                this.lblHours.Text = "Hours";
                //
                // lblMilliSeconds
                //
                this.lblMilliSeconds.AutoSize = true;
                this.lblMilliSeconds.Font = new System.Drawing.Font("Times New Roman", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.lblMilliSeconds.Location = new System.Drawing.Point(419, 99);
                this.lblMilliSeconds.Name = "lblMilliSeconds";
                this.lblMilliSeconds.Size = new System.Drawing.Size(65, 14);
                this.lblMilliSeconds.TabIndex = 7;
                this.lblMilliSeconds.Text = "MilliSeconds";
                //
                // label1
                //
                this.label1.AutoSize = true;
                this.label1.Cursor = System.Windows.Forms.Cursors.No;
                this.label1.Enabled = false;
                this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 27.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.label1.ForeColor = System.Drawing.SystemColors.ControlText;
                this.label1.Location = new System.Drawing.Point(374, 32);
                this.label1.Name = "label1";
                this.label1.Size = new System.Drawing.Size(28, 42);
                this.label1.TabIndex = 6;
                this.label1.Text = ":";
                //
                // tbMilliSeconds
                //
                this.tbMilliSeconds.Cursor = System.Windows.Forms.Cursors.No;
                this.tbMilliSeconds.Font = new System.Drawing.Font("Courier New", 50.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.tbMilliSeconds.Location = new System.Drawing.Point(402, 19);
                this.tbMilliSeconds.Multiline = true;
                this.tbMilliSeconds.Name = "tbMilliSeconds";
                this.tbMilliSeconds.Size = new System.Drawing.Size(98, 77);
                this.tbMilliSeconds.TabIndex = 5;
                this.tbMilliSeconds.Text = "00";
                this.tbMilliSeconds.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
                //
                // lblColon2
                //
                this.lblColon2.AutoSize = true;
                this.lblColon2.Cursor = System.Windows.Forms.Cursors.No;
                this.lblColon2.Enabled = false;
                this.lblColon2.Font = new System.Drawing.Font("Microsoft Sans Serif", 27.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.lblColon2.ForeColor = System.Drawing.SystemColors.ControlText;
                this.lblColon2.Location = new System.Drawing.Point(119, 32);
                this.lblColon2.Name = "lblColon2";
                this.lblColon2.Size = new System.Drawing.Size(28, 42);
                this.lblColon2.TabIndex = 4;
                this.lblColon2.Text = ":";
                //
                // lblColon1
                //
                this.lblColon1.AutoSize = true;
                this.lblColon1.Cursor = System.Windows.Forms.Cursors.No;
                this.lblColon1.Enabled = false;
                this.lblColon1.Font = new System.Drawing.Font("Microsoft Sans Serif", 27.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.lblColon1.ForeColor = System.Drawing.SystemColors.ControlText;
                this.lblColon1.Location = new System.Drawing.Point(247, 32);
                this.lblColon1.Name = "lblColon1";
                this.lblColon1.Size = new System.Drawing.Size(28, 42);
                this.lblColon1.TabIndex = 3;
                this.lblColon1.Text = ":";
                //
                // tbHours
                //
                this.tbHours.Cursor = System.Windows.Forms.Cursors.No;
                this.tbHours.Font = new System.Drawing.Font("Courier New", 50.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.tbHours.Location = new System.Drawing.Point(21, 19);
                this.tbHours.Multiline = true;
                this.tbHours.Name = "tbHours";
                this.tbHours.Size = new System.Drawing.Size(98, 77);
                this.tbHours.TabIndex = 2;
                this.tbHours.Text = "00";
                this.tbHours.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
                //
                // tbMinutes
                //
                this.tbMinutes.Cursor = System.Windows.Forms.Cursors.No;
                this.tbMinutes.Font = new System.Drawing.Font("Courier New", 50.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.tbMinutes.Location = new System.Drawing.Point(147, 19);
                this.tbMinutes.Multiline = true;
                this.tbMinutes.Name = "tbMinutes";
                this.tbMinutes.Size = new System.Drawing.Size(98, 77);
                this.tbMinutes.TabIndex = 1;
                this.tbMinutes.Text = "00";
                this.tbMinutes.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
                //
                // tbSeconds
                //
                this.tbSeconds.Cursor = System.Windows.Forms.Cursors.No;
                this.tbSeconds.Font = new System.Drawing.Font("Courier New", 50.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                this.tbSeconds.Location = new System.Drawing.Point(275, 19);
                this.tbSeconds.Multiline = true;
                this.tbSeconds.Name = "tbSeconds";
                this.tbSeconds.Size = new System.Drawing.Size(98, 77);
                this.tbSeconds.TabIndex = 0;
                this.tbSeconds.Text = "00";
                this.tbSeconds.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
                //
                // Stopwatch
                //
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.BackColor = System.Drawing.SystemColors.MenuBar;
                this.ClientSize = new System.Drawing.Size(541, 145);
                this.Controls.Add(this.groupBox1);
                this.Controls.Add(this.btnReset);
                this.Controls.Add(this.btnStartPause);
                this.ForeColor = System.Drawing.SystemColors.ControlText;
                this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
                this.Name = "Stopwatch";
                this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
                this.Text = "Stopwatch";
                this.TopMost = true;
                this.groupBox1.ResumeLayout(false);
                this.groupBox1.PerformLayout();
                this.ResumeLayout(false);

            }

            #endregion

            private System.Windows.Forms.Button btnStartPause;
            private System.Windows.Forms.Button btnReset;
            private System.Windows.Forms.Timer myTimer;
            private System.Windows.Forms.GroupBox groupBox1;
            private System.Windows.Forms.TextBox tbSeconds;
            private System.Windows.Forms.Label lblColon1;
            private System.Windows.Forms.TextBox tbHours;
            private System.Windows.Forms.TextBox tbMinutes;
            private System.Windows.Forms.Label lblColon2;
            private System.Windows.Forms.Label label1;
            private System.Windows.Forms.TextBox tbMilliSeconds;
            private System.Windows.Forms.Label lblMilliSeconds;
            private System.Windows.Forms.Label lblSeconds;
            private System.Windows.Forms.Label lblMinutes;
            private System.Windows.Forms.Label lblHours;
        }
    }

    Hope this helps


    • Edited by Saicharan Manga Thursday, December 11, 2008 6:50 AM Added links for application screen capture
    • Proposed as answer by Saicharan Manga Thursday, December 11, 2008 7:52 AM
    Thursday, December 11, 2008 6:27 AM
  • I was googling for something like this and i found this thread and this code snippet really works. Thanks
    Saturday, June 06, 2009 8:56 AM