タイマーを付けよう

サブルーチン

さて、タイマーの機能をどのようにつけるかを考えてみます。キーボードからのキー入力に反応して、タイマーの画面に切り替わる、などでもいいのですが、解りにくいのでボタンにしようと思います。ボタンを押したら、タイマー画面に切り替えます。

ボタンを表示するためには、button命令を使用します。ボタンが押されると、その瞬間、ソースコードのどこを実行していても、goto命令が出されるのと同じようにジャンプが起きます。

なので、まず全体の無限ループをラベルとgotoに戻します。というのも、repeatからloopの間をgotoで抜けてしまうと、HSPはそのことを認識できずに「まだrepeat~loopの間だ」と思い込んでしまいます。これが放置されるとおかしなことになって、いつかはエラーになってしまいます。

…と、思ったのですが、まだもう一つrepeat~loopがありました。こちらは何周目かという情報も必要です。うーん、どうしましょう。

色々考えましたが、「サブルーチンジャンプ」を利用しようと思います。これも非常に便利な道具です。gosubラベルreturnのセットで使うものです。

gosubは、ラベルを第1パラメータとして、gotoと同じように次の実行行を変更(ラベルの場所へジャンプ)します。一つ違う点は、gosubが実行された行を覚えている、という事です。そして、ジャンプしたラペルの次の行から実行を進めて行きます。そして、その先にreturnが書いてると、奇跡が起きます。なんと逆ジャンプするのです。正確には、gosubが実行された行へ実行行が戻ります。そして、何事も無かったかのように続きが実行されるのです。

…やっぱり言葉じゃわかりにくいですね。サンプルです。

	gosub *mktime

	mes "現在時刻は["+time+"]です。"
	wait 100
	mes "たとえどんなときだって、"
	wait 100
	mes "サブルーチン*mktimeは呼び出せます。"
	wait 100

	gosub *mktime

	mes "現在時刻は["+time+"]です。"

	stop

*mktime
	;timeに現在時刻を「Am 01:23:45」のような形で代入
	hor=gettime(4)
	if hor<12 { time="A" }else{ time(0)="P" }
	if hor>12 { hor-=12 }
	time+=strf("m %02d:%02d:%02d",hor,gettime(5),gettime(6))
	return
	

つまり、gosubが書いてある場所に、ラベルからreturnまでが割り込んでくるような感じです。なので、gosubでサブルーチンへジャンプする事を「サブルーチンを呼ぶ」なんていうこともあります。

このサブルーチンジャンプには、「一つの作業をまとめておくことでソースコードが見やすくなる」、「何度も行う同じ作業を一つにまとめられる」という2つの利点があります。

このgosubのとび先のラベルからreturnまでは、一つの作業がまとめてあることが多いので、「サブルーチン」といいます。

でもって、ボタンをジャンプをサブルーチンジャンプにしてしまおうと思います。button gosub "timer",*timeronと書くと、ボタンが押されたときに指定されたラベルへサブルーチンジャンプするようになります。

そして、modeという一つ変数を用意しておいて、ボタンのジャンプ先でmode=1とし、returnするようにしておきます。あとは時計のループの中でmodeをチェックして、mode==1ならボタンが押されたとわかるので、repeat~loopを終わりにして、タイマーモードに移行します。repeat~loopを安全に抜け出すためには、break命令を使用します。repat~loopの間でこれを使用すると、反復を終了してloopの次の行へジャンプします。

そこまで組んだものがこちらです。そろそろ長くなってきたので、別のテキストにしました。

clock71.hsp

新しい命令が2つ。clrobjは「オブジェクト」を削除する命令です。詳しくは後程。今回はボタンを消すのに使っています。objsizeはオブジェクトの大きさを決めるものです。こちらも後程。

大体は、画像の読み込みやメインウインドウの形の設定など起動の準備を行う部分、時計モードの画面準備と実際の時刻表示を行う部分、タイマー画面を用意する部分(未完成)、時計のボタンが押された時それを記録するサブルーチンに分かれています。

