Silverlight をインストールするには、ここをクリックします*
Japan変更|サイトマップ
MSDN
|MSDN ライブラリ|デベロッパー センター|ダウンロード情報|開発ツール製品|コミュニティ|ご意見・ご要望|サイトマップ
MSDN Home > Student > プログラミング チャレンジ スクエア > 第 4 章 ラーメンタイマーを作ってみよう C# 編

第 4 章 ラーメンタイマーを作ってみよう


サンプルプログラムのダウンロード (Chap4_CSharp.msi, 583 KB)

※ また、サンプルプログラムは、あらかじめ Visual C# 2005 Express Edition と同じパソコンにインストールしておいてください。
   設定方法は こちら


この章でやること
・ インスタントラーメンを作るためのタイマープログラムを完成させます。
・ Timer コンポーネントの使い方と、変数を使ったカウンタ表示について体験します。

第 4 章 ラーメンタイマーを作ってみよう
Timer コンポーネントの追加
イベントの追加
タイマーの時間を指定しよう
経過時間をリアルタイムに表示する





前の章で変数について学んだ翔太君と美咲さん。でも、まだ具体的にどういう場面で使ったらいいのかピンときてないようです。


翔太:変数を使うと便利、というのはわかったけど、まだ具体的なイメージがわいてこないなぁ。
美咲:私も。変数って言うくらいだから、数字が変化する計算式に使えそう、っていうのはわかるんだけど、具体例っていわれると思いつかないわ。
健一:じゃ、身近で数字が変化するものを考えてごらん。
翔太:身近で数字が変化するもの・・・?
健一:部屋の中に何かないかい?
美咲:部屋の中・・・。パソコン、テレビ、ベッド、本棚、時計・・・、時計?


美咲さんが指差したのは、部屋の隅にある置時計でした。


翔太:時計・・・。時間は確かにだんだん数字が変化していくね。これも変数と関係があるの?
健一:うん。ちょうど入門マニュアルの新しい章で Timer コンポーネントというのが出てくるから、これを見ながら勉強していくことにしよう。
翔太
&
美咲
:Timer コンポーネント?
健一:まずはサンプルを開いてみよう。


プログラムメニューから Visual C# 2005 Express Edition を立ち上げて、サンプルファイルフォルダの中の Part4_C#\Part4_Base フォルダにある Part4.sln を開きます。そして、[ソリューション エクスプローラ] から、[Form1.cs] を開きます。





翔太:本当にデジタル時計みたいだ。
美咲:何か書いてあるわ。ラーメンタイマー・・・?
健一:そう、これはインスタントラーメンを作る時のタイマーの役目を果たすプログラムなんだ。簡単に画面の説明をしておこう。一番上のデジタル時計みたいになってる表示部分は、現在の経過時間を表示するところだ。中央の灰色の部分は、画像を表示する場所。その下に、分と秒と書いてある欄があるだろう? そこはタイマーで計測する時間を指定して、[START] ボタンでスタートする仕組みになっているんだ。例によって、まずデバッグ ボタンをクリックして、動作を確認してみよう。


プログラムが立ち上がるので、まず [START] ボタンをクリックしてみます。





翔太:何も起きないね。
健一:これはまだ画面に必要なボタンなどを配置しただけだからね。この [START] ボタンを押すとタイマーのカウントダウンが始まるようにするのが、この章の目標なんだ。
美咲:ボタンを押す、ということはイベントがまた関係してくるようね。他にもまた新しいことが出てくるのかしら。
健一:それは見てのお楽しみ。それでは、デバッグ中のプログラムを終了させて、入門マニュアルを見ながら先に進めることにしよう。




<Timer コンポーネントの追加>

健一:まず、最初に Timer コンポーネントを追加しよう。 [Form1.cs] のデザイナ 画面で、[ツールボックス] を開いて、[すべての Windows フォーム] の中の [Timer] をクリックするんだ。





美咲:どこに貼り付ければいいの?
健一:画面フォームの中ならどこでもいい。カーソルがになっている状態でフォームのどこかをクリックすると、画面の一番下に timer1 と表示されたはずだ。





もし、うまく行かない場合は、[すべての Windows フォーム] の中の [Timer] をクリックしたままマウスをドラッグして、画面フォームの上でドロップしてください。デザイナ 画面の余白の部分にドロップしても設定されないので、失敗した場合はもう一度やり直せば大丈夫です。画面下に timer1 と表示されるまで試してください。


