実際に、ボタンを押したら描画する「カウンター」プログラムをつくってみましょう。 ボタンの追加方法は、もうわかりますよね。
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秒ルール」は可能なかぎり 遅いマシンでも達成できるようにすべきです。
一つ上のページに戻る