C#でストップウォッチ機能を持ったアプリケーションを作成してみました。
アプリケーションの完成イメージは下図の通りです。
本記事では、Stopwatch クラスと DispatcherTimer クラスを使用しています。クラスの使用方法を紹介していますので、この2つのクラスの使い方を知りたい方にもおすすめですので、ぜひ最後まで読んでみてください。
使用するクラス
ストップウォッチアプリで使用するクラスは2つだけです。
- Stopwatch クラス (System.Diagnostics)
- DispatcherTimer クラス(System.Windows.Threading)
このクラスがあればアプリをつくることができますが、使い方を知っていないとプログラムを実装することはできません。
それぞれのクラスについて、以下に少しだけ解説をしていますので確認してみましょう。
Stopwatch クラス
C#には測定時間を正確に測定する為のクラスが存在します。
使い方はとても簡単で、「Startメソッド」で計測を開始し、「Stopメソッド」で計測を停止します。StartメソッドとStopメソッドは繰り返して使用する事ができ、経過時間は累計されます。
経過時間を初期化(リセット)する場合は「Resetメソッド」を呼び出します。
メソッド | 説明 |
Start() | 計測を開始または再開する |
Stop() | 計測を停止する |
Reset() | タイマーを停止して、計測時間を0にする |
Restart() | タイマーを停止して、経過時間を0にリセットしてから計測を開始する |
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』を適用させて、いい感じに仕上げました。
コードは以下の通りです。プロパティを駆使してコントロールの配置を微調整しているので少し長くなってしまいました。
<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 は解像度を落とすためにフレーム数を少なくしているので、ミリ秒の更新がぎこちないですが、実際に動かしてみるともう少し高速に更新されています。
ストップボタンをクリックしてストップウォッチを停止させた後に、スタートボタンを再度クリックしたとしても、ストップウォッチは続きから計測されています。
ストップウォッチとして使える十分に利用できるアプリケーションが完成しました。
以上、最後まで読んで頂きありがとうございました。