翔太:上の画面を見ると、Timer コンポーネントを置いたところにそれらしいものが表示されてないけど、なぜ下のところに出てくるの?
健一:いいところに気がついたね。それじゃ、ボタンやテキスト ボックスと比較して考えてみようか。
まず、ボタンとテキスト ボックスは何のためにあるか。
美咲:ボタンは、クリックして、何かイベントを起こすため・・・?
健一:テキスト ボックスは?
翔太:文字や数値を入力する場所でしょ?
健一:そう、クリックしたり、文字を入力したりするためには、ボタンやテキスト ボックスがユーザーから見えてないといけない。だって、画面にないボタンはクリックできないからね。
翔太:たしかに、テキスト ボックスがどこにあるか分からなかったら、何を入力したらよいか分からなくなるかもしれないね。
健一:そう、だから、画面上のどこにボタンやテキスト ボックスを配置するか、プログラミングするときに指定する必要があるんだ。
美咲:じゃあ、Timer コンポーネントは画面になくてもいいの?
健一:そのとおり。なぜなら、Timer コンポーネントは、ユーザーの操作とは直接関係がないからなんだ。Timer コンポーネントは、指定された時間が経過すると、決められたイベントを発生させる機能を持っている。だから、時間の設定と、イベントの中身さえプログラミングしてあげれば、画面のデザインとはあまり関係がないんだよ。
翔太:イベントを発生させる、ってことは、例えば第 2 章のサンプルではボタンをクリックするとイベントによって画像のサイズが変わったけど、あれと同じように、指定した時間に画像のサイズを変えたりできるの?
健一:なかなか面白いことを考えるね。たしかに、プログラミング次第でそういうことも可能になるよ。
翔太:へぇー! それはなんだかすごいなぁ。
美咲:そうか、だからラーメンタイマーなのね。指定した時間が経てば、終了したことをイベントによってお知らせしてくれるんだわ。
健一:簡単に言うとそういうことかな。でも、実際にはちょっと手間がかかるんだ。順を追って説明していくから、入門マニュアルと画面を良く見ながら進めてほしい。
翔太
&
美咲
:はい!




<イベントの追加>

健一:それじゃ、最初に基本になる Timer コンポーネントのイベントを設定しよう。timer1 と表示された Timer コンポーネントのプロパティ ウィンドウを確認してごらん。





美咲:次は、[イベント] ボタンをクリックするのね。





健一:そう。そして、一覧にある [Tick] の右側のコンボ ボックスに「timer1_Tick」と入力して [Enter] キーを押す。
翔太:イベントの一覧っていっても一つしかないよ?
健一:そういう場合もあるってこと。特に Timer コンポーネントは特別な存在だからね。これだけでも十分なんだよ。さて、次のリスト 4-1-1 のようなコードが表示されたかな。もし違っていたら、「Form1.cs [デザイン]」タブをクリックし、デザイナ 画面に戻ってプロパティの確認からやり直してみよう。


