HeyCHのブログ

慢性疲労のへいちゃんです

【C#】簡単なストップウォッチを作ろう

簡単なストップウォッチ

スタートとストップの機能だけのストップウォッチを作ってみましょう。
まずは以下のように、ツールボックスからラベルとButtionを配置し、Textプロパティをそれぞれ変更します。

f:id:HeyCH:20200327004154p:plain
ストップウォッチ

ボタンをクリックしたときの処理

フォームに配置されたボタンをダブルクリックすると以下のように、ボタンをクリックしたときの処理が自動で記述されます。
今回はここに、押したときからの経過時間を表示するような処理を書きたいわけです。
※DateTime now;というのがありますが、これはフライングです。

f:id:HeyCH:20200327004702p:plain
ボタン押下時の処理

経過時間を表示する処理

基本的な考え方としては、Startボタンを押したときの時刻を記憶しておき、whileで回して、各時刻を測定し、開始時刻を引けば経過時間が測定できるという考え方で行きます。

        DateTime now;
        DateTime startTime;
        private void button1_Click(object sender, EventArgs e)
        {
            startTime = DateTime.Now;
            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += Bw_DoWork;
            bw.RunWorkerAsync();
        }

        private void Bw_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                now = DateTime.Now;
                TimeSpan ts = now - startTime;
                Invoke((MethodInvoker)delegate ()
                {
                    label1.Text = ts.Hours + ":" + ts.Minutes + ":" + ts.Seconds + "." + ts.Milliseconds;
                });
            }
        }

ちゃんと動かんやんけ!

はい、このままではストップしませんからストップする処理も加えないといけません。
以下が、ストップの処理を加えて、微調整したものになります。

        DateTime now;
        DateTime startTime;
        BackgroundWorker bw;
        private void Form1_Load(object sender, EventArgs e)
        {
            bw = new BackgroundWorker();
            bw.DoWork += Bw_DoWork;
            bw.WorkerSupportsCancellation = true;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            if (button1.Text == "Start")
            {
                startTime = DateTime.Now;
                bw.RunWorkerAsync();
                button1.Text = "Stop";
            }
            else
            {
                bw.CancelAsync();
                button1.Text = "Start";
            }
        }
        private void Bw_DoWork(object sender, DoWorkEventArgs e)
        {
            while (!bw.CancellationPending)
            {
                now = DateTime.Now;
                TimeSpan ts = now - startTime;
                try
                {
                    Invoke((MethodInvoker)delegate ()
                    {
                        label1.Text = String.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
                    });
                }
                catch (Exception ex)
                {
                }
            }
        }

はぁ?全然わからん事書いてるんやが?

はい。僕もなんて説明したらいいかわからないんですが、ストップする処理を加えて微調整するとこんな感じになります。

  • BackgroundWorker をクラス変数にした。
  • Form1_Loadを追加してBackgroundWorker の初期化をそこで行うようにした。
  • bw.WorkerSupportsCancellation = true;というのは、BackgroundWorker の動作をキャンセルできるようにするかどうかを設定できるやつです。
  • button1のTextがStartの時ストップウォッチがスタートするようにし、それ以外の場合、ストップするようにした。
  • bw.CancelAsync();というのがBackgroundWorker の動作をキャンセルする命令です。
  • 文字書式(String.Format)を使用し、00:00:00.000の書式で表示するようにした。(これは「C# 文字書式」で検索すると詳しいのが出てきます)