HeyCHのブログ

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

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

ラップタイムを計れる機能をつけてみよう

ラップタイムは前回LAPボタンを押した時刻(押してない場合、開始時刻)からの経過時間から一時停止時間を引いた値と定義することができると思います。
プログラム的には、LAP押した時のTimeSpanから前回LAPを押した時のTimeSpan(押してない場合、0)から引く。
で、ラップタイムを表示するものとして使用するのに適したものが、DataGridViewというものになります。(Excelみたいな感じでいろいろ表示することができます)
UI的には以下のように、LAPボタン1つとDataGridView1つを追加します。

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

DataGridViewの編集画面を表示しよう

DataGridViewを選択すると、右上に小さい三角形が出現し、これをクリックすることでDataGridViewの編集ができます。

f:id:HeyCH:20200329002838p:plain
DataGridViewの編集画面

DataGridViewに列を追加しよう

列の追加をクリックすると以下のように列の追加ダイアログが表示されます。
ヘッダーテキストに「時刻」、もう1個追加で「ラップタイム」の列を追加してみましょう。

f:id:HeyCH:20200329003650p:plain
追加ダイアログ
f:id:HeyCH:20200329003732p:plain
列追加後

LAPボタンを押した時の処理を書こう

いつものようにLAPボタンをダブルクリックしてLAPボタンを押した時の処理を書きましょう。

        List<TimeSpan> tsl = new List<TimeSpan>();
        private void button3_Click(object sender, EventArgs e)
        {
            if (!bw.IsBusy) return;
            tsl.Add(ts);
            TimeSpan tmp = new TimeSpan(0);
            if (tsl.Count <= 1)
            {
                tmp = tsl[tsl.Count - 1];
            }
            else
            {
                tmp = tsl[tsl.Count - 1]- tsl[tsl.Count - 2];
            }
            DataGridViewTextBoxCell jikoku = new DataGridViewTextBoxCell();
            DataGridViewTextBoxCell laptime = new DataGridViewTextBoxCell();
            jikoku.Value = String.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", now.Hour, now.Minute, now.Second, now.Millisecond);
            laptime.Value = String.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", tmp.Hours, tmp.Minutes, tmp.Seconds, tmp.Milliseconds);
            DataGridViewRow r = new DataGridViewRow();
            r.Cells.Add(jikoku);
            r.Cells.Add(laptime);
            dataGridView1.Rows.Add(r);
        }

微調整

  • 今のままだとDataGridViewが編集できてしまうので、できないようにする。
    f:id:HeyCH:20200329010518p:plain
    ☑を全部はずす
  • フォームを大きくしたとき、DataGridViewも追従するようにする。
    f:id:HeyCH:20200329010852p:plain
    Anchorプロパティ
  • Stopが押された時、DataGridViewもクリアする。
        private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button1.Text = "Start";
            if (isStoped)
            {
                ts = new TimeSpan(0);
                label1.Text = "00:00:00.000";
                tsl.Clear();
                dataGridView1.Rows.Clear();
                isStoped = false;
            }
        }

ここまでのコード

        public Form1()
        {
            InitializeComponent();
        }
        DateTime now;
        DateTime startTime;
        BackgroundWorker bw;
        TimeSpan ts;
        bool isStoped = false;
        private void Form1_Load(object sender, EventArgs e)
        {
            ts = new TimeSpan(0);
            bw = new BackgroundWorker();
            bw.DoWork += Bw_DoWork;
            bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
            bw.WorkerSupportsCancellation = true;
        }

        private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button1.Text = "Start";
            if (isStoped)
            {
                ts = new TimeSpan(0);
                label1.Text = "00:00:00.000";
                dataGridView1.Rows.Clear();
                tsl.Clear();
                isStoped = false;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (button1.Text == "Start")
            {
                startTime = DateTime.Now- ts;
                bw.RunWorkerAsync();
                button1.Text = "Pause";
            }
            else
            {
                bw.CancelAsync();
                button1.Text = "Start";
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            isStoped = true;
            if (bw.IsBusy)
            {
                bw.CancelAsync();
            }
            else
            {
                ts = new TimeSpan(0);
                label1.Text = "00:00:00.000";
                isStoped = false;
            }
        }
        private void Bw_DoWork(object sender, DoWorkEventArgs e)
        {
            while (!bw.CancellationPending)
            {
                now = DateTime.Now;
                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)
                {
                }
            }
        }
        List<TimeSpan> tsl = new List<TimeSpan>();
        private void button3_Click(object sender, EventArgs e)
        {
            if (!bw.IsBusy) return;
            tsl.Add(ts);
            TimeSpan tmp = new TimeSpan(0);
            if (tsl.Count <= 1)
            {
                tmp = tsl[tsl.Count - 1];
            }
            else
            {
                tmp = tsl[tsl.Count - 1]- tsl[tsl.Count - 2];
            }
            DataGridViewTextBoxCell jikoku = new DataGridViewTextBoxCell();
            DataGridViewTextBoxCell laptime = new DataGridViewTextBoxCell();
            jikoku.Value = String.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", now.Hour, now.Minute, now.Second, now.Millisecond);
            laptime.Value = String.Format("{0:D2}:{1:D2}:{2:D2}.{3:D3}", tmp.Hours, tmp.Minutes, tmp.Seconds, tmp.Milliseconds);
            DataGridViewRow r = new DataGridViewRow();
            r.Cells.Add(jikoku);
            r.Cells.Add(laptime);
            dataGridView1.Rows.Add(r);
        }