リスト 4-1-1 は、後で読み返すときに分かりやすいようにコメント文 (' 指定したミリ秒毎に実行される処理) を追加した形で紹介しています。実際に上記の手順でイベントを新しく作った場合、コメントは追加されていませんので、必要に応じて自分で書き加えてください。以後のリストについても同様です。


リスト 4-1-1

        // 指定したミリ秒毎に実行される処理
        private void timer1_Tick(object sender, EventArgs e)
        {

        }


美咲:ここにどんなコードを書き込むの?
健一:それはまた後で。とりあえず、今はここまででいい。今の作業はイベントの入れ物を用意したようなものなんだ。具体的に何をやるかはこれから準備しなければいけない。では、Timer コンポーネントから少し離れて、[START] ボタンを見てみようか。
翔太:[START] ボタン?
健一:そう、[START] ボタンによってタイマーが動作するんだから、そちらも設定しないとね。デザイナ 画面に戻って、ボタンのプロパティ ウィンドウを開いてごらん。





プロパティ ウィンドウを開いたら、次にイベントボタン でイベント一覧を開いて、[Click] の右にあるコンボ ボックスに「btnStart_Click」と入力し、[Enter] キーを押します。すると、先ほどのリスト 4-1-1 のコードの後に、次のリスト 4-1-2 のコードが追加されるはずです。


リスト 4-1-2

        // [START] ボタンが押されたときの処理
        private void btnStart_Click(object sender, EventArgs e)
        {

        }


美咲:イベントの設定だけして、まだ具体的な中身に入らないのかしら。
健一:今度は違うよ。具体的なコードの中身を書いていくんだ。まず、タイマーのカウントダウンが始まったら、カウントダウン中であることを示す画像を表示させよう。今作ったリスト 4-1-2 の中の「private void btnStart_Click〜」の次の行にある「{」と「}」の間に、リスト 4-1-3 のコードを入力してごらん。


リスト 4-1-3

            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.調理中;


翔太:これは?
健一:[START] ボタンをクリックすると、タイマーのカウントダウンをスタートさせることになるのは分かるかい? それと同時に、画面中央にある PictureBox1 の画像をここで指定した画像に切り替えているんだ。この画像は調理中、というメッセージが表示される画像で、ラーメンタイマーだからこのメッセージにしてある。さあ、今度は、タイマーを途中で止められないようにしておこう。
美咲:なぜ途中で止めちゃいけないの?
健一:ただのストップウォッチならもちろんかまわないが、ラーメンタイマーという性質上、途中で時間のカウントを止めてしまうと正しい調理時間が計測できなくなってしまうからね。リスト 4-1-3 のコードに続けて、リスト 4-1-4 のコードを追加してみよう。


リスト 4-1-4

            // [START] ボタンを無効化
            btnStart.Enabled = false;


健一:今度は、実際にタイマーをスタートさせるコードを書くことにしよう。次のリスト 4-1-5 を今までのコードに続けて書くんだ。


リスト 4-1-5

            // タイマーを開始
            timer1.Start();


健一:ここでやっているのは、Timer コンポーネントに対して、カウントダウンを始めなさい、という命令を与えているんだ。Start というのは開始命令のことで、3 章でも少し出てきたメソッドと呼ばれるものなんだ。
美咲:メソッド?
健一:うん、第 3 章でも説明したように、プログラムのコードの中で、何かに命令して動作させたいときに使うもの、と覚えておいてくれればいい。今回の timer1 のように、命令を出すものとセットになって出てくるので、似たようなものがこれから先も出てきたら、メソッドを使って何かやっているんだな、と思い出してほしい。ところで、もちろん開始するメソッドがあれば、終了するメソッドもある。そちらも後で設定するけど、その前に終わったときの画像を設定しておこう。
翔太:終わったときの画像って?
健一:だって、ずっと調理中のままだったら変だろう? 今度は、timer1 の Tick イベントのところで作ったコードの方に書き込むんだ。


コード エディタで、リスト 4-1-1 に出てきた「private void timer1_Tick〜」の次の行にある「{」と「}」の間の行を確認してください。その 2 つの行の間にリスト 4-1-6 のコードを追加します。


リスト 4-1-6

            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.完成;


美咲:今度は完成しましたよ、っていうメッセージを画像で表示するわけね。
健一:そのとおり。


健一:それじゃタイマーの機能を終わらせるコードを書いていこう。さっきのリスト 4-1-6に続けて、次のリスト 4-1-7 のコードを書きこむ。


リスト 4-1-7

            // タイマーを停止
            timer1.Stop();


翔太:今度は Stop なんだ。あれ? さっきは、ボタンのイベントの方に Start のメソッドを書き込んだのに、今度は違うんだね。
美咲:うーん・・・。それは、ボタンによって Timer1 が開始するけど、終了はボタンを使わないってことなんじゃないかしら。
健一:二人ともいいところに気がついたね。美咲ちゃんの言うとおり、メソッドを使う場所が違うのは、プログラムの流れがそうなっているからなんだ。
このように、どういう場面でどういうことをしたいか、ということを考えておくことは、プログラミングにおいてとても重要なことなんだよ。そして、その上で、なるべく順序良くプログラムを書いていけば、トラブルが起きたときに原因を特定して解決する場合などにとても役に立つんだ。
翔太:なるほど・・・。計画性が重要なんだね。
健一:そういうこと。さて、終了したついでに、ボタンの機能が有効になるようにしておこう。


リスト 4-1-7 に続けて、リスト 4-1-8 のコードを書きこんでください。


リスト 4-1-8

            // [START] ボタンを有効化
            btnStart.Enabled = true;


健一:これで、タイマー作動中は無効になっていたボタンの機能が、タイマー終了後には元に戻るはずだ。さあ、ここまでできたら、デバッグ ボタンを押して実際の動きを確認してみよう。


プログラムが立ち上がったら、[START] ボタンをクリックし、画像が一瞬で「調理中」から「完成」に切り替わることを確認します。








もしうまく行かないようなら、一旦終了して、コードを確認してください。うまくできていれば、次のリスト 4-1-9 のようなコードになっているはずです。


リスト 4-1-9

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Part4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // 指定したミリ秒毎に実行される処理
        private void timer1_Tick(object sender, EventArgs e)
        {

            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.完成;
            // タイマーを停止
            timer1.Stop();
            // [START] ボタンを有効化
            btnStart.Enabled = true;

        }

        // [START] ボタンが押されたときの処理
        private void btnStart_Click(object sender, EventArgs e)
        {

            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.調理中;
            // [START] ボタンを無効化
            btnStart.Enabled = false;
            // タイマーを開始
            timer1.Start();

        }
    }
}


美咲:なんだか、あっという間に時間が経ってるみたい。
健一:それは、まだ始まりと終わりの作業だけを決めて、何分表示させるかといった細かい部分を設定してないからだよ。それは次のステップで行うことにしよう。




<タイマーの時間を指定しよう>

健一:ラーメンタイマーを作る準備は整った。このあと、やらなければいけないことは何だったかな?
翔太:えーっと・・・。時間の設定がまだだったよね。Timer コンポーネントに Tick というイベントを設定したけど、具体的に何分計測するかはまだ決めてなかったはず。
美咲:画面デザインを見ると、時間を指定するテキスト ボックスがあるから、そこから時間の設定を読み取る仕組みも必要じゃないかしら。
健一:そう、この場合、ユーザーが指定した時間に合わせて、Timer コンポーネントの設定を変更すればいいんだ。それじゃ、timer1 のプロパティ ウィンドウを開いて、今度は [プロパティ] ボタンをクリックして、プロパティの一覧から [Interval] という項目を探してごらん。