プログラムは、最初大体時計の時刻表示の部分に留まっています。その間にボタンが押されてmodeが1になると、breakが実行されてタイマー画面が生じされてstopで止まります。新しく表示されなおしたボタンが押されると、時計画面の準備が始まるところまで戻されて、また時計の表示が始まります。

オブジェクト

ここで、オブジェクトについて説明しておきます。オブジェクトとは、Windowsが用意してくれているウインドウ内の部品の事です。HSPの場合、ボタンの他に入力ボックス、メッセージボックス、リストボックス、コンボボックス、チェックボックスなどが利用できます。

clrobjの第一、第二パラメータは、オブジェクトをどこからどこまで削除するか「オブジェクトID」で指定します。オブジェクトIDはオブジェクトを作った順に0、1、2、…と勝手につけられる番号です。削除されたオブジェクトのIDは再利用されます。ボタンA,B,Cをつくると、Aが0、Bが1、Cが2です。もしBがclrobjなどで削除され、入力ボックスが新たに作られたとすると、入力ボックスのオブジェクトIDは1になります。

今回はタイマーなので、入力ボックスを使って何秒間待つかを入力してもらうようにしましょう。そんでもって、また1回が1秒のループを作って、残り何秒かも表示しましょう。折角なので、これも画像で表示してみましょう。

で、作ってみたのがこれです。

clock72.hsp

新しい命令、関数のみ紹介します。strlen関数は、文字列の長さを取得する命令です。時刻表示とタイマーの残り時間表示では表示する文字数が変わるので使いました。objmode命令は、オブジェクトの文字のフォントを変える命令です。タイマーの入力ボックスを大きくしたかったのに、オブジェクトのフォントがあまりに小さかったので、これを使って大きくしました。あらかじめfont命令でフォントを設定しておき、objmode 2を実行すると、オブジェクトのフォントがfontで指定したものになります。

タイマー機能を付けたところで、思っていたよりプログラムが長くなってしまったので、全体の流れを図にしてみました。

どのような動作になっているのかが一目瞭然です。

このように簡易的な図を描くことで、全体の流れや構造を確認しやすくなります。

サウンドの扱い

さて、最後の仕上げに、時間が来たら音が鳴るようにしましょう。なんでもいいので、時間が来た時に鳴って欲しいサウンドファイルを用意してください。HSPをインストールしたのであれば、HSPをインストールしたフォルダ(スクリプトエディタのショートカットを右クリックして、[ファイルの場所を開く]とすれば開けます)のhsptvというフォルダに、いくつかサウンドファイルがあるはずなので、コピーして来てください。

使用できるサウンドファイルの拡張子は.wav、.mid、.mp3です。サンプルではhsptvフォルダのse_tyuiin.wavをalt.wavとして使用したいと思います。

サウンドファイルは、最初にmmload命令を使用して読み込んでおく必要があります。第一パラメータがファイル名、第二パラメータがバッファの番号、第三パラメータがモードです。バッファの番号というのは、複数のサウンドファイルを管理する際に使うもので、0から始まる好きな数値を割り当てることが出来ます。あとから再生する時に、この番号でどのサウンドファイルを再生するかを指定します。モードは、無限ループをさせたりできるのですが、今回は特に使用しないので省略しておきます。

再生にはmmplay命令を使用します。第一パラメータはmmloadで割り当てたバッファの番号です。途中でサウンドを停止したい場合は、mmstop命令を使います。これは引数なしで、再生中の全てのサウンドを停止します。

そんなわけで、付け足したのはたった2行です。

clock73.hsp

さて、長かった入門編もいよいよ終盤です。デジタル時計自体はひとまずこれで完成としましょう。お疲れ様でした。続いては、このHSPで作ったプログラムを一般に公開するための方法をご紹介しましょう。

コラム:これからの改造案

デジタル時計の機能自体は、これ以上強化しません。でも正直これでは味気ないとか、見かけが地味だとか、色々あると思います。ここから改造していくのは皆さんの自由です。以下に、改造のポイントを挙げてみますので、参考にしてください。

目次へ戻る