LabVIEWと同様なプログラミングによってWeb Applicationを作成することができるG Web Development Software (以下GWDS)を触ったことがない方に向けて、基本的な事柄を解説していこうという試みです。なお、大部分の事柄は、GWDSの前身であるLabVIEW NXG Web Moduleと共通します。
シリーズ8回目としてイベントストラクチャです。
この記事は、以下のような方に向けて書いています。
- イベントストラクチャって何?
- プログラムの効率を上げたい
- イベントストラクチャの注意点は?
もし上記のことに興味があるよ、という方には参考にして頂けるかもしれません。
なお、前回の記事はこちらです。
イベントストラクチャを扱う
前回の記事では、条件によって処理の内容を変えるケースストラクチャを紹介しました。ある処理の結果によって次の処理の内容が変わる、といったプログラムを組めるようになると、途端に組めるプログラムの幅が増えます。
今回の記事では、アルゴリズムそのものというより効率に焦点を置いたプログラムの書き方である、イベントストラクチャについて紹介します。
イベントストラクチャは、簡単に言えば「イベントが起きたことを検出してそのタイミングで実行する処理を記述できる」ストラクチャです。
これだけではピンとこないと思うので、簡単な例を紹介します。

ここで、イベントストラクチャは黄色の枠組みで表されていて、イベントとしてIncrement(という名前のついたブール制御器)に「Value changed (値変更)」が定義されています。なお、ここでIncrementのブール制御器はラッチ動作としています。
ループや、ケースストラクチャ同様、この枠組みの中だけ特別になっていて、イベントストラクチャの場合「特定のイベントが起きたらこの枠組みの中のコードが実行される」ことになり、「枠の外の処理はイベントに関係なく実行される」ことになります。
そしてもちろん、ループやケースストラクチャと共通して「中身の処理が全て終わらないと枠から抜け出さない」「トンネルが存在する」といった共通の特徴を持っています。
上で書いた通り、イベントストラクチャは「イベント」に対して何かしら処理を行うストラクチャです。
イベント、と言われても何のこっちゃと思うかもしれませんが、ユーザーの操作もイベントの一つです。例えば、ブールのボタンを押す、数値の値を変える、文字列制御器の値を変える、これらはすべて「値変更」イベントです。

なので、上記のプログラムは「Incrementのボタンが押されたことで、FALSEからTRUEになったというイベントを検知して、その中の処理である数字をプラス1する」ということを実行することになります。

定義の仕方は簡単で、以下のようにイベントを構成することができます。
まずはイベントストラクチャを用意します。実は用意の仕方は二種類あるのですが、とりあえず下の図の場所のイベントストラクチャを選択してみてください。

配置をしたら、イベントを登録します。
登録は簡単で、イベントの対象(制御器など)を選び、その対象のどんなイベントか(値変更など)を選択していきます。

ここまで終わったら、あとは黄色の枠組みの中に「そのイベントが起きたら処理させたいこと」を書いていくだけです。
なお、もしLabVIEWを触ったことがある方は、設定できるイベントの種類の数が違うことに気づかれたと思います。
GWDSではLabVIEWと比べて設定できるイベントの数がかなり少ないです。LabVIEWの時にはできていたのに、と思わずに、別の環境でプログラムを作っているという認識でコードを書いた方がいいと思います。
ところで、上の方法ではイベントストラクチャを単体でダイアグラムに置く方法を紹介しました。
実は一つのイベントストラクチャで複数のイベントを登録することができます。ただし一度には一つのイベントしか検出しないので、プログラム実行中に複数のイベントが起こりうる場合には、基本的にイベントは繰り返し検出するということになるので、Whileループに入っていることが多いです。
そのため、最初からWhileループ付きのイベントストラクチャというものも用意されています。

最初にプロジェクトを作ったときにindex.gviwebにはWhileループが予め用意されていました。そのWhileループを使うのであればイベントストラクチャ単体を用意すればいいですし、もしWhileループを消した、あるいは追加したいなどといった場合には上の方法でWhileループ付きのイベントストラクチャが便利です。
イベントの追加はプラスボタンを押して行えます。

なお、上記の図でそうしているように、イベント検出の対象になる制御器(上記のIncrementやdecrementのブール制御器など)は基本的にそのイベントケースの中に入れておきます。
イベントケースの外に置いている場合、GWDSがイベントを検出するタイミングと制御器の値が切り替わるタイミングがずれることで予想した結果にならないことがあります。
イベントで動くことを実感する
ここまで読んできて、実際にイベントストラクチャがどういう動作をしているか、いまいちピンと来ないかもしれません。
LabVIEWであれば、実行のハイライト機能を使ってプログラム全体の動作をアニメーションで確認することができるのですが、GWDSにはこの実行のハイライト機能が存在しないのでそれができません。
ですが、イベントが起きないとプログラムが動かないこと自体はつぎのように確認することができます。