翔太:もう 100 という数値が設定されてるみたいだ。これが基本設定なの?
健一:そうだよ。ちなみに、これは 100 ミリ秒、という設定になっているんだ。
美咲:ミリ秒?
健一:うん。1 ミリ秒は 1 秒の 1000 分の 1。つまり 100 ミリ秒というのは、0.1 秒ということになる。
翔太:だから、さっきデバッグ ボタンをクリックしたときに、すぐに終了したのか。
美咲:でも、画面のデザインを見る限り、ミリ秒で時間を設定するようになってなかったわ。分と秒の指定だから、そのままでは Interval の値にならないんじゃない?
健一:そこは、プログラミングで解決するのさ。それじゃ、次のリスト 4-2-1 のコードを追加してごらん。追加する場所は、「private void btnStart_Click〜」の次の行にある「{」と「}」の間だ。ボタンをクリックするとすぐに実行したいので、「{」のすぐ次の行に入れておこう。


リスト 4-2-1

            // 指定されたタイマー停止時間を秒単位にしてプロパティに設定
            timer1.Interval = (int)(nudMinuteNum.Value * 60 + nudSecondNum.Value) * 1000;


美咲:nudMinuteNum は分を入力する数値アップダウン コントロールの名前で、nudSecondNum は秒を設定する数値アップダウン コントロールの名前ね。Value ってなんだったかしら。
健一:Value は第 3 章でも出てきたけど、指定された値のことを指すんだ。ここでやっているのは、まず、nudMinuteNum で指定された値に 60 を掛けることで、分を秒に置き換えている。それに、nudSecondNum で指定された秒数の値を足して、指定時間全体を秒数に置き換えているんだ。
翔太:それに 1000 を掛けてるってことは、さらにここでミリ秒に置き換えてるんだね。
健一:そのとおり。そして、そのミリ秒に直した指定時間の情報を、Interval の値に代入している、というわけだ。
美咲:こうやって、分や秒の指定をミリ秒に変換してるのね。
健一:仕組みが分かったら、デバッグ ボタンをクリックして、ここまでの動きを実際に確認してみよう。設定時間はとりあえず 5 秒くらいで試してみようか。


デバッグ ボタンをクリックして、プログラムを立ち上げます。時間の指定のところで、5 秒と設定して [START] ボタンをクリックしてください。





翔太:さっきよりも調理中と完成の間の時間が長かったから、どうやらうまくいったみたいだね。
健一:どうやら、っていうのはどういう意味だい?
翔太:え? えーと、なんとなく自分で 5 つ数えたのと同じくらいだったから・・・
美咲:調理中という画像が表示されているのが大体 5 秒くらいだと私も思ったけど。
健一:そうだね。でも大体これくらい、って言う程度にしかわからないタイマーだと、本当に何処まで正確なのかが分からない。プログラムに間違いはないとはいっても、見た目でそれが分かるに越したことはないだろう?
翔太:あ、そういえば、一番上のデジタル時計のところはまだ動いてなかったね。
健一:デジタル時計に時間が表示されるとかなり分かりやすくなるよね。今度はデジタル時計の表示をうまく使う方法を考えてみよう。


次に進む前に、デバッグ実行しているプログラムを終了します。もし、ここまでのプログラムがうまく動いていない場合は、コード エディタでコードを確認してみてください。うまくできていれば、次のリスト 4-2-2 のようになっているはずです。


リスト 4-2-2

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Part4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // 指定したミリ秒毎に実行される処理
        private void timer1_Tick(object sender, EventArgs e)
        {
            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.完成;
            // タイマーを停止
            timer1.Stop();
            // [START] ボタンを有効化
            btnStart.Enabled = true;
        }


        // [START] ボタンが押されたときの処理
        private void btnStart_Click(object sender, EventArgs e)
        {

            // 指定されたタイマー停止時間を秒単位にしてプロパティに設定
            timer1.Interval = (int)(nudMinuteNum.Value * 60 + nudSecondNum.Value) * 1000;
            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.調理中;
            // [START] ボタンを無効化
            btnStart.Enabled = false;
            // タイマーを開始
            timer1.Start();
        }
    }
}




<経過時間をリアルタイムに表示する>

健一:デジタル時計のように時間の経過を表示するのは、実は二人にプログラミングしてもらうのは少し難しすぎるんだ。そこで、この入門マニュアルでは、特別なコントロールを用意しているから、それを利用することにしよう。
美咲:DigitalTimer っていう名前のコントロールね。
健一:そう、画面でデジタル時計のように見えているところがコントロールになっているんだよ。
翔太:それじゃ、そのプロパティ ウィンドウを開いて・・・
健一:おっと、今回はそうじゃないんだ。まず Timer コンポーネントのプロパティを変えておかないといけない。
翔太:Timer コンポーネント?
健一:デザイナ 画面で、timer1 のプロパティ ウィンドウを開いて、プロパティ一覧の [Interval] の値を、100 ではなくて 1000 にしておくんだ。





