C#

【WPF】ストップウォッチアプリを作成してみた(C#)

C#でストップウォッチ機能を持ったアプリケーションを作成してみました。

アプリケーションの完成イメージは下図の通りです。

本記事では、Stopwatch クラスと DispatcherTimer クラスを使用しています。クラスの使用方法を紹介していますので、この2つのクラスの使い方を知りたい方にもおすすめですので、ぜひ最後まで読んでみてください。

使用するクラス

ストップウォッチアプリで使用するクラスは2つだけです。

  1. Stopwatch クラス   (System.Diagnostics)
  2. DispatcherTimer クラス(System.Windows.Threading)

このクラスがあればアプリをつくることができますが、使い方を知っていないとプログラムを実装することはできません。

それぞれのクラスについて、以下に少しだけ解説をしていますので確認してみましょう。

 

Stopwatch クラス

C#には測定時間を正確に測定する為のクラスが存在します。

使い方はとても簡単で、「Startメソッド」で計測を開始し、「Stopメソッド」で計測を停止します。StartメソッドとStopメソッドは繰り返して使用する事ができ、経過時間は累計されます。

経過時間を初期化(リセット)する場合は「Resetメソッド」を呼び出します。

メソッド説明
Start()計測を開始または再開する
Stop()計測を停止する
Reset()タイマーを停止して、計測時間を0にする
Restart()タイマーを停止して、経過時間を0にリセットしてから計測を開始する

>>Stopwatch クラスについて詳しく見る

 

DispatcherTimer クラス

C#には指定した時間間隔で、イベントを発生させる Timer クラスが存在します。.NET Framework には4種類のTimerクラスが用意されており、本記事では WPF 用の DispatcherTimer を使用します。

  • Windowsタイマー:System.Windows.Forms.Timerクラス
  • スレッドタイマー:System.Threading.Timerクラス
  • サーバベースタイマー:System.Timers.Timerクラス
  • WPFタイマー:System.Windows.Threading.DispatcherTimerクラス

StopWatch クラスと同じく、使い方は簡単です。

タイマーにより呼び出されるメソッドを Tick イベントに登録をして、IntervalプロパティにTimeSpanでイベントを発生させる間隔を指定します。「Startメソッド」でタイマーを開始し、「Stopメソッド」でタイマーを停止します。

タイマーメソッドは UIスレッドから呼び出しがされるので、画面に配置しているコントロールを操作することが可能です。

メソッド説明
Start()タイマーを開始する
Stop()タイマーを停止する

>>DispatcherTimer クラスについて詳しく見る

 

ストップウォッチアプリを作成する

さっそく、ストップウォッチアプリを作成してみましょう。

デザインを作成する

ストップウォッチアプリの画面にはタイマーで計測した時間を表示する用の Label コントロールを配置し、タイマーを開始・停止・初期化する用の Button コントロールを配置します。

計測時間は、分・秒・ミリ秒の3つに分割してそれぞれの Label で表示します。

アプリケーションの画面は『Material Design』を適用させて、いい感じに仕上げました。

>>Material Designを適用する方法はこちら

コードは以下の通りです。プロパティを駆使してコントロールの配置を微調整しているので少し長くなってしまいました。

<Window
    x:Class="TimerApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="Stopwatch App"
    Width="480"
    Height="220"
    ResizeMode="NoResize"
    mc:Ignorable="d">
    <Window.Resources>
        <Style
            x:Key="TemplateLabel"
            BasedOn="{StaticResource MaterialDesignLabel}"
            TargetType="Label">
            <Setter Property="Foreground" Value="DarkGray" />
            <Setter Property="Margin" Value="5,20,0,0" />
            <Setter Property="FontSize" Value="30" />
        </Style>
        <Style
            x:Key="TemplateTimerLabel"
            BasedOn="{StaticResource MaterialDesignLabel}"
            TargetType="Label">
            <Setter Property="Margin" Value="40,0,0,0" />
            <Setter Property="FontSize" Value="50" />
            <Setter Property="Content" Value="00" />
        </Style>
        <Style
            x:Key="TemplateButton"
            BasedOn="{StaticResource MaterialDesignRaisedDarkButton}"
            TargetType="Button">
            <Setter Property="materialDesign:ButtonAssist.CornerRadius" Value="25" />
            <Setter Property="Margin" Value="48,0,0,0" />
            <Setter Property="Height" Value="38" />
            <Setter Property="Width" Value="90" />
        </Style>
    </Window.Resources>

    <Grid>
        <StackPanel
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Orientation="Horizontal">
            <materialDesign:PackIcon
                Width="40"
                Height="40"
                Margin="180,0,0,0"
                Foreground="{StaticResource PrimaryHueDarkBrush}"
                Kind="TimerOutline" />
            <Label
                Content="タイマー"
                FontSize="20"
                FontWeight="Bold"
                Foreground="{StaticResource PrimaryHueDarkBrush}" />
        </StackPanel>

        <Border Margin="0,45,0,65" Background="AliceBlue" />

        <StackPanel
            Margin="0,40,0,0"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Orientation="Horizontal">
            <Label Name="lblMinutes" Style="{StaticResource TemplateTimerLabel}" />
            <Label Content="m" Style="{StaticResource TemplateLabel}" />
            <Label Name="lblSecound" Style="{StaticResource TemplateTimerLabel}" />
            <Label Content="s" Style="{StaticResource TemplateLabel}" />
            <Label Name="lblmilliSecound" Style="{StaticResource TemplateTimerLabel}" />
            <Label Content="ms" Style="{StaticResource TemplateLabel}" />
        </StackPanel>

        <StackPanel
            Margin="0,130,0,0"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Orientation="Horizontal">
            <Button
                Name="btnStart"
                Click="btnStart_Click"
                Content="スタート"
                Style="{StaticResource TemplateButton}" />
            <Button
                Name="btnStop"
                Click="btnStop_Click"
                Content="ストップ"
                Style="{StaticResource TemplateButton}" />
            <Button
                Name="btnReset"
                Click="btnReset_Click"
                Content="リセット"
                Style="{StaticResource TemplateButton}" />
        </StackPanel>
    </Grid>
</Window>

 

コードを記述する

各ボタンのクリックイベントとタイマーイベントの処理を実装します。

クリックイベントではクリックされたボタンの種類によって、コントロールとオブジェクトの制御を行います。

タイマーイベントではストップウォッチの計測時間を TimeSpan で取得します。Minutes で TimeSpanの構造体の「分」の部分、Seconds で TimeSpanの構造体の「秒」の部分、Millisecondsで TimeSpanの構造体の「ミリ秒」の部分をそれぞれ取得してラベルに表示します。

using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;

namespace TimerApp
{
    public partial class MainWindow : Window
    {
        readonly Stopwatch stopwatch = new Stopwatch();
        readonly DispatcherTimer timer = new DispatcherTimer();

        public MainWindow()
        {
            InitializeComponent();

            btnStart.IsEnabled = true;   //スタートボタン有効
            btnReset.IsEnabled = false;  //リセットボタン無効
            btnStop.IsEnabled = false;   //ストップボタン無効

            timer.Interval = new TimeSpan(0,0,0,0,10);    //インターバルを10ミリ秒に設定
            timer.Tick += new EventHandler(TimerMethod);  //インターバル毎に発生するイベントを設定

            Topmost = true;                               //最画面表示(このプロパティはなくても良い)
        }

        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            btnStart.IsEnabled = false;  //スタートボタン無効
            btnReset.IsEnabled = true;   //リセットボタン有効
            btnStop.IsEnabled = true;    //ストップボタン有効

            stopwatch.Start();           //タイマー 測定開始
            timer.Start();               //ストップウォッチ開始
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            btnStart.IsEnabled = true;  //スタートボタン有効
            btnReset.IsEnabled = true;  //リセットボタン有効
            btnStop.IsEnabled = false;  //ストップボタン無効

            timer.Stop();               //タイマー 測定停止
            stopwatch.Stop();           //ストップウォッチ停止
        }

        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            btnStart.IsEnabled = true;   //スタートボタン有効
            btnReset.IsEnabled = false;  //リセットボタン無効
            btnStop.IsEnabled = false;   //ストップボタン無効

            timer.Stop();                //タイマー 測定停止
            stopwatch.Reset();           //ストップウォッチ初期化

            lblMinutes.Content = "00";       //分     初期化
            lblSecound.Content = "00";       //秒     初期化
            lblmilliSecound.Content = "00";  //ミリ秒 初期化
        }

        private void TimerMethod(object sender, EventArgs e) 
        {
            var result = stopwatch.Elapsed;
            lblMinutes.Content = result.Minutes.ToString("00");                   //分     更新
            lblSecound.Content = result.Seconds.ToString("00");                   //秒     更新
            lblmilliSecound.Content = (result.Milliseconds / 10).ToString("00");  //ミリ秒 更新
        }
    }
}

 