ループには、反復端子というものがついていました。これは、今ループの何回目か、という数字を出力してくれる端子です。
通常のWhileループだけだと、ものすごい速さで反復端子が回る様子が確認できます。もし待機関数を使用している場合には、その関数で指定した早さで回ることになります。一方で、イベントストラクチャを使用したWhileループではイベントが実行されるたびに一回の処理が実行されます。
つまり、イベントストラクチャを使用している場合には、ループの「空回り」(不必要に回っている状態)が起こりません。ボタンが押されたら処理を実行する、それ以外のときには処理を実行する必要がない、というときにイベントストラクチャでプログラムの実行そのものを制御します。

もちろん、Whileループの中に入れている待機の関数に指定している値を大きくすることで、ループの繰り返し周期が長くなり、一見空回りが少なくなっているように見えることになりますが、すべての反応も遅くなり、また結局は時間が間延びしただけで空回り自体は起こってしまいます。
くどいようですが、何かユーザーの操作(=イベント)が起こったときだけ動作する、それ以外は動作せず、PC(ブラウザ上で実行している分にはブラウザ?)の負荷にならないようにする、それがイベントストラクチャです。
イベントデータを使用する
これまでの説明で全然触れていなかったのですが、各イベントを作った際に、イベントストラクチャの内部左側に、「Old Value」だとか、「New Value」だとかが表示されていることに気付いたと思います。
これらは、各イベントケース内で補助的に使用できるイベントデータと呼ばれるものになります。別に必ず使う必要があるというものでもないので、使わない場合にはそのまま放っておけばいいです。

ただ、例えばOld Valueだと、値変更イベントが起こる前の値を取得できたりするので、以下のように文字列に対してしりとりができたりします。

・・・まぁこれはちょっと実践的とは言えない例ですが、別に文字列じゃなくても数値の値変更イベントでもこのようなイベントデータを使えるので、何かイベント前後の値で処理を行いたいときなどには便利です。
イベントストラクチャの注意点
さて、とりあえずイベントストラクチャを使用してプログラムを作る基本的な内容は紹介したので、早速前回の記事で作ったタイマーのプログラムをイベントストラクチャで書き直してみようと以下のプログラムを書いてみました。

こちらのプログラム、上の図には反復端子に表示器を付けていませんが、実行すると確かにループは勝手には回りません。ところが、実行しても一向に時間を測ってはくれません。

なぜだかわかりますか?
イベントストラクチャは、イベントが起こらないと実行されません。ところが、上記のタイマープログラムは、毎ループごとに現在の時間と一つ前のループでの時間との差分を計算し、それが指定した時間より大きくなるかで判断させます。つまり、時間を測るにはループが回る必要があります。でもイベントストラクチャはイベントが起こらないと回らない。よって時間を測ることができません。

ここでは特に紹介していませんが、イベントには「タイムアウトイベント」といって、指定した時間が経過する、ということをイベントとして、特定の処理を実行させることができます。
でもそれって、指定した時間が来たら勝手にループが回るので、結局空回りするような状態になっているってことです。ちゃんとタイムアウトイベント自体を使用する場面はあるのですが、今回のタイマープログラムでタイムアウトイベントを使うのは意味がありません。
「じゃあイベントストラクチャでこういうプログラムは書けないの?」というと、そうではなく、実はとてもうまい方法を用いることでちゃんと動くようになります。
そのうまい方法、ベースとなる考え方は実は今までに紹介したGWDSのプログラムの書き方を駆使してできるようになるのですが・・・たぶん思いつくのは難しいと思います。
GWDSには、プログラムテンプレートが存在し、今後紹介するものに「ステートマシン」と呼ばれるテンプレートがあり、これを使うことでイベントストラクチャに対応したタイマープログラムを作れます。
プログラムテンプレートは、これさえ知っておけばこのテンプレートの考え方に当てはめてプログラムを組むだけで立派なアプリケーションが出来上がる、という便利なものです。次々回、ステートマシンを扱う予定です。
今回の記事ではイベントストラクチャについて紹介しました。このイベントストラクチャを使用することで、「空回り」という無駄の出にくいプログラムを作ることができます。
これを覚えていないと書けないプログラム、というのは少ないかもしれませんが、ユーザーの操作に対するレスポンスに関わる可能性があるため、取り入れられる場面ではぜひ取り入れることを検討してみるクセをつけてもらえるといいかなと思います。
一方で、イベントストラクチャだけでは書くのが難しい場面にも遭遇しました。イベントストラクチャの利点を活かしつつ、ちゃんと動くプログラムを作る、そこまでできたらもう初心者卒業だと思います。
次回の記事では、プログラムに深みを持たせるためのいくつかの便利な機能として、プロパティノードとタイプ定義を扱います。これら自体はバラバラなトピックですが、その後に紹介するステートマシンのプログラムを構築する上で役に立ってきます。
もしよろしければ次の記事も見ていってもらえると嬉しいです。
ここまで読んでいただきありがとうございました。
コメント