美咲:ここで 1000 にしておいても、さっき追加したコードがあるから意味がないんじゃない?
健一:もちろん、リスト 4-2-1 で追加したコードは削除するんだ。すると、btnStart_Click イベントのコードは、次のリスト 4-3-1 のようになるはずだけど、プロパティの設定を行うこととあわせて、何が行われるようになると思う?


リスト 4-3-1

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Part4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        // 指定したミリ秒毎に実行される処理
        private void timer1_Tick(object sender, EventArgs e)
        {

            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.完成;
            // タイマーを停止
            timer1.Stop();
            // [START] ボタンを有効化
            btnStart.Enabled = true;

        }

        // [START] ボタンが押されたときの処理
        private void btnStart_Click(object sender, EventArgs e)
        {

            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.調理中;
            // [START] ボタンを無効化
            btnStart.Enabled = false;
            // タイマーを開始
            timer1.Start();

        }
    }
}


翔太:リスト 4-2-1 のコードは、時間の指定を取り込むコードだったから・・・、それがなくなってリスト 4-3-1 の状態になったら、プロパティ ウィンドウで指定した 1000 ミリ秒の時間設定だけがずっと有効になるんじゃないかな?
健一:正解! そうなると、1000 ミリ秒、つまり 1 秒間でプログラムが終了してしまうことになってしまうけど、この設定は見方を変えれば、1 秒間同じ画像を表示するプログラム、ということでもあるんだ。
翔太:それが何か重要なの?
健一:1 秒間で終わってしまうプログラムでも、例えばそれを 60 回繰り返せばどうなる?
美咲:あ、そうか! 1 分間同じ画像が表示され続けることになるわ。
健一:そう、そして 1 秒間画像を表示するごとにデジタル時計の数字も変わるようにすれば・・・
翔太:時間をカウントすることになるんだ!
健一:どうやらこれからやろうとすることがわかってもらえたみたいだね。それでは、具体的な作業を説明しよう。


健一:今回やりたいことは 3 つあるんだ。まず、1) [START] ボタンをクリックしたときに、指定された時間を秒数に置き換えて記録する。これはもう既にやったよね。次に、2) Tick イベントが発生する度に何度発生したか、つまり何秒経過したかを数える。そして、3) 指定した秒数まで Tick イベントが発生したら、画像を切り替えてタイマーを停止する。以上の 3 つについて、順番に見ていこう。
美咲:実際には 1) はもう終わってるから、2) からになるのね。
健一:それじゃ、コード エディタを開いて、まず、最初に指定した時間を記録するための変数 WaitSecond と、Tick イベントが発生した回数(秒数)を数えるための変数 SecCount をそれぞれ作ろう。


コード エディタを開いて、一番上にある「private void timer1_Tick〜」のすぐ上の行に、次のリスト 4-3-2 を追加します。




リスト 4-3-2

        private int SecCount;       // 秒数をカウントする変数
        private int WaitSecond;     // タイマー停止時間を秒単位で記憶する変数


翔太:なぜ、この位置に書き込むの? それに、第 3 章で変数を作ったときには、double になってたところが int になってるね。
美咲:それに第 3 章では、private なんて付かなかったと思う。
健一:二人ともなかなか注意力が高まってきたみたいだね。第 3 章で、double というのが変数の種類だと説明したのは覚えてるかな? int というのも同じように変数の種類を表わしているんだ。ちなみに、double 型というのは小数点付きの数値を扱うための変数で、int 型というのは整数を扱うための変数ということになる。時間の管理で小数点はいらないだろう? だからここでは int を使うんだよ。private については、この場合はここで設定するための約束事だと考えてくれて良い。ただ、こういう書き方もある、ということを覚えておいてくれればそれで十分だ。
美咲:じゃあ、なぜこの場所に書くの?
健一:この場所は、このプログラムの中で一番最初の位置になるんだ。この 2 つの変数は、プログラムの中で最も重要で、しかもいろいろなイベントで使うことになるから、一番最初に設定しておきたいんだよ。とりあえず、どのイベントでも使えるようにするためにこの位置に書いてある、と、ここでは考えておいてもらえるかな。
翔太:ということは、変数の設定、ってコードを書く場所によって役割が変わってくる可能性があるってこと?
健一:そういうことになるね。簡単に説明できるようなら、もう少し説明しておきたいところだけど、この章のテーマとは関係なくなってしまうので、ここではこれ以上の説明は省略させてほしい。ただ、変数を作ることを、変数を宣言する、というんだ。これは覚えておくといいよ。
翔太:宣言、ってなんかかっこいいな。
美咲:これからこの変数を使います、ってことを、プログラムの中で意思表示をしてるってことなのね。
健一:そういうこと。それじゃ、リスト 4-3-2 で宣言した 2 つの変数のうち、WaitSecond 変数について、具体的にコードを追加していこうか。リスト 4-3-3 を、さっき削除したリスト 4-2-1 のコードのところに書き加えてごらん。


