タイマーイベント
タイマーイベントの処理
最後に、タイマーによるイベント処理について説明します。WIN32APIでは、タイマーを使って一定の時間間隔でイベントを発生させることができます。
サンプルプログラム
では実際にタイマーイベントの処理を行うプログラムを見てみましょう。以下のプロジェクトを実行してみてください。
win32proj7-1:WinMain.cppダウンロード
// ************************************ // Ex 時間割り込み // ************************************ //必要なヘッダーファイルのインクルード #define STRICT #include <windows.h> #include <stdlib.h> #include <string.h> #include <tchar.h> // シンボル定義及びマクロ #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 // 経過時間カウントダウン int Sec = 10; // インスタンス(グローバル変数) HINSTANCE hInst; // ウィンドウプロシージャのコールバック関数 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { static TCHAR szWindowClass[] = _T("Sample07"); static TCHAR szTitle[] = _T("時間割り込みのサンプル"); WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("RegisterClassExの処理に失敗しました"), _T("Sample07"), NULL); return 1; } hInst = hInstance; // グローバル変数に値を入れる // The parameters to CreateWindow explained: // szWindowClass : アプリケーションの名前 // szTitle : タイトルバーに現れる文字列 // WS_OVERLAPPEDWINDOW : 生成するウィンドウのタイプ // CW_USEDEFAULT, CW_USEDEFAULT : 最初に置くポジション (x, y) // WINDOW_WIDTH, WINDOW_HEIGHT : 最初のサイズ (幅, 高さ) // NULL : このウィンドウの親ウィンドウのハンドル // NULL : メニューバー(このサンプルでは使用せず) // hInstance : WinMain関数の最初のパラメータ // NULL : WM_CREATE情報(このアプリケーションでは使用せず) HWND hWnd = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL ); // ウィンドウが生成できなかった場合 if (!hWnd) { MessageBox(NULL, _T("ウィンドウ生成に失敗しました!"), _T("Sample07"), NULL); return 1; } // ウィンドウの表示に必要なパラメータ: // hWnd : CreateWindowの戻り値 // nCmdShow : WinMainの引数の4番目 ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // メインのメッセージループ: MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } // ウィンドウプロシージャ(メッセージに対するコールバック関数) LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { //ペイント構造体 PAINTSTRUCT psMyPaint; //デバイスコンテキスト HDC hDC; // 文字列を入れるポインタ TCHAR szstr[100]; switch (message) { case WM_CREATE: //ウインドウが生成されたときに1度だけ通過 //時間割り込みの発生タイミングを設定 SetTimer(hWnd, 1, 1000, NULL); break; // エスケープキーの場合 case WM_KEYDOWN: switch (wParam) { case VK_ESCAPE: //終了メッセージを発生させる PostMessage(hWnd, WM_CLOSE, 0, 0); break; } break; case WM_PAINT: // 描画開始 hDC = BeginPaint(hWnd, &psMyPaint); // 経過時間の表示 _stprintf_s(szstr, _T("%d"), Sec); TextOut(hDC, 5, 5, szstr, _tcslen(szstr)); // 描画終了 EndPaint(hWnd, &psMyPaint); return 0; case WM_TIMER: // タイマー割り込み処理 Sec -= 1; if (Sec < 0){ Sec = 10; } InvalidateRect(hWnd, NULL, TRUE); break; case WM_DESTROY: //タイマーの削除 KillTimer(hWnd, 1); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; }
プログラムを起動すると、画面左上に「10」という文字が出現します。(図7-1.)
図7-1.タイマーイベントの処理①(初期画面)
この数値は、1秒ごとに、「9」、「8」…と、減少していきます。(図7-2./7-3.)
図7-1.タイマーイベントの処理②
図7-1.タイマーイベントの処理③
そして、最後に「0」となると、再び「10」に戻り、再び0に向かってカウントダウンを再開します。プログラムはESCキーか、右上の×ボタンを押すと、再開します。
プログラムの仕組み
タイマー関連
このプログラムには、タイマー関連の関数が必要です。タイマーに関する関数は、タイマーの設定を行うSetTimer関数と、タイマーの停止処理を行うKillTimer関数が必要になります。仕様は、以下の通りになります。
SetTimer関数UINT_PTR SetTimer(
HWND hWnd, // ウィンドウのハンドル
UINT_PTR nIDEvent, // タイマの識別子
UINT uElapse, // タイムアウト値
TIMERPROC lpTimerFunc // タイマのプロシージャ
);
関数が成功すると、新しいタイマの識別子を表す整数が返ります。 タイムアウト値は、タイマーの周期で、単にはミリ秒(1000分の1秒)になります。_PTRnIDEventは、タイマーの識別子です。タイマーは、複数設定できるため、この識別子の値で区別します。
KillTimer関数BOOL KillTimer(
HWND hWnd, // ウィンドウのハンドル
UINT_PTR uIDEvent // タイマの識別子
);
SetTimerで生成したタイマーを破棄します。破棄するタイマーは、SetTimerでセットしたものと同じものを与えることになります。生成したタイマーは、必ずこの関数で破棄する必要があります。
WM_CREATE,WM_TIMER
また、このプログラムでは、今まで出てこなかった新しいイベントが二つ出てきています。それぞれを解説します。
まず、119行目に出てくる、WM_CREATEイベントですが、これは、ウィンドウ生成時に、一度だけ呼び出されるイベントです。また、WM_TIMERは、タイマーイベントを意味あします。
処理の流れ
以上を踏まえ、このプログラムの処理の流れを説明しましょう。
プログラムが起動すると、WM_CREATEイベントで、121行目のSetTimerイベントが実行されます。これにより、識別子1で、1秒(=1000ミリ秒)のタイマーを発生させます。
すると、1秒ごとに、WM_TIMERイベントの記述されている、144行目から155目の処理が実行されます。ここで、タイマーの時間を表す関数Secの値が1つ減らされます。その際、0未満になれば、再び値を10に戻します。時間が更新されると、再描画の要求を行います。
133行目から144行目では、WM_PAINTによる描画処理が行われます。ここで、TextOut関数を用いて、Secを描画しています。これにより、1秒ごとの時間のカウントダウンが画面に表示されます。