デバッグをする

ここまで出来たら、ソリューションのビルドを行ってデバックを実行します。

アプリケーションが起動したら、スタートボタンをクリックして、ストップウォッチを動かしてみましょう。

上図の GIF は解像度を落とすためにフレーム数を少なくしているので、ミリ秒の更新がぎこちないですが、実際に動かしてみるともう少し高速に更新されています。

ストップボタンをクリックしてストップウォッチを停止させた後に、スタートボタンを再度クリックしたとしても、ストップウォッチは続きから計測されています。

ストップウォッチとして使える十分に利用できるアプリケーションが完成しました。

以上、最後まで読んで頂きありがとうございました。

プログラミングを学習したいなら…

プログラミングスキルを身に付けるなら、プログラミングを効率良く学べる
プログラミングスクール」がオススメです。

特にこんな方にオススメ!!
これからエンジニアを目指したい
プログラミングの専門性を高めたい
プログラミングを学んで副業をしたい
エンジニアに転職して年収をアップさせたい

プログラミングを触ったことがない未経験からでも、プログラミングスクールで学習すれば、エンジニアへ就職・転職することも可能です。

あなたの「行動力」と「やる気」で、あなたの人生を大きく変えるチャンスになることでしょう。

プログラミングスクールに興味がある方は是非チェックしてみてください。

> プログラミングを学ぶ <

COMMENT

メールアドレスが公開されることはありません。

CAPTCHA