コード エディタで、「private void btnStart_Click〜」の次の行にある「{」と「}」の間に、リスト 4-3-3 を追加します。


リスト 4-3-3

            // 指定されたタイマー停止時間を秒単位で記憶
            WaitSecond = (int)(nudMinuteNum.Value * 60 + nudSecondNum.Value);
            // 指定されたタイマー停止時間が 0 秒のときは開始処理をキャンセル
            if (WaitSecond == 0)
            {
                return;
            }


この結果、btnStart_Click イベントに関するコードは次のリスト 4-3-4 のようになります。


リスト 4-3-4

        // [START] ボタンが押されたときの処理
        private void btnStart_Click(object sender, EventArgs e)
        {
            // 指定されたタイマー停止時間を秒単位で記憶
            WaitSecond = (int)(nudMinuteNum.Value * 60 + nudSecondNum.Value);
            // 指定されたタイマー停止時間が 0 秒のときは開始処理をキャンセル
            if (WaitSecond == 0)
            {
                return;
            }
            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.調理中;
            // [START] ボタンを無効化
            btnStart.Enabled = false;
            // タイマーを開始
            timer1.Start();
        }


美咲:リスト 4-3-3 の最初の行は、リスト 4-2-1 でやってるのとほとんど同じね。1000 を掛けてないから、ミリ秒じゃなくて秒のまま変数に代入してるみたいだわ。
翔太:次の行ではなにをやってるの?
健一:次の行からリスト 4-3-3 の最後の行までは、WaitSecond 変数の値が 0、つまりタイマーが止まるまでの時間が 0 秒だったら、これ以降のコードを無視して [START] ボタンを押す前の状態に戻る、という作業を行っている。「return」というのが、[START] ボタンを押す前の状態に戻るという命令なんだよ。
美咲:じゃ、0 秒じゃなかったら?
健一:その場合は一番下の「}」の次の行から下の行を実行するんだ。つまり、リスト 4-3-4 でいうと、表示画像を変更する命令から下が順番に実行されることになる。そういえば、この「if」から始まる命令は初めて出てきたね。これは難しい言い方をすると、条件分岐、という仕組みなんだ。
翔太:条件分岐?
健一:うん。条件を指定しておいて、その条件に当てはまるかどうかで、その後の作業を振り分けるんだ。今回の場合、WaitSecond 変数と 0 という値が等しい、あるいは一致する、という条件が式という形で指定されているんだけど、コードを見れば分かるように、「=」を二つ続けて「==」と書いてあるだろう? 代入のときは「=」が 1 つで済んだけど、条件式では 2 つ使う必要があるので、注意しないといけないところなんだよ。
翔太:記号の使い方が目的や状況によって違ってくるんだね。
健一:そうなんだ。これ以外にも、プログラミングで使う記号の使い方の中には、普通の計算式と違う場合があるけど、それはまた具体的に出てきたら説明することにしよう。また、条件分岐そのものについて、今回はごく単純なコードで、条件も 1 つしかないけど、うまく使いこなすといろいろなことができるようになるんだ。この機会に名前だけでも覚えておくといいよ。
続けて、[START] ボタンを押したときの作業を追加していくよ。さっきのリスト 4-3-3 のコードのすぐ後ろに次のリスト 4-3-5 のコードを書き加えるんだ。


リスト 4-3-5

            // 秒数のカウントと表示を 0 に初期化
            SecCount = 0;
            DigitalTimer.Second = 0;


この結果、btnStart_Click イベントに関するコードは次のリスト 4-3-6 のようになります。


リスト 4-3-6

        // [START] ボタンが押されたときの処理
        private void btnStart_Click(object sender, EventArgs e)
        {
            // 指定されたタイマー停止時間を秒単位で記憶
            WaitSecond = (int)(nudMinuteNum.Value * 60 + nudSecondNum.Value);
            // 指定されたタイマー停止時間が 0 秒のときは開始処理をキャンセル
            if (WaitSecond == 0)
            {
                return;
            }
            // 秒数のカウントと表示を 0 に初期化
            SecCount = 0;
            DigitalTimer.Second = 0;
            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.調理中;
            // [START] ボタンを無効化
            btnStart.Enabled = false;
            // タイマーを開始
            timer1.Start();
        }


