この記事は、初心者向けのまずこれシリーズ第16回の補足記事です。イベントストラクチャの使用法についてもっと知りたい、という方向けにもう少し内容を補足しています。
この記事では、イベントストラクチャについて知っておくと役に立つかもしれない3つのトピックについて簡単に紹介してきます。
- プログラム的な値変更に対するイベント検知
- イベントのダイナミック登録
- ユーザイベントの生成
ある程度大きなプログラムを書いたり、アーキテクチャを工夫しないと実現できないようなプログラムとする場合でないとあまり使用しないテクニックかもしれません。
実際この記事で扱う内容を知らなくてもプログラムを書ける場合が多いですが、選択肢の幅を広げるためにも知っておいて損はないと思います。
以下それぞれの項目について紹介していきます。
プログラム的な値変更に対するイベント検知
イベントの中でもかなり頻繁に使用するのが値変更イベントだと思います。ユーザーが起こすイベントは基本的にフロントパネルの何かしらの操作でありその操作の結果数値やブールの値が変更することを受けてイベントとするものです。
しかし、中にはユーザーによる操作ではなく、プログラムの動作の結果値が変更した際にその値変更をイベントとして検出したい場面が出るかもしれません。
以下のサンプルは実用的ではないですが例としてブールボタンを押すことで数値表示器の値が1ずつ増加するように組んだ場合の例です。
ブールの値変更イベントが実行されることで数値表示器の値が変わるので、その値変更を受けて数値の値変更イベントを起こそうとしています。
ですが、値の変化がただ起こってもイベントとして検出されることはありません。上のブロックダイアグラムのプログラムを実行しても、意図したとおりの文字表示はされることはありません。
この場合には値の変更をプロパティノードを使用して行います。ただ、単なるプロパティノードの「値」プロパティではできず、「値(信号)」というプロパティを使用します。
プロパティノード自体はまずこれの第18回の記事で取り上げているのでもしわからないという方はこちらを見ていただくといいと思います。
下の図に表示したような「値(信号)」という項目を使用して意図した動作を得られます。
ただしこの形のプログラムにした場合には、結果文字列で表示する反復の回数は数値の表示器の値をNとしすると、常に2N-1の値になることに注意します。
なぜなら、イベントとしては常に「ブールに対する値変更」からの「数値表示器に対する値変更」の二つがカウントされるわけで、数値表示器に対する値変更の前にブールに対する値変更でループが一度回るためです。
実際は上記のような組み方をする場合はほとんどないと思いますが、いずれにしろプログラム的な値変更を検出させる場合にはその対象(数値表示器など)をプロパティノードによって値を変更させることで実現できます。
イベントのダイナミック登録
イベントはプログラム実行前、つまり編集の時点であらかじめ設定しておくことができる一方で、プログラムの実行中に設定を行うといったことができます。これがダイナミックイベント登録です。対してあらかじめプログラムの編集時点で登録する方法はスタティック登録、と言えます。
とはいっても、プログラム編集時に、そのイベント登録されるであろうイベントに対するコードはもちろん用意する必要があります。
組み方としては簡単で、イベント登録に設定したい制御器や表示器のリファレンスをつなげ、登録したいイベントを選択後、イベント登録のイベント登録refnumをイベントストラクチャに配線します。
イベントストラクチャには「ダイナミックなイベント端子を表示」で特殊なノードを表示させておきます。
あとはこのダイナミックイベントに対してイベントを用意できるように設定します。
なお、イベントをダイナミックに登録してそのWhileループが終わったら、好きなタイミングでイベント登録解除の関数を使用すれば、それ以降ダイナミック登録したイベントの検出は行われません。
ちょっと面倒なこの作業、どういった役割があるかというと、まず登録がされない限りイベントストラクチャはイベント検出しません。そして逆に、プログラム中で登録を解除することができます。解除されたイベントはもはやイベントとして検知されなくなる、ということになります。
まずこれの第16回の記事でイベントストラクチャの注意点として、イベントはプログラム実行が終了するまで検出され続けるという注意点について書きましたが、これはスタティックなイベント登録がされている場合であり、ダイナミックイベント登録だと余計なイベント検出をやめることができるためトラブルを回避できます。
具体例を示すため、あらためてまずこれの記事で挙げていた注意点について以下に紹介します。
イベントストラクチャの入ったWhileループがあり、そのWhileループが終わった後にもプログラム自体が続くときに問題が起こる、という話です。
上の図で第一ループ停止ボタンを押すとイベントストラクチャが入ったWhileループは止まり次のWhileループが始まりますが、この間に数値制御器を変更する(数値の値変更イベントに対応)と、イベントを検知するもののイベントそのものは実行できない(左のWhileループは終了しているためですね)ためフロントパネルがロックされます。
この問題をダイナミックイベント登録によって解消することができます。つまり、数値制御器の値変更というイベントをダイナミックに登録し、イベントストラクチャが終わったらこれを解除することで、数値制御器の値変更イベントそのものが検知対象から外すことができます。
ここまで読んで、「あれ、こう書いたとしても左側のWhileループを抜けた後に、第一ループ停止ボタンを押したらフロントパネルのロックは起こるのでは?」と思った方は正しく理解できていると思います。
まさにその通りで、イベント登録解除でイベントの検出対象から外れるのはあくまでダイナミックにイベント登録したもののみで、もし第一ループ停止ボタンの値変更をスタティックにイベント登録していた場合には相変わらずフロントパネルのロック状態が発生しえます。
気を付ける点はありますが、イベントの登録さえもプログラム的に組むことで、意図しない動作を防ぐ組み方をするときなど役立てることができるかと思います。
ユーザイベントの生成
イベントの生成は、あらかじめ決められたイベントだけではなく、ユーザがオリジナルのイベントを登録、そのイベント内でデータを使用、という使い方もできます。
これにはユーザイベントと呼ばれる一連の組み方があります。ほぼテンプレートといっていいと思うので、こういう形式だということで覚えてしまっていいと思います。
ユーザイベントには、そのイベントでどのようなデータを使いたいか、をクラスタ定数で与えてやります。また、このクラスタ定数の名前自体がイベントの名前になります。
そしてこのユーザイベントを起こすには、ユーザイベント生成関数を使用します。
例えば、フロントパネルのボタンを押すとある乱数を生成し、その乱数を出した時刻と乱数を10倍下数を表示させるというイベントをユーザイベントとします。
このユーザイベントを起こすには、ユーザイベントを生成関数が実行される必要があります。例えばフロントパネルに乱数という名前のボタンがあるとして、これの値変更イベントの中でユーザイベントを生成するとします。
プログラムを実行すると、乱数ボタンを押すことで乱数が一つ生成され、またユーザイベントを生成が実行されることでユーザイベントである「乱数生成」が実行されます。
イベントが実行されたタイミングを調べたいときには、メニューバーの「表示」から「イベント検査ウィンドウ」を出してプログラムを実行することでどのイベントがどの順番に実行されたかを確認できます。
この例で紹介したプログラム程度であれば、そもそも乱数のボタンの値変更イベントで時刻と10倍した値を表示させればいいのでプログラムとしては無意味なのですが、流れはなんとなくでもつかめたでしょうか?
この記事で紹介したより実践的なイベントの具体的な例はサンプルファインダにサンプルがあります。
検索のタブでイベントと検索して見つかる、「ダイナミックイベント生成」と「ユーザイベント生成」がそれらにあたります。これに限らず、サンプルファインダにあるサンプルではイベントストラクチャを使用した様々なサンプルがあるのでいろいろ見てみると面白いと思います。ただし「ユーザイベント生成」のサンプルはステートマシンの知識を必要とします。
まずこれの記事では、プログラムをより効率よく実行するためにイベントストラクチャを使用するという話をしていました。
この補足記事で上げている内容は少し高度な(複雑な)内容になっているかもしれません。しかし、冒頭でもお話ししたように、プログラムの効率を上げるために知っておくと役に立つかもしれないものとして内容だけでも知っていれば、全く知らないよりはプログラムの組み方の選択肢が増えるので頭の片隅にでも入れておくのに越したことはないと思います。
ここまで読んでいただきありがとうございました。
コメント