ここでは、ユーザーがGUIコンポーネントを操作した際に処理を行う、「イベント処理」について解説します。
これまでは、プログラムを実行すると、あらかじめ決まりきった処理の流れに基づいて、処理が行われてきました。
一方、GUIを用いたプログラムでは、ユーザーがボタンをクリックしたり、マウスを動かしたりした時 に、それぞれに対応した処理を行う必要があります。 「いつ処理されるか」は決められないため、「何かが起こった時に処理する」という形に、処理の流れの考え方を変える必要があるわけです。
このような処理を扱うための仕組みの一つが、「イベント駆動プログラミング」です。VCSSLのGUIの処理は、典型的なイベント駆動プログラミングの仕組みを採用しています。
イベントとは、「何かが起こった時に処理する」における、「起こった何か」を指す用語です。 そして、その「何かが起こった」という事を、「イベントが発生した」と言います。
例えば、「ユーザーがボタンをクリックした」とか、「マウスが操作された」といった事がイベントです。
さて、イベントが発生すると、それに対応する関数がシステム側から呼ばれます。 このような関数の事を一般に「イベントハンドラ関数」と呼びます。
イベントハンドラ関数の内容はあらかじめ用意されているのではなく、プログラムの書き手が自由な内容を記述します。
VCSSLでは、 処理したいイベントの種類に応じて特定の関数名と引数を持たせると、 それが自動的にイベントハンドラ関数と見なされ、イベント発生時に呼び出されます。 特別な登録処理などを行う必要はありません。
VCSSLのイベントハンドラ関数は、以下のように共通した特徴を持っています:
ここからは、実際に様々な種類のイベントと、イベントハンドラ関数の仕様を見ていきましょう。
ウィンドウに関するイベントを処理するには、以下のイベントハンドラ関数を使用します。
イベントハンドラ関数 | 引数 | イベント |
onWindowOpen | int id | ウィンドウが起動した際に呼び出されます。 |
onWindowClose | int id | ウィンドウが閉じた際に呼び出されます。 |
onWindowMove | int id, int x, int y |
ウィンドウが動いた際に呼び出されます。 |
onWindowResize | int id, int width, int height |
ウィンドウサイズが変わった際に呼び出されます。 |
onWindowShow | int id | ウィンドウが表示された際に呼び出されます。 |
onWindowHide | int id | ウィンドウが非表示になった際に呼び出されます。 |
引数は以下の通りです:
ここで特に重要なのがonWindowClose関数です。 このイベントハンドラ関数内で exit() 関数をコールするようにすると、 一般的なソフトウェアのような「 ウィンドウを閉じると処理を終了する 」という機能を実現できます。
これまで、VCSSLプログラムを終了させるには、 VCSSLコンソールを手動で閉じるしかありませんでした。 しかし、ウィンドウを閉じればプログラムが自動終了するようにしておけば、 VCSSLコンソールは不要なので、hide() 命令で隠してしまっても問題ありません。
ボタンに関するイベントを処理するには、以下のイベントハンドラ関数を使用します。
イベントハンドラ関数 | 引数 | イベント |
onButtonClick | int id, string text |
ボタンがクリックされた際に呼び出されます。 |
引数は以下の通りです:
セレクトフィールドに関するイベントを処理するには、以下のイベントハンドラ関数を使用します。
イベントハンドラ関数 | 引数 | イベント |
onSelectFieldClick | int id, string text |
セレクトフィールドがクリックされ、項目が選択された際に呼び出されます。 |
引数のidには、イベントが発生したセレクトフィールドのGUIコンポーネントIDが渡されます。 また、引数のtextには、選択された項目名が渡されます。
チェックボックスに関するイベントを処理するには、以下のイベントハンドラ関数を使用します。
イベントハンドラ関数 | 引数 | イベント |
onCheckBoxClick | int id, bool state |
チェックボックスがクリックされた際に呼び出されます。 |
引数のidには、イベントが発生したチェックボックスのGUIコンポーネントIDが渡されます。 また、引数のstateには、チェックボックスのON/OFF状態が渡されます。
GUIコンポーネント上でキーボードのキーを操作した際には、キーイベントが発生します。
注意:
ただし、キーイベントを利用するには、キーイベントがどのGUIコンポーネント上で発生するかという点に関して注意が必要です。
もし、ウィンドウ上に、テキストフィールドなどのキーボード入力を扱うGUIコンポーネントが配置されている場合、キーイベントは優先的にそれらのGUIコンポーネント上で発生します。もしもその横に、グラフィックスラベルなどを配置していて、その上でキーイベントを拾おうとしても、うまく拾えません。
また、ウィンドウ上にボタンなどの特定のキー操作(ENTERなど)に反応するGUIコンポーネントが配置されている場合にも、その特定のキー操作を、他のGUIコンポーネント上でイベントとして拾えない場合もあります。
そのため、テキストラベルやグラフィックスラベルなどの、一般にキー入力がされないGUIコンポーネント上で、キーイベントを利用したい場合は、 ウィンドウ上にテキスト入力系コンポーネントやボタンなどは配置しない事が推奨されます。
キーイベントを処理するには、以下のイベントハンドラ関数を使用します。
イベントハンドラ関数 | 引数 | イベント |
onKeyDown | int id, string key |
キーが押された際に呼び出されます。 |
onKeyDown | int id, int keyCode |
キーが押された際に呼び出されます。 |
onKeyUp | iint id, string key |
キーが離された際に呼び出されます。 |
onKeyUp | iint id, int keyCode |
キーが離された際に呼び出されます。 |
引数は以下の通りです:
上記の通り、2つめの引数には、string 型とint型の2通りがあります。 前者は、キーの表面に印字された(キーラベルの)文字列が格納されます。 例えば「A」のキーを押した際は "A" が、「@」のキーを押した際は "@" が格納されます。 それに対して後者は、キーに1対1で割り振られた整数値が格納され、 例えば「@」のキーを押した際はKEY_ATの値が格納されます。
前者と後者にはそれぞれメリットとデメリットがあります。 前者は比較的手軽に扱える上、 連続したキー入力内容をstring変数末尾に追記していくような処理に便利です。 反面、キー判別に key == "@" といったリテラルの文字列比較を多用するのはミスタイプに弱く、 厳格性に欠けるため、大きなプログラムでは好ましくありません。 それに対して後者は、厳格な記述が可能ですが、 小さなプログラムでは記述が面倒になる場合があります。
文字列 | キーコード | 文字列 | キーコード |
A〜Z | KEY_A〜KEY_Z | 0〜9 | KEY_0〜KEY_9 |
F1〜F12 | KEY_F1〜KEY_F12 | @ | KEY_AT |
/ | KEY_SLASH | ||
ENTER | KEY_ENTER | + | KEY_PLUS |
SPACE | KEY_SPACE | - | KEY_MINUS |
TAB | KEY_TAB | , | KEY_COMMA |
SHIFT | KEY_SHIFT | . | KEY_PERIOD |
CONTROL | KEY_CONTROL | ALT | KEY_ALT |
; | KEY_SEMICOLON | [ | KEY_LEFT_SQUARE_BRACKET |
^ | KEY_CIRCUMFLEX | ] | KEY_RIGHT_SQUARE_BRACKET |
UP | KEY_UP | DOWN | KEY_DOWN |
LEFT | KEY_LEFT | RIGHT | KEY_RIGHT |
GUIコンポーネント上でマウスを動かしたり、 クリックしたりすると、マウスイベントが発生します。 マウスイベントを処理するには、以下のイベントハンドラ関数を使用します。
マウス操作は行えるアクションが多彩なので、 それに応じてイベントハンドラも様々なものが用意されています。
イベントハンドラ関数 | 引数 | イベント |
onMouseOver | int id, int x, int y |
マウスがコンポーネント領域内に入った際に呼び出されます。 |
onMouseOut | int id, int x, int y |
マウスがコンポーネント領域外に出た際に呼び出されます。 |
onMouseMove | iint id, int x, int y |
マウスがコンポーネント領域内で動いた際に呼び出されます。 |
onMouseCkick | int id, int x, int y, int button, int count |
マウスのボタンがクリックされた際に呼び出されます。具体的には、環境に設定された短い時間内で、マウスボタンが「 押し離し 」された場合に呼ばれます。 |
onMouseDown | int id, int x, int y, int button |
マウスのボタンが押された際に呼び出されます。 |
onMouseUp | int id, int x, int y, int button |
マウスのボタンが離された際に呼び出されます。 |
onMouseDrag | int id, int x, int y, int button |
マウスのいずれかのボタンがドラッグされた際に呼び出されます。 |
onMouseScroll | int id, int degree |
マウスホイールが操作された際に呼び出されます。 |
引数は以下の通りです:
実際に各種イベントハンドラ関数を使用してみましょう。 以下のように記述し、実行してみてください。
import GUI ;
import Graphics ;
// =============================================
// GUIコンポーネントの配置 ここから
// =============================================
// ( x, y ) = ( 300, 20 ) の位置に幅360×高さ480のウィンドウを生成
int windowID = newWindow( 300, 20, 360, 480, "Hello GUI" ) ;
// ( 10, 10 ) の位置に100×50のボタンを配置
int buttonID = newButton ( 10, 10, 100, 50, "PUSH" ) ;
mountComponent( buttonID, windowID ) ;
// ( 10, 70 ) の位置に100×50サイズのテキストフィールドを配置
int textFieldD = newTextField( 10, 70, 100, 30, "INPUT" ) ;
mountComponent( textFieldD, windowID ) ;
// ( 120, 10 ) の位置に200×200サイズのテキストエリアを配置
int textAreaID = newTextArea( 120, 10, 200, 200, "INPUT" ) ;
mountComponent( textAreaID, windowID ) ;
// ( 10, 110 ) の位置に100×20サイズのセレクトフィールドを配置
string text[ 3 ] ;
text[ 0 ] = "TYPE-A";
text[ 1 ] = "TYPE-B";
text[ 2 ] = "TYPE-C";
int selectFieldID = newSelectField( 10, 110, 100, 20, text ) ;
mountComponent( selectFieldID, windowID ) ;
// ( 10, 140 ) の位置に100×20サイズのチェックボックスを作成
int checkBoxID = newCheckBox( 10, 140, 100, 20, "TURBO", true ) ;
mountComponent( checkBoxID, windowID ) ;
// ( 10, 170 ) の位置に100×20サイズのテキストラベルを配置
int textLabelID = newTextLabel( 10, 170, 100, 20, "Hello GUI ! " ) ;
mountComponent( textLabelID, windowID ) ;
// 「Test.png」という名前のPNG形式画像ファイルを読み込み
int graphicsID = newGraphics( "Test.png" ) ;
// ( 10, 220 )の位置に310×200サイズの画像ラベルを配置
int imageLabelID = newImageLabel( 10, 220, 310, 200, graphicsID ) ;
mountComponent( imageLabelID, windowID ) ;
// =============================================
// GUIコンポーネントの配置 ここまで
// =============================================
// =============================================
// イベントハンドラ ここから
// =============================================
// ウィンドウを閉じた際に呼び出される
void onWindowClose( int id ){
alert( "プログラムを終了します。" ) ;
exit( );
}
// ボタンクリック時に呼び出される
void onButtonClick( int id, string text ){
alert( "ボタン " + text + " がクリックされました。" ) ;
}
// セレクトフィールド選択時に呼び出される
void onSelectFieldClick( int id, string text ){
alert( text + " が選択されました。" ) ;
}
// チェックボックス選択時に呼び出される
void onCheckBoxClick( int id, bool state ){
alert( "選択状態が " + state + " になりました。" ) ;
}
// マウスドラッグ時に呼び出される
void onMouseDrag( int id, int x, int y, int button ){
// ドラッグされたコンポーネントの判別
if( id == imageLabelID ){
// マウスボタンの判別
if( button == MOUSE_RIGHT ){
println( "右ドラッグ X=" + x + " Y=" + y ) ;
}else if( button == MOUSE_LEFT ){
println( "左ドラッグ X=" + x + " Y=" + y ) ;
}
}
}
// マウスクリック時に呼び出される
void onMouseClick( int id, int x, int y, int button, int count ){
// クリックされたコンポーネントの判別
if( id == imageLabelID ){
// マウスボタンの判別
if( button == MOUSE_RIGHT ){
println( "右クリック X=" + x + " Y=" + y ) ;
}else if( button == MOUSE_LEFT ){
println( "左クリック X=" + x + " Y=" + y ) ;
}
// ダブルクリックの判別
if( count == MOUSE_DOUBLE ){
alert( "ダブルクリックされました。" );
}
}
}
// キー入力時に呼び出される(キーラベル文字列取得)
void onKeyDown( int id, string key ){
println( "キー入力 =" + key ) ;
}
// キー入力時に呼び出される(キーコード取得)
void onKeyDown( int id, int keyCode ){
if( keyCode == KEY_SPACE ){
alert( "スペースキーが押されました。" ) ;
}
}
// =============================================
// イベントハンドラ ここまで
// =============================================
EventSample.vcssl
このプログラムを実行すると、ウィンドウが表示され、その上に様々なGUIコンポーネントが表示されます。 各GUIコンポーネントを操作すると、それに応じた処理が実行されます。