イベント盛りだくさん!
[Japanese Pocket C User's Page]-[Tips!]
GUIアプリケーションを作るときに避けて通れないのが、
イベントの制御です。PCFormを使っていれば、VBのような感覚で利用出来ますが、
やはり、基本的な考え方は押さえておいた方がいいでしょう。
1.イベント制御の流れ
GUIを使ったプログラムでは、ボタンを押したとか、
クリックをしたなどのイベントに基づき処理が実行されます。
この流れをPocketCでプログラムにする場合、
大まかな流れは次の通りです。
1)関数sleepを使い、割り込みを待つ
2)関数eventを使い、発生したイベントを分類
3)さまざまな関数を使い、イベントの詳細を調べる。
4)イベントの内容に基づき、処理を実行する。
PCFormでは、1)〜3)までは作ってくれますが、4)の部分は、
各自がコーディングすることになります。
そのため、PC Fromを使っている人は、それぞれのイベントにおいて、
どのような詳細情報を取れるのかという観点で読んでください。
2.イベントの種類
関数eventにて取得出来るイベントは次の通りです。
ID | 名称 | 説明 | 詳細調査方法 |
0 | PM_NONE | なにも発生しなかった | |
1 | PM_CHAR | 文字が入力されたとき | key:入力された文字 |
2 | PM_MOUSEMOVE | スタイラスが移動 | penx,peny:座標 |
3 | PM_MEMORYSHORT | メモリが少なくなったとき | |
4 | PM_BUTTONDOWN | 画面がタップされた | penx,peny:座標 |
5 | PM_BUTTONUP | スタイラスが画面から離れた | penx,peny:座標 |
6 | PM_DBCLICK | ダブルクリック | |
7 | PM_PAINT | 画面が再描画されたとき | |
8 | PM_COMMAND | GUI コントロールにて、 イベントが発生 |
guiid:イベント発生オブジェクト menu:イベントが発生したメニューID getnotify:メッセージ |
9 | PM_KEYDOWN | キーが押された | |
10 | PM_KEYUP | キーが放された | waitp:キーが話されるのを待つ getc:キーが放されるまで待ち、キーを返す。 |
11 | PM_TIMER | タイマーイベントが発生 | settimer:タイマーイベントを設定 timerid:発生したタイマーイベント killtimer:タイマーイベントを削除 |
12 | PM_COMMEVENT | シリアル通信が発生したとき | 詳しくは、シリアル関連のヘルプを |
・ID・・・関数eventの戻値
・名称・・・pcheader.hでの定義名
3.さまざまな動作が発生したときの動き
イベントが発生する流れをいくつかの簡単な例で説明します。
1)ボタンが押されたとき
順番 | ID | イベント | 説明 |
1 | 9 | PM_KEYDOWN | 「SHIFT」が押された(keyで確認) |
2 | 9 | PM_KEYDOWN | 「a」が押された(keyで確認) |
3 | 1 | PM_CHAR | 文字「A」が確定(charで確認) |
4 | 10 | PM_KEYUP | 「a」が放された(keyで確認) |
5 | 10 | PM_KEYUP | 「SHIFT」が放された(keyで確認) |
実際に入力された文字により、処理を分けるときに、
「A」や[B」といった目にみえて分かる文字ならいいですが、
タブやCTRLなどの場合は、判断に迷います。
こういった場合に対応するためのヘッダーファイルが、
CE Factoryさんのところで紹介されています。
VK_Define.hというファイルがそうです。
この中で定義されているコードを利用すれば、何が押されたかが分かります。
2)スタイラスで移動
順番 | ID | イベント | 説明 |
1 | 4 | PM_BUTTONDOWN | スタイラスで画面を触った |
2 | 2 | PM_MOUSEMOVE | スタイラスを移動 |
3 | 5 | PM_BUTTONUP | スライスを画面から放した |
スタイラスの移動については、関数penx,penyにて座標を確認することができます。
3)タイマーイベント
順番 | ID | イベント | 説明 |
1 | settimerで、タイマーイベントを生成 | ||
2 | 11 | PM_TIMER | タイマーイベントが発生。 timeridで、発生したタイマーイベントを知る |
3 | killtimerでタイマーイベントを削除 |
特定の時間が過ぎたら、処理を実行するタイマーイベントは、
あらかじめ関数settimerで定義を行う必要があります。
killtimerを実行しないと、時間が過ぎるたびに、イベントが発生する。
4.イベントを強制的に起動する
イベントを強制的に発生させる方法がいくつかあります。
関数名 | 発生するイベント | 説明 |
keyevent | PM_KEYDOWN,PM_KEYUP | 使い方がよく分かりませんでした |
postevent | ユーザ定義イベント | ユーザが設定したイベントIDを発生させる。 システム保有のIDと同じ物を送らないこと。 |
settimer | PM_TIMER | タイマーイベントを設定する。 |
この中でよく使いそうなのは、settimerですね。
5.サンプルプログラム
で、今回もサンプルプログラムです。
このサンプルプログラムでは、発生したイベントの情報が画面に表示します。
(プログラム名 event_chk.pc)
#include "/pocketc/pcheader.h" #include "/pocketc/VK_Define.h" #define CTL_EDIT 1001 #define CTL_BUTTON 1002 #define TIMER1 1003 #define TIMER2 1004 int r_count; //表示ルーチンの行カウント int t_count; //タイマーイベントカウント用 // ===== キーコード表示 string showkey(char ch_in) { string ans; ans=ch_in; switch(ch_in) { case VK_TAB: { ans="[TAB]"; break; } case VK_SHIFT: { ans="[SHIFT]"; break; } case VK_SPACE: { ans="[SPACE]"; break; } } return ans; } // ===== 表示ルーチン ===== int writestr(string str_txt) { string str_add; r_count++; str_add=editget(CTL_EDIT) ; if (r_count==8) { str_add=""; r_count=0; } str_add=str_add+ "@"+ str_txt+"\r\n"; editset(CTL_EDIT,str_add ); } // ===== TIMER1 ===== int ev_timer1() { MessageBox((string)t_count,"Timer1",1,1); t_count++; if (t_count==3) { MessageBox("Kill Timer1","Timer1",1,1); killtimer(TIMER1); } } // ===== TIMER2 ===== int ev_timer2() { MessageBox("after 5 minutes.exit","Timer2",1,1); quit(); } main() { int ev; int flg_change; int g_id; int msg; int t_event; // ==== 初期化 ===== r_count=0; t_count=0; // ===== Timerイベント ===== settimer(TIMER1,15000); settimer(TIMER2,300000); //===== 画面作成 createctrl("EDIT","",WS_VISIBLE | WS_BORDER | ES_MULTILINE ,0,20,60,200,140,CTL_EDIT); // EDIT作成 createctrl("BUTTON","event!",WS_VISIBLE | WS_BORDER,0,20,40,200,20,CTL_BUTTON); // BUTTON作成 while(1) { sleep(0); ev=event(0); switch(ev) { case PM_CHAR: { writestr(" char "+showkey(key())); break; } case PM_MOUSEMOVE: { writestr(" move position :"+penx()+","+peny()); break; } case PM_BUTTONDOWN: { writestr(" down position :"+penx()+","+peny()); break; } case PM_BUTTONUP: { writestr(" up position :"+penx()+","+peny()); break; } case PM_DBCLICK: { writestr(" double click position :"+penx()+","+peny()); break; } case PM_PAINT: { g_id=guiid(); if (g_id !=0) { writestr("paint /gui id " + g_id ); } break; } case PM_COMMAND: { g_id=guiid(); msg=getnotify(); writestr("command /gui id " + g_id + " / message " + msg ); break; } case PM_KEYUP: { writestr(" key up "+showkey(key())); break; } case PM_KEYDOWN: { writestr(" key down "+showkey(key())); break; } case PM_TIMER: { t_event=timerid(); writestr("Timer Event "+t_event); switch (t_event) { case TIMER1: { ev_timer1(); break; } case TIMER2: { ev_timer2(); break; } } break; } } } }
6.解説
ちょっと長く見えますので、簡単に解説おば。
全体の流れは、
・関数を定義
・画面等の初期化
・whileによるイベントループ内で処理
です。それぞれはそれほど難しくはないと思うので、
関数だけ説明しときます。
1)関数:showkey
VK_Define.hを利用して、TAB,SHIFT,SPACEキーが押された時に表示できるようにする。
2)関数:writestr
発生したイベント表示。
3)関数:timer1,timer2
タイマーイベントにより、呼び出される。
7.おさらい
今回は次のことを学びました。
1)eventループについて
2)各イベント発生時の詳細情報の取得方法
3)簡単なイベントの流れの例
ちょっと考え方がむずかしくなってきましたが、
分かるところからしっかりと押さえて行きましょう。