美咲:これは分かるわ。まず、SecCount 変数に 0 を代入してるのね。それから、次の行では、DigitalTimer コントロールの Second というプロパティに 0 を代入しているみたい。
健一:そう。それじゃ、これがプログラム上で何を意味しているかは分かるかい?
美咲:えーっと・・・、これが書かれているのが、[START] ボタンをクリックしたときに発生するイベントなのよね。そこで、Timer コントロールの Tick イベントが発生した回数(秒数)を記録する SecCount 変数を 0 にしてるということは・・・。
翔太:もしかして・・・
健一:なんだい、翔太君。
翔太:[START] ボタンを押した時点で、確実に 0 秒から始まるようにしてるってこと?
健一:正解! そう、ここでやっていることは、実は初期化という作業なんだ。DigitalTimer コントロールについても同じように 0 を代入して初期化してるんだよ。
美咲:初期化?
健一:これからこの 2 つの変数には時間の経過とともに数値が代入されていくことになるだろう? そのため、最初の段階で、値を 0 にしてしまうことで、余計な値が紛れ込んだりしないようにしてるんだ。
翔太:それって、初めて買ったフロッピーディスクをフォーマットするようなものかな。
健一:いい例えだね。そういうイメージで捉えておいて間違いじゃないよ。毎回フォーマット=初期化するのは面倒かもしれないけど、コードに書いておけばたったこれだけで済むし、より安全にプログラムを実行するには必要なことなんだ。ちなみに、変数を宣言したときには、このように何か値を代入して初期化する必要がある。これも大事な約束事の 1 つなんだよ。
美咲:そういえば、第 3 章でも変数を宣言してすぐに値を代入してたわね。
翔太:あれはそういう意味もあったんだね。簡単にやってきたことでも、実はいろいろ意味があったりするんだなぁ。
健一:そうなんだ。これまでの章はもちろん、これからの残りの章も、それぞれ紹介したいポイントに絞って説明しているけど、それ以外のところでもちゃんとプログラミングに必要なルールは守って書いてある。最後の章まで行ったら、今度はもう一度プログラムのコードを見ながら、1 行ずつ意味を調べてみると新しい発見があるかもしれないよ。
翔太:それはそれで面白そうだけど、まだまだ先の話になりそうだな。
美咲:そうね、まずはこの章をちゃんと終わらせないと。
健一:よーし、それじゃ次に進もうか。


コード エディタで、「private void timer1_Tick〜」の次の行にある「{」と「}」の間にあるコードを一旦削除します。まず、この部分のコードは、現時点で次のリスト 4-3-7 のようになっているはずです。


リスト 4-3-7

        // 指定したミリ秒毎に実行される処理
        private void timer1_Tick(object sender, EventArgs e)
        {

            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.完成;
            // タイマーを停止
            timer1.Stop();
            // [START] ボタンを有効化
            btnStart.Enabled = true;

        }


この中の、次の部分を削除します。


リスト 4-3-8

            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.完成;
            // タイマーを停止
            timer1.Stop();
            // [START] ボタンを有効化
            btnStart.Enabled = true;


そして、代わりに次のコードを書き込みます。


リスト 4-3-9

            // 秒数をカウントし、表示するため DigitalTimer に設定する
            SecCount = SecCount + 1;
            DigitalTimer.Second = SecCount;


美咲:コードを一旦削除するのはどうして?
健一:すぐにまた、少し形を変えて書き込むから心配しなくていいよ。中途半端に残すよりも、この新しいコードをちゃんと書くために一度整理しておきたかったんだ。
翔太:よし、さっきは美咲ちゃんが解説したから、今度は僕が説明する番だな。えーっと、これは最初に SecCount 変数に代入を・・・。あれ? 代入する値のところにまた SecCount って出てきてるよ? 自分に自分を代入してどうするんだ?
健一:ちょっといきなりは難しかったかもしれないな。よくこの行を読んでごらん。= の右側に書いてあるのは、SecCount ではなくて、SecCount+1 という式だろう?
翔太:本当だ。でも自分に 1 を加えるってどういうこと?
健一:[START] ボタンを押したらどうなるか、もう一度コードを見ながら考えてみるといいよ。
美咲:まず、WaitSecond 変数に指定した時間が秒数で代入されるわ。それで、条件分岐のところは、条件をクリアしてるから飛ばしたと仮定すると、次に来るのは SecCount 変数を 0 にしてるところね。それから、DigitalTimer コントロールにも 0 を与えて・・・
翔太:・・・画像を調理中という画像に指定して、ボタンの機能を無効にしてから、Timer コンポーネントを Start メソッドで開始してるんだよね。
健一:ということは、一番最初に Timer コンポーネントが開始したときに、SecCount 変数の値はどうなってる?
美咲:0 ?
健一:そう、そして、この行に来ると、それに 1 が加わるんだ。すると?
翔太:0 + 1 だから、1 になるね。
健一:そう、その 1 という値をまた SecCount 変数に代入してるんだ。だから、この次の行に進んだ時点では、SecCount 変数は既に 0 ではなく、1 に変わってるんだよ。
翔太:ということは、ここで DigitalTimer コントロールの Second プロパティに代入される値は、1 になってるってこと?
健一:そう、そのとおり。ここでやってることは、その次の作業と関係しているから、続けて次のコードを書き加えてごらん。


リスト 4-3-9 の後に、リスト 4-3-10 を追加します。


