Ko-Window プログラマーズマニュアル 「クライアントデータの使い方」 ●イベントルーチンを共有する 画像ローダーなど、一度に同じウィンドウを複数開くプログラムの場合、プログラ ムコードを共有することができます。例えばザウルスの手書きメモ画像データを表示 する zauimg.win というプログラムを複数実行すると、実行しただけメモリを消費し ますが、zauimg.win に複数のデータファイルを与えると、与えた分だけウィンドウは 開くものの起動しているプロセスは1つです。 ・プログラムを複数起動する場合 ┌────────┐ zauimg.win 1 ─ Win1 ─> |zau01.ztg を表示| └────────┘ ┌────────┐ zauimg.win 2 ─ Win2 ─> |zau02.ztg を表示| └────────┘ ┌────────┐ zauimg.win 3 ─ Win3 ─> |zau03.ztg を表示| └────────┘ ・1つのプログラムで複数の同じウィンドウを開く場合 ┌────────┐ ┌─ Win1 ─> |zau01.ztg を表示| | └────────┘ | ┌────────┐ zauimg.win ─共有─ Win2 ─> |zau02.ztg を表示| | └────────┘ | ┌────────┐ └─ Win3 ─> |zau03.ztg を表示| └────────┘ この場合メモリ上に存在する zauimg.win は1つだけです。またプロセステーブルも 1つしか消費せず、極めて高効率になっています。 ●共有ウィンドウの開き方 まずこのプログラムを見て下さい。 ---------------------------------------------------------------------------- #include Exec( wp, info ) WindowID wp; EventInfo *info; { DrawBuf dbuf; switch( info->option ){ case EventOpen: WindowRedraw( wp ); return TRUE; case EventClose: WindowClose( wp ); WindowConnectionClose(); return TRUE; case EventRedraw: DrawSetClear( &dbuf, 1 ); WindowDraw( wp, &dbuf, 1 ); return TRUE; } return FALSE; } WindowMain() { WindowTitleOpen( 10, 10, 100, 100, NULL, "smpl", Push|Close, Exec ); WindowTitleOpen( 10, 10, 100, 100, NULL, "smpl", Push|Close, Exec ); } ---------------------------------------------------------------------------- 何も特殊なことはしていません。唯一、WindowMain() 内で同じイベント処理ルー チンを渡したウィンドウを2つ開いています。実行すると中に何も表示されていない 全く同じウィンドウを2つ開きます。この時、イベント処理ルーチンの共有が行われ ています。 ただしこの場合同じイベントルーチンを使っているので開かれるウィンドウも全く同 じものになってしまいます。ウィンドウごとにそれぞれ異なったデータを管理するた めにクライアントデータ、というものを使います。 ●クライアントデータ データの設定 void WindowSetClientData( WindowID, int data, void *pointer ) データの参照 int WindowGetClientData( WindowID ) void *WindowGetClientPointer( WindowID ) 1つのウィンドウに対して設定しておけるデータは、上記のように int と void* の 2つです。8byte までのデータであれば、この2つの領域をそのまま使用することが できます。それより大きなデータを与える場合は、動的にデータ領域を malloc で確 保し、そのアドレスを ClientData として設定します。 ---------------------------------------------------------------------------- #include Exec( wp, info ) WindowID wp; EventInfo *info; { DrawBuf dbuf[2]; char *string= WindowGetClientPointer( wp ); switch( info->option ){ case EventOpen: return TRUE; case EventClose: WindowClose( wp ); WindowConnectionClose(); return TRUE; case EventRedraw: DrawSetClear( dbuf, 1 ); DrawSetSymbol( dbuf+1, 0, 0, string, AttrDefault, 12 ); WindowDraw( wp, dbuf, 2 ); return TRUE; } return FALSE; } WindowMain() { WindowID wp; wp= WindowTitleOpen( 10, 10, 200, 20, NULL, "smpl", Push|Close, Exec ); WindowSetClientData( wp, 0, "その1" ); WindowRedraw( wp ); wp= WindowTitleOpen( 10, 10, 200, 20, NULL, "smpl", Push|Close, Exec ); WindowSetClientData( wp, 0, "その2" ); WindowRedraw( wp ); } ---------------------------------------------------------------------------- この例は、先程のサンプルを拡張し、1つのイベント処理ルーチンで異なる文字列を 表示させているものです。EventOpen で WindowRedraw() せず、WindowTitleOpen() が戻って来てから WindowRedraw() による初期化表示を行わせています。これは、表 示する文字列をクライアントデータとして設定する前に EventRedraw されてしまう のを防ぐためです。 なお、ここまでのサンプルでは EventClose 内で WindowConnectionClose() を実行 しているために、どちらかのウィンドウを閉じればプログラムがすべて終了していま す。これを防ぐには、グローバル変数で現在開かれているウィンドウの数を保持して おき、最後のウィンドウが閉じられたら WindowConnectionClose() を実行する、等の 工夫が必要になります。 次のサンプルプログラムでこれらを含めて処理していますので参考にして下さい。 ---------------------------------------------------------------------------- #include int Count= 0; Exec( wp, info ) WindowID wp; EventInfo *info; { DrawBuf dbuf[2]; int num= WindowGetClientData( wp ); char buf[30]; switch( info->option ){ case EventOpen: return TRUE; case EventClose: WindowClose( wp ); if( !--Count ) WindowConnectionClose(); return TRUE; case EventRedraw: sprintf( buf, "%d", num ); DrawSetClear( dbuf, 1 ); DrawSetSymbol( dbuf+1, 0, 0, buf, AttrDefault, 16 ); WindowDraw( wp, dbuf, 2 ); return TRUE; case EventMouseSwitch: if( info->LeftON ){ New(); return TRUE; } } return FALSE; } New() { WindowID wp; wp= WindowTitleOpen( 10, 10, 200, 50, NULL, "smpl", Push|Close, Exec ); WindowSetClientData( wp, rand(), 0 ); WindowRedraw( wp ); Count++; } WindowMain() { New(); } ---------------------------------------------------------------------------- このプログラムは、ウィンドウ内に乱数値を表示します。ウィンドウ内を左クリッ クするたびにウィンドウをどんどん開いていきます。すべてのウィンドウは1つのイ ベント処理ルーチンで駆動されています。全部のウィンドウを閉じた段階でプログラ ムは終了します。 1994/9/19 小笠原博之 oga@dgw.yz.yamagata-u.ac.jp DenDenNET: DEN0006 COR.