EzGraph : Eazy Graphic Library

概要 チュートリアル 機能一覧 関数名一覧 機能別一覧 色見本 MMLの書き方

イベントドリブンとは?

一般的に、テキストベースのプログラム (CUI; Character User Interface) では、 以下のようにscanf()関数やgets()関数を用いてキーボードからの入力を 受け付けていました。

#include <stdio.h>

int main()
  char name[128];

  printf("What is your name?\n");
  scanf("%s", name);
  printf("You are %s.\n", name);
  return 0;
}

しかし、グラフィカルなプログラム (GUI; Graphical User Interface) では、 取り扱う入力がキーボードだけではなく、マウスの入力も同時に扱う必要が あります。また、上記の例では、キーボード入力があるまでscanf()関数で 待ち続けますが、一般的に GUI プログラムでは、入力の有無に関わらず プログラムの進行を止めたくない場合が多々あります。

例えば、テトリスを作る場合、キーボード入力がなくても、 一定時間が経過したらブロックを落下させる必要があります。 そのため、GUIプログラムでは、一般的にイベントドリブンという考え方に 基づいてプログラムを設計します。

マウスイベント

イベントドリブンとは、scanf()関数やgets()関数のように入力が あるまで待ち続けるのではなく、入力(イベント)が発生したら あらかじめ決めておいた関数を呼び出してもらうというプログラミング スタイルです。

以下にEzGraphを用いた簡単な例を示します。

#include <stdio.h>
#include <EzGraph.h>

/* マウスが押された時に呼び出してもらう関数 */
void MouseEvent(int x, int y, unsigned int n){
  printf("座標 (%d, %d) で第 %u ボタンがクリックされました\n", x, y, n);
}

int main(){
  /* マウスが押された時に呼び出してもらう関数を登録する */
  EzSetMouseHandler(MouseEvent);

  /* イベントが発生するまで待ち続ける */
  EzEventLoop();
}

上記プログラムをコンパイルし、実行すると真っ黒いウィンドウが出てきますので、 ウィンドウ内の適当な場所をクリックしてみてください。 するとプログラムを起動した端末に、クリックした座標と押されたボタン番号が 表示され、クリックした場所に円が描かれたはずです。 円の大きさは、押したボタンにより変化します。

キーボードイベント

今度は上記プログラムにキーボードイベントを追加してみましょう。
#include <stdio.h>
#include <EzGraph.h>

/* マウスが押された時に呼び出してもらう関数 */
void MouseEvent(int x, int y, unsigned int n){
  printf("座標 (%d, %d) で第 %u ボタンがクリックされました\n", x, y, n);
  EzDrawCircle(x, y, 10*n);
}

/* キーが押された時に呼び出してもらう関数 */
void KeyEvent(int key){
  printf("キー (%c) が押されました\n", key);
}

int main(){
  /* マウスが押された時に呼び出してもらう関数を登録する */
  EzSetMouseHandler(MouseEvent);

  /* キーが押された時に呼び出してもらう関数を登録する */
  EzSetKeyHandler(KeyEvent);

  /* イベントが発生するまで待ち続ける */
  EzEventLoop();
}

タイマーイベント

今度は上記プログラムにタイマーイベントを追加してみましょう。 タイマーイベントとは、一定時間が経過した時に発生する周期イベントです。 キー入力がなかった場合のタイムアウトやユーザーの入力とは無関係に 実行したい処理がある場合に利用します。 ここでは、0.1秒毎にウィンドウの中心の円が大きくなる機能を付けてみましょう。

#include <stdio.h>
#include <time.h>
#include <EzGraph.h>

int circle_r = 0;

/* マウスが押された時に呼び出してもらう関数 */
void MouseEvent(int x, int y, unsigned int n){
  printf("座標 (%d, %d) で第 %u ボタンがクリックされました\n", x, y, n);
  /*TimerEvent()関数により描写色を変更されるため再設定 */
  EzSetColorByName("White");
  EzDrawCircle(x, y, 10*n);
}

/* キーが押された時に呼び出してもらう関数 */
void KeyEvent(int key){
  printf("キー (%c) が押されました\n", key);
}

/* 0.1秒毎に呼び出してもらう関数 */
void TimerEvent(void){
  circle_r++;
  if(circle_r > 200){
    /* 円の半径が200になったら、タイマーを停止 */
    EzSetTimerHandler(NULL, 0);
  }
  EzSetColorByName("Cyan");
  EzDrawCircle(300, 300, circle_r);
}

int main(){
  /* マウスが押された時に呼び出してもらう関数を登録する */
  EzSetMouseHandler(MouseEvent);

  /* キーが押された時に呼び出してもらう関数を登録する */
  EzSetKeyHandler(KeyEvent);

  /* 0.1秒毎に呼び出してもらう関数を登録する */
  EzSetTimerHandler(TimerEvent, 100);

  /* イベントが発生するまで待ち続ける */
  EzEventLoop();
}

このプログラムでは、0.1秒経過する毎に、EzEventLoop()関数の中からTimerEvent()関数が呼び出されます。円が大きくなっている間に キーボードやマウスを操作し、入力が受け付けられていることを確認して みて下さい。

タイマーイベントは周期イベントなので、一定時間が経過する度に 呼び出されます。もし、途中でタイマーイベントを停止したい場合は、 上のサンプルプログラムの様にイベントハンドラとしてNULLを登録 して下さい。

チュートリアルの目次

  1. 初歩的な使い方
  2. 複雑な図形描写
  3. イベントドリブン
  4. ダブルバッファリング
  5. 画像ファイルの表示
  6. リアルタイムなキー入力
  7. ネットワーク機能

Takahiro SASAKI
E-mail: sasaki at arch.info.mie-u.ac.jp