リスト 4-3-10

            // カウントした秒数がタイマー停止時間になったか判断する
            if (SecCount == WaitSecond)
            {
                // 表示画像を変更
                pictureBox1.Image = Part4.Properties.Resources.完成;
                // タイマーを停止
                timer1.Stop();
                // [START] ボタンを有効化
                btnStart.Enabled = true;
            }


翔太:また条件分岐だ。
健一:if の隣の括弧の中に書いてあるのが、条件なんだ。ここでは、SecCount 変数の値と、WaitSecond 変数の値が同じであるかどうかが条件になっている。さっきと同じように、左右の値が同じであることを表わすために「=」を 2 つ続けて「==」として使っている。
翔太:WaitSecond はユーザーが指定した時間を秒数に直したものだったよね。SecCount 変数は、Tick イベントが発生した回数 (秒数) だったはず。でも、それが同じになったらっていうのはどういうこと?
健一:つまり、指定した秒数まで Tick イベントが行われたら、っていうことさ。2 つの変数の値が同じになる、つまり条件の式が成立すると、if から始まる行の次の行にある「{」と「}」の間にある行が実行されるんだ。ここでは、まず完成という画像が表示され、Timer コンポーネントが Stop メソッドで停止する。そして、[START] ボタンを押すと機能が有効になるように設定が変更されるという流れになっている。
美咲:指定した秒数になったら Stop メソッドが有効になる・・・、ということは、Stop メソッドが有効になるまで、イベントが繰り返されるってことね。
健一:そうなんだ。だから、繰り返されるたびに、SecCount 変数は、自分に 1 を加え続ける。そうして、WaitSecond 変数の値に近づいていくんだよ。こうした自分自身に値をくわえるという代入の仕方は、プログラミングでは良く使う手法なんだ。すぐに使えるようにならなくても、こういう繰り返しの作業の際に出てきたんだということを覚えておいてくれればいい。


健一:さあ、ここまででプログラミングは終了だ。出来上がったら、デバッグ ボタンをクリックして、プログラムを動かしてみよう。








もし、うまく動かない場合には、どこかでコードの記述が間違っている可能性があります。デバッグを一旦終了して、コード エディタで内容を確認してください。正しく記述されていれば、次のリスト 4-3-11 のようになっているはずです。


リスト 4-3-11

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Part4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private int SecCount;       // 秒数をカウントする変数
        private int WaitSecond;     // タイマー停止時間を秒単位で記憶する変数

        // 指定したミリ秒毎に実行される処理
        private void timer1_Tick(object sender, EventArgs e)
        {
            // 秒数をカウントし、表示するため DigitalTimer に設定する
            SecCount = SecCount + 1;
            DigitalTimer.Second = SecCount;

            // カウントした秒数がタイマー停止時間になったか判断する
            if (SecCount == WaitSecond)
            {
                // 表示画像を変更
                pictureBox1.Image = Part4.Properties.Resources.完成;
                // タイマーを停止
                timer1.Stop();
                // [START] ボタンを有効化
                btnStart.Enabled = true;
            }
        }

        // [START] ボタンが押されたときの処理
        private void btnStart_Click(object sender, EventArgs e)
        {
            // 指定されたタイマー停止時間を秒単位で記憶
            WaitSecond = (int)(nudMinuteNum.Value * 60 + nudSecondNum.Value);
            // 指定されたタイマー停止時間が 0 秒のときは開始処理をキャンセル
            if (WaitSecond == 0)
            {
                return;
            }
            // 秒数のカウントと表示を 0 に初期化
            SecCount = 0;
            DigitalTimer.Second = 0;
            // 表示画像を変更
            pictureBox1.Image = Part4.Properties.Resources.調理中;
            // [START] ボタンを無効化
            btnStart.Enabled = false;
            // タイマーを開始
            timer1.Start();
        }
    }
}


健一:今回のサンプルはどうだった?
翔太:第 3 章に比べるとまたハードルが高くなったみたいだったけど、でもいろいろ新しい話が出てきて面白かったよ。
美咲:時間に関係するプログラムを書くのって、こんなにいろいろなことをしないといけないのね。今度から、パソコンで時間を確認するときに、中でどういうことをやっているのか考えてしまうかも。
健一:そうやって、実際のプログラムの中の動きを想像してみるのはとてもいいことだよ。でも、いままで勉強してきた内容だと、まだまだあまり高度なことはイメージできないと思う。いきなり高いレベルのことをやろうとする必要はないから、少しずつ勉強していくようにしよう。


健一さんの助けを借りて、何とか第 4 章を終了することができた二人ですが、どうやらプログラムの世界に少し興味が出てきたようです。皆さんは、いかがだったでしょうか。

さて、次の第 5 章では、文字を使ったサンプルプログラムが登場します。第 3 章で少し出てきた文字列を扱う変数についても改めて登場するので、翔太君たちと一緒にさらに詳しい変数の使い方を体験してみてください。


Top of Page Top of Page Top Page プログラミング チャレンジ スクエアへ戻る


Microsoft