実際に、ボタンを押したら描画する「カウンター」プログラムをつくってみましょう。 ボタンの追加方法は、もうわかりますよね。
void draw(HDC hdc, int counter){ HFONT hfont, hfontOld; char buf[260]; hfont=GetStockObject(OEM_FIXED_FONT);/*固定ピッチフォント*/ hfontOld=SelectObject(hdc, hfont); SetTextColor(hdc, RGB(rand()%256, rand()%256, rand()%256)); /*文字色*/ SetBkColor (hdc, RGB(rand()%256, rand()%256, rand()%256)); /*背景色*/ SetBkMode(hdc, OPAQUE); /*背景色を不透明にする*/ //SetBkMode(hdc, TRANSPARENT); /*背景色を透明にする*/ sprintf(buf, "%6d", counter); TextOut(hdc, 3, 3, buf, strlen(buf)); SelectObject(hdc, hfontOld); DeleteObject(hfont); } BOOL FAR PASCAL count(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){ /*中略*/ case WM_COMMAND: switch((WORD)wParam) { case IDCOUNT: counter++; hdc=GetDC(hDlg); draw(hdc, counter); ReleaseDC(hDlg, hdc); break; /*中略*/ case WM_PAINT: hdc = BeginPaint(hDlg, &ps); draw(hdc, counter); EndPaint(hDlg, &ps); break;
case WM_COMMAND: switch((WORD)wParam) { case IDCOUNT: counter++; InvalidateRect(hDlg, NULL, TRUE);/*WM_PAINTを自分自身に送る*/ break; /*中略*/ case WM_PAINT: hdc = BeginPaint(hDlg, &ps); hfont=GetStockObject(OEM_FIXED_FONT);/*固定ピッチフォント*/ hfontOld=SelectObject(hdc, hfont); SetTextColor(hdc, RGB(rand()%256, rand()%256, rand()%256)); /*文字色*/ SetBkColor (hdc, RGB(rand()%256, rand()%256, rand()%256)); /*背景色*/ SetBkMode(hdc, OPAQUE); /*背景色を不透明にする*/ //SetBkMode(hdc, TRANSPARENT); /*背景色を透明にする*/ sprintf(buf, "%6d", counter); TextOut(hdc, 3, 3, buf, strlen(buf)); SelectObject(hdc, hfontOld); DeleteObject(hfont); EndPaint(hDlg, &ps); break;「カウンター」の全ソース
case WM_PAINT: hdc = BeginPaint(hDlg, &ps); for (;;) {/*無限ループ、もしくはそれに近い、長時間かかるループ*/ /*実際の描画処理*/ } EndPaint(hDlg, &ps); break;こういうことをすると、メッセージ処理が止まってしまいます。つまり、 そのアプリは、ユーザーが操作できなくなるということです。 Windowsには、「0.1秒ルール」というのがあります。これは、どんな メッセージも、原則として0.1秒以内に処理ルーチンからリターンしなければ ならないというものです。 こういう場合、タイマメッセージなど、一定のタイミングでやってくる メッセージを利用します。タイマメッセージは、SetTimer()で設定すると、WM_TIMERメッセージを送ってきます。 KillTimer()で解除します。
では作ってみましょう。こういう例題として「時計」はちょっとありきたりですが……。
「時計」の全ソース
なお、利用するメッセージは定期的にやってくるメッセージなら何でも良いので、 タイマメッセージを使ったのはあくまで例です。マルチメディア系のプログラムなら MM_WOM_DONE とか MM_MCINOTIFY とかを定期的に送ってくるようにプログラミングできますので、 そちらを使うほうが自然です。
「0.1秒ルール」には、例外が一点あります。メッセージボックスや、他のモーダル ダイアログボックスを出す場合は、ユーザはそちらを操作できます。実際、 MessageBox APIやDialogBox APIは、そのダイアログをユーザが閉じない限り リターンしないので、そもそも「0.1秒ルール」を守ることは不可能です。
それ以外の状況で、どうしても「0.1秒ルール」をやぶらなければならないときは、 カーソルを砂時計にするなどして、操作できないことをユーザに知らせます。
それとは別に、デバッグ目的であれ何であれ、WM_PAINTメッセージの応答中に メッセージボックスやダイアログボックスを出すのは厳禁です。 これは「時間がかかるから」という理由ではなく、その新たなダイアログを 閉じたり移動したりするとき、もう一度WM_PAINTメッセージが発生する可能性が あるからです。そうするとさらにダイアログが開かれ、これを無限に繰り返すことに なってしまいます。
あと、これは余談ですが、CPUの速度は最近のギガヘルツのオーダーのものから i386sx 16MHzのような超低速なものまであります。「0.1秒ルール」は可能なかぎり 遅いマシンでも達成できるようにすべきです。
一つ上のページに戻る