イベント。それは何かが始まる予感・・・~イベントの基本~
年度の切り替わりや大型連休が過ぎ去り、そして梅雨が明け・・・・夏のイベントを心待ちにウキウキワクワクとカレンダーを眺めているみなさん。
お久しぶりです。エイタです。
そういえば PowerBuilder は「イベントドリブン型」のプログラムなんですよね。 それを全くお伝えしていなかったなと。 イベントといっても展示会とかセミナーとかってわけじゃない。 ましてや文化祭とか卒業式とか、そんな心躍るようなものでもありません。
しかし、これが無ければ何も始まらない! 今回はそんな「イベント」の基本について説明していきます!
イベントってなに?
コンピュータープログラムでいうところの「イベント」というのは、アプリケーションやオブジェクトに対して「何か操作された」場合に発生する処理のことです。 たとえば自動販売機にお金を入れてボタンを押したら飲み物が出てくるでしょ? あれと同じ。 投入口に「貨幣が投入される」というイベントによって「投入金額を表示する、購入可能な商品のボタンを点灯する」という処理が実行され、「ボタンが押される」というイベントで「飲み物を出す」といった処理が実行されるって感じです。
多くのプログラム言語では「イベントハンドラ (どんな時に発生するか?)」の定義を自前で記述しなければいけない場合が多いんですが、PowreBuilder ではそんなことは必要ない。 IDE では各コントロールのイベントがリストされていて、そこから記述したいイベントを選択し、処理を書くだけ。 データウィンドウにしても「値が入力されたとき (ItemChanged)」、「クリックされたとき (Clicked)」、「垂直スクロールしたとき (ScrollVertical)」などなど、一般的な操作については既に用意されているので、それほど困ることはありません。
イベントドリブンの基本はウィンドウや配置されたコントロールに対してユーザーがどのような操作をした場合にどのような処理を実行するか、というところです。 つまり、ユーザーとアプリケーションの対話がイメージしやすいんです。 上の図のようなさまざまな操作に対して、どんな処理を実行するかという仕様をもとに実装していきます。
イベントに処理を書く前に・・・
さて、あなたは今「ボタンがクリックされたときの処理を書きたい」と思い立ったとします。 そんな時に何から始めたらいいのかを説明していきましょう。
ウィンドウに配置したボタンをダブルクリックするか、右クリックメニューの [スクリプト] を選択してみてください。
するとそのボタンのイベントを記述するためのスクリプトエディタが表示されるはず。 上部にはドロップダウンが 3 つありますね。 左のドロップダウンは対象のコントロール (コマンドボタンやデータウィンドウなど) で、真ん中がそのコントロールのイベントです。 右のドロップダウンは先祖を選択することができ、先祖に記述された処理を確認することができます (先祖がない場合は使用不可です)。
その右側にある [プロトタイプの表示/非表示] ボタンはイベントの名前や戻り値、引数等を確認することができます。 一番右の [エラーの表示/非表示] はその名の通り、コンパイルエラーが表示される領域を表示するかしないか、を切り替えることができます。
あとはスクリプトエディタに処理を書いていくだけ。 イベントの引数や戻り値がどのように機能するかを説明しながら、イベントへの処理の書き方を見ていきましょう。
イベントの引数
イベントには引数を持つものもあります。 この引数にはイベントが発生した際に自動で値が格納されます。 たとえば データウィンドウコントロールのカラムの値が変更された際に発生する ItemChanged イベントには row、dwo、data という 3 つの引数があります。 それぞれ、「どの行 (row)」の「どのカラム (dwo)」に、「どんな値 (data)」が入力されたか、が渡されます。 この引数を使って、「特定のカラムの値が変更されたことを判定する」であったり「入力された値をチェックする」といったことができます。
たとえばこんな感じ。 ItemChanged イベントの引数 data を確認することで、「どんな値が入力されたか」を知ることができます。
[DataWindow の ItemChanged イベント]
string ls_column_name long ll_input ls_column_name = dwo.name // emp_id が入力された場合 IF ls_column_name = "emp_id" THEN // 入力値を数値型に変換 ll_input = Long(data) // 入力された値をチェック (1 ~ 999) IF ll_input < 1 OR ll_input > 999 THEN MessageBox("エラー", "社員ID は 1 ~ 999 の範囲で入力してください。") RETURN 1 END IF END IF
引数を確認することで、そのイベントがどのように発生したかという詳細を知ることができるんですね。
ほかにもクリックされた座標 (Window コントロールの Clicked イベント) であったり、データベースエラーが発生したときの SQL (DataWindow コントロールの DBError イベント) といった情報が取得できます。
イベントの戻り値
イベントの多くは戻り値を持っています。 イベントの戻り値の役割りとしては、一般的な関数のように「呼び出し元に情報を返す」というより、「イベントが発生した後にどのように動作させるか」という意味合いのほうが近いです。
ちょっとわかりにくいと思うので、またまたデータウィンドウコントロールの ItemChanged を例にすると、このイベントでは戻り値によって下記のように処理の後の動作が変わります。
ItemChanged イベントの戻り値
戻り値 | 動作 |
---|---|
0 | データを受け付ける。 |
1 | 入力されたデータを却下したうえでフォーカスも移動できない。 |
2 | 入力されたデータを却下するが、フォーカスは移動できる。 |
さきほどの「イベントの引数」の例では emp_id に 1 ~ 999 以外の値が入力された場合には RETURN 1 を返しており、範囲内の値を入力するまではフォーカスが動かせないという動作になります。
ほかにも、ウィンドウコントロールが閉じられようとしたときに発生する CloseQuery イベントでは RETURN 1 を返すことでウィンドウが閉じるのをキャンセルできます。 これを使えば「本当に画面を閉じてもいいんですか?」みたいな動作を実装できます。
[Window の CloseQuery イベント]
// 画面の終了確認 IF MessageBox("確認", "画面を閉じてもよろしいですか?", Question!, OKCancel!) = 2 THEN RETURN 1 //戻り値 1: クローズをキャンセル END IF
RETURN を記述しなかったり、特定の値を返さずに RETURN した場合はデフォルトの動作になります。 詳しくはヘルプを確認してください。
(PowerBuilder 2017 R3 のマニュアルはこちら)
イベントの呼び出し
イベントは通常、何らかのユーザーの操作によって発生しますが、スクリプトで関数のように呼び出すことも可能です。 呼び出し方法にはいくつかあります。 例えばコマンドボタン (cb_1) の Clicked イベントを呼び出すときは以下のような感じ。
[EVENT キーワードを使用]
control.EVENT clicked()
[TriggerEvent 関数でイベント名を文字列で指定]
cb_1.TriggerEvent("clicked")
[TriggerEvent 関数でイベントを TrigEvent カタログデータ型で指定]
control.TriggerEvent(clicked!)
一番わかりやすいのが、最初の EVENT キーワードを使用する方法でしょう。 引数が定義されているイベントの場合は、関数と同様に引数を渡して呼び出します。
// 50 行目が選択されたときのイベントを発生させる dw_1.EVENT RowFocusChanged(50)
TriggerEvent 関数の用途としては、コンパイルの時点でその名前を持つイベントが存在するかどうかがわからない場合に便利です。 使用するオブジェクトやコントロールが動的に決まる場合、コンパイルの時点ではオブジェクトに固有に定義されたイベントが不明なので、コンパイルエラーになります。 これを避けるために文字列として指定して、アプリケーションの実行時に動的に呼び出すということができます。
// ユーザーオブジェクトに modified というイベントがあるはず uo_1.TriggerEvent("modified")
存在しないイベント名が指定されてもコンパイルエラーにはならず実行時に例外エラーになるので、そこだけは注意しましょう。
また、イベントの呼び出しはあくまでイベントに記述した処理が実行されるだけです。 たとえば ItemChanged イベントをスクリプトから呼び出しても、実際に値が入力されるわけではないのでご注意を。
ユーザーイベントの作成
イベントは自分で作ることもできます。 既存のイベントだけでも多くの操作をカバーできますが、操作に対応するイベントが用意されていないこともあります。 たとえばデータウィンドウでは、「キー入力時」のイベントが用意されていません。 そんな時はイベントを自作し、コントロールへの操作にマッピングしてしまうことができます。
では、さっそくデータウィンドウ上でキー入力が行われたときのイベントを作っていきましょう。
まずは対象のデータウィンドウのイベントを開き、[1] 真ん中のドロップダウンで “(新規イベント)” を選択します。 すると「戻り値のデータ型」や「イベント名」、「引数」といった情報の入力が可能になりますが、まずは [2]「イベント名」を入力しましょう。 今回は “ue_key” とします。 “ue_” は「ユーザーイベント (User Event)」を意味するプレフィックス (接頭辞) です。
次に [3] 「イベント」を設定 します。 この「イベント」というのはコントロールに対するさまざまな操作にマッピングされており、「イベント ID」とも呼ばれます。 データウィンドウのキー入力にマッピングされたイベント ID は “pbm_dwnkey” です。
後はスクリプトを記述していくだけです。 下記はデータウィンドウ上で Enter キーを入力されたときに Tab 移動を実現するサンプルです。
[DataWindow の ue_key イベント (pbm_dwnkey)]
IF key = KeyEnter! THEN // [Enter] 押下時 IF keyflags = 2 THEN // [Ctrl + Enter] の場合は何もしない (Enterの入力を有効にする) RETURN 1 ELSE // [Ctrl] が押されていない場合は Tab 移動する Send(Handle(this), 256, 9, Long(0,0)) RETURN 1 END IF END IF
自分でイベントを作るなんて初めはドキドキしますが、開発の幅が広がってユーザーの細かな要件に応えられるようになります。 ぜひマスターしましょう!
ちなみに「イベント」を “(none)” に設定したイベントはどんな操作にも紐づかず (マッピングされていない)、スクリプトから呼び出すことしかできないイベントです (「非マップイベント」と呼ばれたりします)。 スクリプトからしか呼ばれないなら、ユーザー定義関数と何が違うのか? と言うと、呼び出し側で戻り値が受け取れないというデメリットがありますが、TriggerEvent/PostEvent 関数を使えばイベント名を文字列で指定して呼び出すことができるので、関数と比べて動的な呼び出しが実装しやすいというメリットがあります。
イベントに関する注意点
イベントによっては別のイベントを発生させる場合もあります。 また、特定のメソッドがイベントが発生することも (Resize メソッドを呼び出すと Resize イベントが発生するとか)。 このため、イベント内で呼び出した処理がそのイベント自身を発生させ・・・といった無限ループによりアプリケーションの動作が不安定になることもあるので、イベント内で自身のイベントが呼び出されないようご注意ください。
また、デバッグ時にはデバッグ画面が表示される都合上、画面のアクティブ状態が変化します。 そのため GetFocus、LoseFocus、Activate、Deactivate といったイベントが意図せず発生することがあり、想定しない順序でイベントが実行されることがあるのでこちらも注意してください。
まとめ
今回はイベントについて説明してきましたが、この「イベント」というものは PowerBuilder アプリケーション開発のベースとなる考え方です。 どんな操作をしたときにどんな処理を実行すると便利なのか。 そんなことを考えながら設計していくとユーザビリティの高いアプリケーションが作れるのではないでしょうか。
さて、みなさんは次のイベントって決まっていますか? えーと・・・次の連休は・・・遠いな。
いや、イベントは待っているだけではなく、自分で作ってしまえばいいんですよね!
発生させたイベントで、いったいどんな処理が走るのか? わからないからこそ人生は面白い! ENJOY IT!
・・・あ、プログラミングでは処理をしっかり把握したうえで実装してくださいね!
以上、エイタでした!