さて、タイマーの機能をどのようにつけるかを考えてみます。キーボードからのキー入力に反応して、タイマーの画面に切り替わる、などでもいいのですが、解りにくいのでボタンにしようと思います。ボタンを押したら、タイマー画面に切り替えます。
ボタンを表示するためには、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の次の行へジャンプします。
そこまで組んだものがこちらです。そろそろ長くなってきたので、別のテキストにしました。
新しい命令が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秒のループを作って、残り何秒かも表示しましょう。折角なので、これも画像で表示してみましょう。
で、作ってみたのがこれです。
新しい命令、関数のみ紹介します。strlen
関数は、文字列の長さを取得する命令です。時刻表示とタイマーの残り時間表示では表示する文字数が変わるので使いました。objmode
命令は、オブジェクトの文字のフォントを変える命令です。タイマーの入力ボックスを大きくしたかったのに、オブジェクトのフォントがあまりに小さかったので、これを使って大きくしました。あらかじめfont命令でフォントを設定しておき、objmode 2
を実行すると、オブジェクトのフォントがfontで指定したものになります。
タイマー機能を付けたところで、思っていたよりプログラムが長くなってしまったので、全体の流れを図にしてみました。
このように簡易的な図を描くことで、全体の流れや構造を確認しやすくなります。
return
でひとまとまりの処理を挟んだものを「サブルーチン」という。gosub
命令を使うさて、最後の仕上げに、時間が来たら音が鳴るようにしましょう。なんでもいいので、時間が来た時に鳴って欲しいサウンドファイルを用意してください。HSPをインストールしたのであれば、HSPをインストールしたフォルダ(スクリプトエディタのショートカットを右クリックして、[ファイルの場所を開く]とすれば開けます)のhsptvというフォルダに、いくつかサウンドファイルがあるはずなので、コピーして来てください。
使用できるサウンドファイルの拡張子は.wav、.mid、.mp3です。サンプルではhsptvフォルダのse_tyuiin.wavをalt.wavとして使用したいと思います。
サウンドファイルは、最初にmmload
命令を使用して読み込んでおく必要があります。第一パラメータがファイル名、第二パラメータがバッファの番号、第三パラメータがモードです。バッファの番号というのは、複数のサウンドファイルを管理する際に使うもので、0から始まる好きな数値を割り当てることが出来ます。あとから再生する時に、この番号でどのサウンドファイルを再生するかを指定します。モードは、無限ループをさせたりできるのですが、今回は特に使用しないので省略しておきます。
再生にはmmplay
命令を使用します。第一パラメータはmmloadで割り当てたバッファの番号です。途中でサウンドを停止したい場合は、mmstop
命令を使います。これは引数なしで、再生中の全てのサウンドを停止します。
そんなわけで、付け足したのはたった2行です。
mmload
、mmplay
、mmstop
を用いるさて、長かった入門編もいよいよ終盤です。デジタル時計自体はひとまずこれで完成としましょう。お疲れ様でした。続いては、このHSPで作ったプログラムを一般に公開するための方法をご紹介しましょう。
デジタル時計の機能自体は、これ以上強化しません。でも正直これでは味気ないとか、見かけが地味だとか、色々あると思います。ここから改造していくのは皆さんの自由です。以下に、改造のポイントを挙げてみますので、参考にしてください。