第10章 タイマーを使ったアプリケーション


さて、今回はタイマーを使ってもう少しましな プログラムを作ります。 現在時刻を刻々と表示するようなプログラムを 作ってみましょう。 最も原始的な時計 と言ってもよいでしょう。

まず、現在時刻の取得ですがどうすればよいのでしょうか。 32ビット版SDKにはGetLocalTimeというAPI関数が あります。これが使えそうですね。 16ビット版にはないようです。

エー、じゃあ16ビットでやってる人はどうなるの?

心配いりません。従来のCの方法で取得すればよいですね。

C言語編第26章を参照して 下さい。まずは、16ビット版でもできる方法でやってみましょう。

<手順> 1.現在時間取得関数を作る   この中で、現在時刻を文字列にコピーする 2.1秒ごとに時間取得関数を呼び出す 3.コピーされた文字列を表示する

と、まあこんな感じでしょうか。 まずは、現在時刻を取得する関数を作りましょう。

int GetTimeStr(void) { char *str_org = "ただいま%2d年%d月%2d日の%2d時%2d分%2d秒です"; time_t long_time; struct tm *now_time; time(&long_time); now_time = localtime(&long_time); sprintf(time_str, str_org, now_time->tm_year, now_time->tm_mon + 1, now_time->tm_mday, now_time->tm_hour, now_time->tm_min, now_time->tm_sec); return 0; }

グローバル変数time_strを用意しておいて下さい。これに、現在時刻を コピーします。当然time.hとかstdio.hも必要ですね。

つぎに、ウィンドウプロシージャを書き直してみましょう。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { PAINTSTRUCT ps; HDC hdc; int id; switch (msg) { case WM_CREATE: if(SetTimer(hWnd, ID_MYTIMER, 1000, NULL) == 0) { MessageBox(hWnd, (LPCSTR)"タイマー失敗!", (LPCSTR)"失敗", MB_OK | MB_ICONEXCLAMATION); } break; case WM_TIMER: GetTimeStr(); InvalidateRect(hWnd, NULL, FALSE); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 10, 10, (LPCSTR)time_str, strlen(time_str)); EndPaint(hWnd, &ps); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0L); break; default: break; } break; case WM_CLOSE: id = MessageBox(hWnd, (LPCSTR)"終了してもよいですか", (LPCSTR)"終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if(KillTimer(hWnd, ID_MYTIMER) == TRUE) { MessageBox(hWnd, (LPCSTR)"タイマーを殺しました!", (LPCSTR)"タイマー削除の成功", MB_OK | MB_ICONEXCLAMATION); } DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; }

WM_CREATEメッセージが来たらタイマーを起動します。 WM_TIMERメッセージの発生は1秒に1回でよいでしょう。 この時、SetTimer関数の戻り値をチェックして万一 失敗したならその旨メッセージボックスで知らせるようにします。

WM_TIMERメッセージを捕まえたら、GetTimeStr関数(自作の関数)を呼びます。 この関数はグローバル変数time_strに現在の時刻をコピーします。 さて、これだけでは変数にコピーされるだけで描画は行われません。 そこで、InvalidateRect関数を呼び出します。 この関数のプロトタイプは、

BOOL InvalidateRect( HWND hWnd, //ウィンドウハンドル CONST RECT *lpRect, //長方形構造体のアドレス BOOL bErase //背景消去フラグ );

と、なっています。何をする関数かというとウィンドウの 更新リージョンに長方形を追加します。更新リージョンとは 再描画しなくてはならない部分のことです。

2番目の引数は、更新リージョンのRECT構造体のアドレスです。 RECT構造体については第5章を 参照して下さい。 クライアント領域全体を再描画するときはNULLにします。

3番目の引数は、更新リージョンの背景を消去するかどうかを決めます。 FALSEなら、背景はそのまま残ります。

要するに、更新リージョンを無理矢理追加してクライアント領域を 再描画させているわけです。こういうやり方はよく行われます。

WM_PAINTとWM_COMMANDの所は、説明不要ですね。

WM_CLOSEメッセージのところで、終了確認をして 終了ならタイマーを殺しています。うまく殺せたら?その旨 メッセージボックスでお知らせを出すようにしました。 念のため、全ソースを表示しておきます。 また、最初に表示されるウィンドウの大きさは、 CreateWindow関数のところでちょうどよいくらいに 調節してあります。

// timer.cpp #include <windows.h> #include <time.h> #include <stdio.h> #include "timer.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); BOOL InitApp(HINSTANCE, LPCSTR); BOOL InitInstance(HINSTANCE, LPCSTR, int); int GetTimeStr(void); char time_str[256]; int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; char szClassName[] = "timer"; //ウィンドウクラス if (!hPrevInst) { if (!InitApp(hCurInst, szClassName)) return FALSE; } if (!InitInstance(hCurInst, szClassName, nCmdShow)) { return FALSE; } while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 BOOLはTRUEかFALSEしか返さないの意味 BOOL InitApp(HINSTANCE hInst, LPCSTR szClassName) { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "TIMERMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; return (RegisterClass(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, LPCSTR szClassName, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "タイマー", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 350, //幅 80, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; } //ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { PAINTSTRUCT ps; HDC hdc; int id; switch (msg) { case WM_CREATE: if(SetTimer(hWnd, ID_MYTIMER, 1000, NULL) == 0) { MessageBox(hWnd, (LPCSTR)"タイマー失敗!", (LPCSTR)"失敗", MB_OK | MB_ICONEXCLAMATION); } break; case WM_TIMER: GetTimeStr(); InvalidateRect(hWnd, NULL, FALSE); break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 10, 10, (LPCSTR)time_str, strlen(time_str)); EndPaint(hWnd, &ps); break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0L); break; default: break; } break; case WM_CLOSE: id = MessageBox(hWnd, (LPCSTR)"終了してもよいですか", (LPCSTR)"終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { if(KillTimer(hWnd, ID_MYTIMER) == TRUE) { MessageBox(hWnd, (LPCSTR)"タイマーを殺しました!", (LPCSTR)"タイマー削除の成功", MB_OK | MB_ICONEXCLAMATION); } DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0L; } int GetTimeStr(void) { char *str_org = "ただいま%2d年%d月%2d日の%2d時%2d分%2d秒です"; time_t long_time; struct tm *now_time; time(&long_time); now_time = localtime(&long_time); sprintf(time_str, str_org, now_time->tm_year, now_time->tm_mon + 1, now_time->tm_mday, now_time->tm_hour, now_time->tm_min, now_time->tm_sec); return 0; }

ヘッダーファイルは、次の通りです。

// timer.h #define IDM_END 1000 #define ID_MYTIMER 32767

リソース・スクリプトは次の通りです。

// timer.rc #include <windows.h> #include "timer.h" ///////////////////////////////////////////////////////////////////////////// // // Menu // TIMERMENU MENU DISCARDABLE BEGIN MENUITEM "終了", IDM_END END

それでは、実行してみましょう。

左の図ではわかりませんが、実際は刻一刻と 時刻が更新されています。最も簡単な Windows版デジタル時計の完成です。 次回は、これを利用してもう少し気の利いた プログラムを書いてみましょう。乞うご期待!


[SDK Index] [総合Index] [Previous Chapter] [Next Chapter]

Update Mar/30/1997 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。