今回は、時計にタイマーを付けます。アラームと似ていますが、アラームは
あらかじめセットした時刻にwave音が鳴ります。これに対してアラームは
今から何分後、というようにセットします。カップラーメンなどを作る時に
便利です。
右クリックで出てくるメニューに「タイマー」「タイマーセット」が加わりました。
「タイマーセット」を選択すると左のようなダイアログボックスが出てきます。
これに希望の時間をセットします。左の例では1時間5秒(半端な時間です)にセットしてあります。
セットできる最大値は23時間59分59秒です。
「スタート」ボタンを押すと・・・
今まで、日付が表示されていた部分に残り時間が、刻々と表示されます。
0秒になるとWave音が鳴ります。途中でやめたい時は、右クリックして 「タイマー設定」ダイアログを出し、「ストップ」ボタンを押します。 (今回のプログラムでは一度ストップすると、その時間から再スタートすることはできません。)
では、プログラムを見てみましょう。
// clock07.rcの一部
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
MYMENU MENU
BEGIN
POPUP "ダミーです"
BEGIN
POPUP "ファイル(&F)"
BEGIN
MENUITEM "終了(&X)...", IDM_END
END
POPUP "オプション(&O)"
BEGIN
MENUITEM "背景色(&B)...", IDM_BACKGROUND
MENUITEM "文字色(&T)...", IDM_TEXT
MENUITEM "文字盤の色(&P)...", IDM_PLATE
MENUITEM "長針の色(&L)...", IDM_LONG
MENUITEM "短針の色(&S)...", IDM_SHORT
MENUITEM "秒針の色(&O)...", IDM_SECOND
END
POPUP "アラーム(&L)"
BEGIN
MENUITEM "時刻設定(&S)...", IDM_ALARMSET
END
POPUP "タイマー(&T)"
BEGIN
MENUITEM "タイマーセット(&T)...", IDM_TIMER
END
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
CAT BITMAP "bitmap1.bmp"
MASK BITMAP "bmp00001.bmp"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
MYALARM DIALOGEX 0, 0, 115, 73
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "アラーム設定"
FONT 10, "MS ゴシック", 400, 0, 0x80
BEGIN
DEFPUSHBUTTON "OK",IDOK,7,52,50,14
PUSHBUTTON "キャンセル",IDCANCEL,58,52,50,14
CONTROL "アラームをセットする",IDC_CHECK1,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,7,7,101,15
CONTROL "",IDC_DATETIMEPICKER1,"SysDateTimePick32",
DTS_RIGHTALIGN | DTS_UPDOWN | WS_TABSTOP,30,25,54,17
END
MYTIMER DIALOGEX 0, 0, 123, 54
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "タイマー設定"
FONT 10, "MS ゴシック", 400, 0, 0x80
BEGIN
DEFPUSHBUTTON "スタート",IDOK,7,33,50,14
PUSHBUTTON "ストップ",IDCANCEL,65,33,50,14
CONTROL "",IDC_DATETIMEPICKER1,"SysDateTimePick32",
DTS_RIGHTALIGN | DTS_UPDOWN | WS_TABSTOP,35,7,53,19
END
/////////////////////////////////////////////////////////////////////////////
//
// WAVE
//
BELL WAVE "ringin.wav"
リソース・スクリプトです。メニュー項目が追加になっています。
タイマーセットのダイアログボックスが追加となっています。
// clock07.cpp
#define hParentKey HKEY_CURRENT_USER
#define lpszSubKey "Software\\Kumei\\Clock"
#define PAI 3.14159
#define CLOCK_WIDTH 250 //時計全体のウィンドウ幅
#define CLOCK_HEIGHT 60 //高さ
#define MYTIMER 1 //タイマーID
#include <windows.h>
#include <windowsx.h>
#include <math.h>
#include <commctrl.h>
#include <Mmsystem.h>
#include "resource.h"
typedef struct MYDATA {
COLORREF cr_bg; //背景色
COLORREF cr_txt; //文字色
COLORREF cr_plate; //文字盤の色
COLORREF cr_short; //短針の色
COLORREF cr_long; //長針の色
COLORREF cr_second; //秒針の色
int x;
int y;
char szAlarmSet[8];
char szAlarmTime[16];
char szTimerTime[16];
} INIDATA;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK MyAlarmProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK MyTimerProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
HFONT SetMyFont(LPCTSTR, int);
BOOL GetMyColor(HWND, COLORREF *, COLORREF);
void GetInitialSettings(INIDATA *);
BOOL GetDataDWORD(char *, DWORD *);
BOOL GetDataString(char *, char *);
BOOL SetInitialSettings(INIDATA);
BOOL SetDataDWORD(char *, DWORD);
BOOL SetDataString(char *, char *);
BOOL ShowClock(HDC, char *, INIDATA);
BOOL GetHMS(char *, int *, int *, int *);
BOOL ShowBitmap(HDC, INIDATA);
BOOL MyTimerShow(HDC, int, int, INIDATA, DWORD);
BOOL SetHMS(char *, DWORD);
char szClassName[] = "clock07"; //ウィンドウクラス
char szAppName[] = "猫クロック"; //アプリケーション名
HINSTANCE hInst;
MYDATA構造体にszTimerTimeメンバが増えました。一度セットした
タイマー時間は、次回タイマーセットダイアログが出てきた時に反映されます。タイマーセットダイアログのプロシージャ、MyTimerShow関数、SetHMS関数が増えました。
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,
LPSTR lpsCmdLine, int nCmdShow)
{
MSG msg;
BOOL bRet;
hInst = hCurInst;
if (!InitApp(hCurInst))
return FALSE;
if (!InitInstance(hCurInst, nCmdShow))
return FALSE;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1) {
break;
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
//ウィンドウ・クラスの登録
ATOM InitApp(HINSTANCE hInst)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc; //プロシージャ名
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;//インスタンス
wc.hIcon = (HICON)LoadImage(NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hCursor = (HCURSOR)LoadImage(NULL,
MAKEINTRESOURCE(IDC_ARROW),
IMAGE_CURSOR,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL; //メニュー名
wc.lpszClassName = (LPCSTR)szClassName;
wc.hIconSm = (HICON)LoadImage(NULL,
MAKEINTRESOURCE(IDI_APPLICATION),
IMAGE_ICON,
0,
0,
LR_DEFAULTSIZE | LR_SHARED);
return (RegisterClassEx(&wc));
}
//ウィンドウの生成
BOOL InitInstance(HINSTANCE hInst, int nCmdShow)
{
HWND hWnd;
hWnd = CreateWindowEx(WS_EX_TOPMOST, //拡張ウィンドウスタイル
szClassName,
"猫でもわかるWindowsプログラミング", //タイトルバーにこの名前が表示されます
WS_POPUP, //ウィンドウの種類
0, //X座標
0, //Y座標
CLOCK_WIDTH, //幅
CLOCK_HEIGHT, //高さ
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)
{
int id, x, y;
SYSTEMTIME st;
PAINTSTRUCT ps;
HDC hdc;
HFONT hFont;
SIZE s;
HRGN hRgn, hRgn1, hRgn2, hRound1Rgn, hRound2Rgn, hRectRgn;
HBRUSH hBrush;
HMENU hMenu, hSubMenu;
POINT pt;
COLORREF cr;
static INIDATA inidata;
RECT rc;
char szYobi[8];
static char szBuf[64], szBuf2[64]; //時刻表示用
INITCOMMONCONTROLSEX ic;
static BOOL bTimer; //タイマ表示かどうか
static DWORD dwStartMs;
MMTIME mm;
switch (msg) {
case WM_CREATE:
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
ic.dwICC = ICC_DATE_CLASSES;
InitCommonControlsEx(&ic);
GetInitialSettings(&inidata);
MoveWindow(hWnd,
inidata.x,
inidata.y,
CLOCK_WIDTH,
CLOCK_HEIGHT,
TRUE);
SetTimer(hWnd, MYTIMER, 1000, NULL);
hRgn = CreateRectRgn(0, 0, 1, 1);
hRgn1 = CreateRectRgn(0, 0, 1, 1);
hRgn2 = CreateRectRgn(0, 0,1, 1);
hRound1Rgn = CreateEllipticRgn(0, 0, CLOCK_HEIGHT, CLOCK_HEIGHT);
hRectRgn = CreateRectRgn(CLOCK_HEIGHT / 2,
0,
CLOCK_WIDTH - CLOCK_HEIGHT / 2,
CLOCK_HEIGHT);
CombineRgn(hRgn1, hRound1Rgn, hRectRgn, RGN_OR);
hRound2Rgn = CreateEllipticRgn(CLOCK_WIDTH - CLOCK_HEIGHT,
0,
CLOCK_WIDTH,
CLOCK_HEIGHT);
CombineRgn(hRgn2, hRound2Rgn, hRectRgn, RGN_OR);
CombineRgn(hRgn, hRgn1, hRgn2, RGN_OR);
SetWindowRgn(hWnd, hRgn, TRUE);
DeleteObject(hRound1Rgn);
DeleteObject(hRound2Rgn);
DeleteObject(hRectRgn);
DeleteObject(hRgn1);
DeleteObject(hRgn2);
break;
case WM_RBUTTONDOWN:
pt.x = LOWORD(lp);
pt.y = HIWORD(lp);
hMenu = LoadMenu(hInst, "MYMENU");
hSubMenu = GetSubMenu(hMenu, 0);
ClientToScreen(hWnd, &pt);
TrackPopupMenu(hSubMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, NULL);
DestroyMenu(hMenu);
break;
case WM_LBUTTONDOWN:
PostMessage(hWnd, WM_NCLBUTTONDOWN, (WPARAM)HTCAPTION, lp);
break;
case WM_TIMER:
if (wp != MYTIMER)
return DefWindowProc(hWnd, msg, wp, lp);
GetLocalTime(&st);
wsprintf(szBuf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
switch (st.wDayOfWeek) {
case 0:
strcpy(szYobi, "Sun");
break;
case 1:
strcpy(szYobi, "Mon");
break;
case 2:
strcpy(szYobi, "Tue");
break;
case 3:
strcpy(szYobi, "Wed");
break;
case 4:
strcpy(szYobi, "Thu");
break;
case 5:
strcpy(szYobi, "Fri");
break;
case 6:
strcpy(szYobi, "Sat");
break;
}
wsprintf(szBuf2, "%d/%02d/%02d(%s)", st.wYear, st.wMonth, st.wDay, szYobi);
if (strcmp(inidata.szAlarmSet, "Yes") == 0 && strcmp(szBuf, inidata.szAlarmTime) == 0) {
PlaySound("BELL", hInst, SND_RESOURCE | SND_ASYNC | SND_LOOP);
MessageBox(hWnd, "時間ですよ", szAppName, MB_OK);
PlaySound(NULL, hInst, SND_PURGE);
}
InvalidateRect(hWnd, NULL, TRUE);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
hBrush = CreateSolidBrush(inidata.cr_bg);
SelectObject(hdc, hBrush);
PatBlt(hdc, 0, 0, CLOCK_WIDTH, CLOCK_HEIGHT, PATCOPY);
ShowBitmap(hdc, inidata);
hFont = SetMyFont("MS ゴシック", 30);
SelectObject(hdc, hFont);
GetTextExtentPoint32(hdc, szBuf, (int)strlen(szBuf), &s);
x = (CLOCK_WIDTH - s.cx) / 2 + 4;
y = (CLOCK_HEIGHT - s.cy) / 2 + 10;
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, inidata.cr_txt);
TextOut(hdc, x, y, szBuf, (int)strlen(szBuf));
DeleteObject(hFont);
hFont = SetMyFont("MS ゴシック", 16);
SelectObject(hdc, hFont);
GetTextExtentPoint32(hdc, szBuf2, (int)strlen(szBuf2), &s);
x = (CLOCK_WIDTH - s.cx) / 2 + 4;
if (!bTimer) {
TextOut(hdc, x, 4, szBuf2, (int)strlen(szBuf2));
} else {
if (MyTimerShow(hdc, x, 4, inidata, dwStartMs)) {
bTimer = FALSE;
PlaySound("BELL", hInst, SND_RESOURCE | SND_ASYNC | SND_LOOP);
MessageBox(hWnd, "時間ですよ", szAppName, MB_OK);
PlaySound(NULL, hInst, SND_PURGE);
}
}
DeleteObject(hFont);
DeleteObject(hBrush);
ShowClock(hdc, szBuf, inidata);
EndPaint(hWnd, &ps);
break;
case WM_COMMAND:
switch (LOWORD(wp)) {
case IDM_END:
SendMessage(hWnd, WM_CLOSE, 0, 0);
break;
case IDM_BACKGROUND:
if (GetMyColor(hWnd, &cr, inidata.cr_bg)) {
inidata.cr_bg = cr;
}
break;
case IDM_TEXT:
if (GetMyColor(hWnd, &cr, inidata.cr_txt)) {
inidata.cr_txt = cr;
}
break;
case IDM_PLATE:
if (GetMyColor(hWnd, &cr, inidata.cr_plate)) {
inidata.cr_plate = cr;
}
break;
case IDM_SHORT:
if (GetMyColor(hWnd, &cr, inidata.cr_short)) {
inidata.cr_short = cr;
}
break;
case IDM_LONG:
if (GetMyColor(hWnd, &cr, inidata.cr_long)) {
inidata.cr_long = cr;
}
break;
case IDM_SECOND:
if (GetMyColor(hWnd, &cr, inidata.cr_second)) {
inidata.cr_second = cr;
}
break;
case IDM_ALARMSET:
DialogBoxParam(hInst, "MYALARM", hWnd, (DLGPROC)MyAlarmProc, (LPARAM)&inidata);
break;
case IDM_TIMER:
if (DialogBoxParam(hInst,
"MYTIMER",
hWnd,
(DLGPROC)MyTimerProc,
(LPARAM)&inidata) == IDOK) {
bTimer = TRUE;
memset(&mm, 0, sizeof(MMTIME));
mm.wType = TIME_MS;
timeGetSystemTime(&mm, sizeof(MMTIME));
dwStartMs = mm.u.ms;
} else {
bTimer = FALSE;
}
break;
}
break;
case WM_CLOSE:
id = MessageBox(hWnd,
"終了してもよろしいですか",
szAppName,
MB_YESNO | MB_ICONQUESTION);
if (id == IDYES) {
GetWindowRect(hWnd, &rc);
inidata.x = rc.left;
inidata.y = rc.top;
DestroyWindow(hWnd);
}
break;
case WM_DESTROY:
SetInitialSettings(inidata);
KillTimer(hWnd, MYTIMER);
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
メインウィンドウのプロシージャです。WM_TIMERメッセージが来た時、bTimerがTRUEの時(タイマー作動中の時) MyTimerShow関数を呼んでタイマーの残り時間を表示するようにしました。
また、MyTimerShow関数がTRUEを返した時(残り時間が0となった時)PlaySound関数で Wave音を鳴らします。この場合、タイマーはもう作動しなくてよいので、bTimerをFALSE にしておきます。
PlaySound関数については第342章に解説があります。
メニューからIDM_TIMERが選択された時は、DialogBoxParam関数でタイマーセット ダイアログを出します。
そして、このダイアログがIDOK(「スタート」ボタンが押された)を返したら タイマーをスタートさせないといけないので、bTimerをTRUEにします。
そして、timeGetSystemTime関数でこの時のシステム時間を取得します。 これは、Windowsが起動してからのミリセコンドです。これをstaticな変数dwStartMsに保存しておきます。
MMRESULT timeGetSystemTime( LPMMTIME pmmt, UINT cbmmt );システム時刻(Windowsが起動してからの経過時間)をミリセコンドで取得します。
pmmtには、MMTIME構造体のアドレスを指定します。
cbmmtには、MMTIME構造体のサイズ(バイト)を指定します。
この関数を使うにはmmsystem.hをインクルードし、プロジェクトにwinmm.libを参加 させる必要があります。
MMTIME構造体は次のように定義されています。
typedef struct mmtime_tag {
UINT wType;
union {
DWORD ms;
DWORD sample;
DWORD cb;
DWORD ticks;
struct {
BYTE hour;
BYTE min;
BYTE sec;
BYTE frame;
BYTE fps;
BYTE dummy;
BYTE pad[2]
} smpte;
struct {
DWORD songptrpos;
} midi;
} u;
} MMTIME;
時間フォーマットを指定します。次の中から1つを選びます。
| 値 | 意味 |
|---|---|
| TIME_BYTES | ファイルの先頭からの現在の位置のオフセット(バイト) |
| TIME_MIDI | MIDI時間 |
| TIME_MS | ミリセコンド |
| TIME_SAMPLES | WAVE形式オーディオサンプルの数 |
| TIME_SMPTE | SMPTE規格フォーマットの時間 |
| TIME_TICKS | MIDIストリーム内のtick数
msには、ミリセコンドが格納されます。(TIME_MSを指定した場合)
sampleには、先頭からのサンプル数が格納されます。(TIME_SAMPLES)
cbには、ファイルの先頭からのオフセットが格納されます。(TIME_BYTES)
ticksには、MIDIストリーム内のtick数が格納されます。(TIME_TICKS)
hourはSMPTE企画の時です。
minは分、secは秒、frameはフレーム番号、fpsは1秒あたりのフレーム数、 songptrposは、ソングポインタの位置です。
さて、システムタイムをミリセコンドで取得するだけならtimeGetTime関数 の方が簡単ですが、ここではあえてtimeGetSystemTime関数を使いました。 気にくわない人は書き換えてください。
DWORD timeGetTime(VOID);システム時間をミリセコンドで返します。
HFONT SetMyFont(LPCTSTR face, int h)
{
HFONT hFont;
hFont = CreateFont(h, //フォント高さ
0, //文字幅
0, //テキストの角度
0, //ベースラインとx軸との角度
FW_REGULAR, //フォントの重さ(太さ)
FALSE, //イタリック体
FALSE, //アンダーライン
FALSE, //打ち消し線
SHIFTJIS_CHARSET, //文字セット
OUT_DEFAULT_PRECIS, //出力精度
CLIP_DEFAULT_PRECIS,//クリッピング精度
PROOF_QUALITY, //出力品質
FIXED_PITCH | FF_MODERN,//ピッチとファミリー
face); //書体名
return hFont;
}
BOOL GetMyColor(HWND hWnd, COLORREF *lpcr, COLORREF org_cr)
{
CHOOSECOLOR cc;
static DWORD dwCustColors[16];
cc.lStructSize = sizeof(CHOOSECOLOR);
cc.hwndOwner = hWnd;
cc.lpCustColors = dwCustColors;
cc.rgbResult = org_cr;
cc.Flags = CC_RGBINIT;
if (ChooseColor(&cc)) {
*lpcr = cc.rgbResult;
return TRUE;
}
return FALSE;
}
これらの関数に変更はありません。
void GetInitialSettings(INIDATA *lpini)
{
DWORD dwData;
char szData[32];
if (GetDataDWORD("background-color", &dwData)) {
lpini->cr_bg = (COLORREF)dwData;
} else {
lpini->cr_bg = RGB(0, 255, 255);
}
if (GetDataDWORD("text-color", &dwData)) {
lpini->cr_txt = (COLORREF)dwData;
} else {
lpini->cr_txt = RGB(0, 0, 0);
}
if (GetDataDWORD("x", &dwData)) {
lpini->x = (int)dwData;
} else {
lpini->x = 0;
}
if (GetDataDWORD("y", &dwData)) {
lpini->y = (int)dwData;
} else {
lpini->y = 0;
}
if (GetDataDWORD("short-color", &dwData)) {
lpini->cr_short = (COLORREF)dwData;
} else {
lpini->cr_short = RGB(0, 0, 255);
}
if (GetDataDWORD("long-color", &dwData)) {
lpini->cr_long = (COLORREF)dwData;
} else {
lpini->cr_long = RGB(0, 0, 0);
}
if (GetDataDWORD("second-color", &dwData)) {
lpini->cr_second = (COLORREF)dwData;
} else {
lpini->cr_second = RGB(255, 0, 0);
}
if (GetDataDWORD("plate-color", &dwData)) {
lpini->cr_plate = (COLORREF)dwData;
} else {
lpini->cr_plate = RGB(0, 255, 255);
}
if (GetDataString("alarm-set", szData)) {
strcpy(lpini->szAlarmSet, szData);
} else {
strcpy(lpini->szAlarmSet, "No");
}
if (GetDataString("alarm-time", szData)) {
strcpy(lpini->szAlarmTime, szData);
} else {
strcpy(lpini->szAlarmTime, "00:00:00");
}
if (GetDataString("timer-time", szData)) {
strcpy(lpini->szTimerTime, szData);
} else {
strcpy(lpini->szTimerTime, "00:00:00");
}
return;
}
レジストリから値を読み出しINIDATA構造体にセットします。timer-timeエントリが増えています。読み込みに失敗した時は"00:00:00"に設定します。
BOOL GetDataDWORD(char *szName, DWORD *dwValue)
{
HKEY hKey;
DWORD dwPosition;
DWORD dwType = REG_DWORD;
DWORD dwByte = 32;
RegCreateKeyEx(hParentKey,
lpszSubKey,
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwPosition);
if (RegQueryValueEx(hKey,
szName,
NULL,
&dwType,
(BYTE *)dwValue,
&dwByte) != ERROR_SUCCESS) {
RegCloseKey(hKey);
return FALSE;
}
RegCloseKey(hKey);
return TRUE;
}
BOOL GetDataString(char *szName, char *szValue)
{
HKEY hKey;
DWORD dwPosition;
DWORD dwType = REG_SZ;
DWORD dwByte = 32;
RegCreateKeyEx(hParentKey,
lpszSubKey,
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwPosition);
if (RegQueryValueEx(hKey,
szName,
NULL,
&dwType,
(BYTE *)szValue,
&dwByte) != ERROR_SUCCESS) {
return FALSE;
}
RegCloseKey(hKey);
return TRUE;
}
これらの関数に変更はありません。
BOOL SetInitialSettings(INIDATA inidata)
{
SetDataDWORD("background-color", inidata.cr_bg);
SetDataDWORD("text-color", inidata.cr_txt);
SetDataDWORD("x", inidata.x);
SetDataDWORD("y", inidata.y);
SetDataDWORD("short-color", inidata.cr_short);
SetDataDWORD("long-color", inidata.cr_long);
SetDataDWORD("second-color", inidata.cr_second);
SetDataDWORD("plate-color", inidata.cr_plate);
SetDataString("alarm-set", inidata.szAlarmSet);
SetDataString("alarm-time", inidata.szAlarmTime);
SetDataString("timer-time", inidata.szTimerTime);
return TRUE;
}
INIDATA構造体の値をレジストリに書き込みます。timer-timeエントリへの
書き込みが増えています。
BOOL SetDataDWORD(char *szName, DWORD dwData)
{
HKEY hKey;
DWORD dwPosition;
RegCreateKeyEx(hParentKey,
lpszSubKey,
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwPosition);
RegSetValueEx(hKey,
szName,
0,
REG_DWORD,
(CONST BYTE *)&dwData,
sizeof(DWORD));
RegCloseKey(hKey);
return TRUE;
}
BOOL SetDataString(char *szName, char *szData)
{
HKEY hKey;
DWORD dwPosition;
LONG lResult;
RegCreateKeyEx(hParentKey,
lpszSubKey,
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hKey,
&dwPosition);
lResult = RegSetValueEx(hKey,
szName,
0,
REG_SZ,
(CONST BYTE *)szData,
lstrlen(szData));
RegCloseKey(hKey);
return TRUE;
}
BOOL ShowClock(HDC hdc, char *lpszBuf, INIDATA inidata)
{
HBRUSH hBrush;
HPEN hPen;
int h, m, s, x0, y0, x, y;
int l = CLOCK_HEIGHT / 2;
if (strcmp(lpszBuf, "") == 0)
return FALSE;
hBrush = CreateSolidBrush(inidata.cr_plate);
SelectObject(hdc, hBrush);
Ellipse(hdc, 1, 1, CLOCK_HEIGHT - 1, CLOCK_HEIGHT - 1);
Ellipse(hdc, 4, 4, CLOCK_HEIGHT - 4, CLOCK_HEIGHT - 4);
DeleteObject(hBrush);
GetHMS(lpszBuf, &h, &m, &s);
x0 = y0 = CLOCK_HEIGHT / 2;
//短針
if (h > 11)
h -= 12;
hPen = CreatePen(PS_SOLID, 4, inidata.cr_short);
SelectObject(hdc, hPen);
MoveToEx(hdc, x0, y0, NULL);
x = (int)(x0 + (l - 16) * sin(h * PAI / 6 + m * PAI / 360));
y = (int)(x0 - (l - 16) * cos(h * PAI / 6 + m * PAI / 360));
LineTo(hdc, x, y);
DeleteObject(hPen);
//長針
hPen = CreatePen(PS_SOLID, 2, inidata.cr_long);
SelectObject(hdc, hPen);
MoveToEx(hdc, x0, y0, NULL);
x = (int)(x0 + (l - 10) * sin(m * PAI / 30 + s * PAI / 1800));
y = (int)(y0 - (l - 10) * cos(m * PAI / 30 + s * PAI / 1800));
LineTo(hdc, x, y);
DeleteObject(hPen);
//秒針
hPen = CreatePen(PS_SOLID, 1, inidata.cr_second);
SelectObject(hdc, hPen);
MoveToEx(hdc, x0, y0, NULL);
x = (int)(x0 + (l - 5) * sin(s * PAI / 30));
y = (int)(y0 - (l - 5) * cos(s * PAI / 30));
LineTo(hdc, x, y);
DeleteObject(hPen);
return TRUE;
}
BOOL GetHMS(char *lpszBuf, int *lpH, int *lpM, int *lpS)
{
char szTemp[64], *token, szSep[] = ":";
strcpy(szTemp, lpszBuf);
token = strtok(szTemp, szSep);
*lpH = atoi(token);
token = strtok(NULL, szSep);
*lpM = atoi(token);
token = strtok(NULL, szSep);
*lpS = atoi(token);
return TRUE;
}
BOOL ShowBitmap(HDC hdc, INIDATA inidata)
{
HBITMAP hBmp, hMask;
BITMAP bmp_info;
HDC hdc_mem;
int wx,wy;
HBRUSH hBrush;
hBrush = CreateSolidBrush(inidata.cr_bg);
SelectObject(hdc, hBrush);
hBmp = (HBITMAP)LoadImage(hInst,
"CAT",
IMAGE_BITMAP,
0, 0,
LR_DEFAULTCOLOR);
hMask = (HBITMAP)LoadImage(hInst,
"MASK",
IMAGE_BITMAP,
0, 0,
LR_DEFAULTCOLOR);
if (hMask == NULL) {
MessageBox(NULL, "Error", szAppName, MB_OK);
return FALSE;
}
GetObject(hBmp, (int)sizeof(BITMAP), &bmp_info);
wx = bmp_info.bmWidth;
wy = bmp_info.bmHeight;
hdc_mem = CreateCompatibleDC(hdc);
SelectObject(hdc_mem, hBmp);
MaskBlt(hdc, CLOCK_WIDTH - wx - 5, 5, wx, wy,
hdc_mem, 0, 0,
hMask, 0, 0, MAKEROP4(SRCCOPY, PATCOPY));
DeleteObject(hBmp);
DeleteObject(hMask);
DeleteObject(hBrush);
DeleteDC(hdc_mem);
return TRUE;
}
BOOL CALLBACK MyAlarmProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
{
SYSTEMTIME st;
static HWND hTime, hCheck;
char szBuf[32];
static INIDATA *lpinidata;
int h, m, s;
switch (msg) {
case WM_INITDIALOG:
hTime = GetDlgItem(hDlg, IDC_DATETIMEPICKER1);
hCheck = GetDlgItem(hDlg, IDC_CHECK1);
SendMessage(hTime, DTM_SETFORMAT, 0, (LPARAM)"HH:mm:ss");
lpinidata = (INIDATA *)lp;
if (strcmp(lpinidata->szAlarmSet, "No") == 0) {
EnableWindow(hTime, FALSE);
Button_SetCheck(hCheck, BST_UNCHECKED);
} else {
EnableWindow(hTime, TRUE);
Button_SetCheck(hCheck, BST_CHECKED);
GetHMS(lpinidata->szAlarmTime, &h, &m, &s);
GetLocalTime(&st);
st.wHour = h;
st.wMinute = m;
st.wSecond = s;
DateTime_SetSystemtime(hTime, GDT_VALID, &st);
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wp)) {
case IDOK:
if (Button_GetCheck(hCheck) == BST_CHECKED) {
strcpy(lpinidata->szAlarmSet, "Yes");
DateTime_GetSystemtime(hTime, &st);
wsprintf(szBuf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
strcpy(lpinidata->szAlarmTime, szBuf);
} else {
strcpy(lpinidata->szAlarmSet, "No");
strcpy(lpinidata->szAlarmTime, "00:00:00");
}
EndDialog(hDlg, IDOK);
return TRUE;
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
return TRUE;
case IDC_CHECK1:
if (Button_GetCheck(hCheck) == BST_CHECKED) {
EnableWindow(hTime, TRUE);
}
else
EnableWindow(hTime, FALSE);
return TRUE;
}
return FALSE;
}
return FALSE;
}
これらの関数に変更はありません。
BOOL CALLBACK MyTimerProc(HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
{
static HWND hTime;
SYSTEMTIME st;
char szBuf[64];
static INIDATA *lpini;
int h, m, s;
switch (msg) {
case WM_INITDIALOG:
hTime = GetDlgItem(hDlg, IDC_DATETIMEPICKER1);
SendMessage(hTime, DTM_SETFORMAT, 0, (LPARAM)"HH:mm:ss");
lpini = (INIDATA *)lp;
GetLocalTime(&st);
GetHMS(lpini->szTimerTime, &h, &m, &s);
st.wHour = h;
st.wMinute = m;
st.wSecond = s;
DateTime_SetSystemtime(hTime, GDT_VALID, &st);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wp)) {
case IDOK:
DateTime_GetSystemtime(hTime, &st);
wsprintf(szBuf, "%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
strcpy(lpini->szTimerTime, szBuf);
EndDialog(hDlg, IDOK);
return TRUE;
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
return TRUE;
}
return FALSE;
}
return FALSE;
}
タイマー設定ダイアログのプロシージャです。WM_INITDIALOGメッセージが来たら、Date and Time Pickerコントロールのフォーマットを 指定します。そして、INIDATA構造体に指定してある時間にセットします。
スタートボタン(IDOK)が押されたらDate and Time Pickerコントロールに指定してある時間を取得して、szBufに書き込みます。
また、INIDATA構造体に書き込みます。
BOOL MyTimerShow(HDC hdc, int x, int y, INIDATA inidata, DWORD dwStart)
{
MMTIME mm;
char szBuf[64];
DWORD dwNow, dwTimerSec;
int h, m, s;
GetHMS(inidata.szTimerTime, &h, &m, &s);
dwTimerSec = h * 60 * 60 + m * 60 + s;
timeGetSystemTime(&mm, (UINT)sizeof(MMTIME));
dwNow = mm.u.ms;
SetHMS(szBuf, dwTimerSec - (dwNow - dwStart) / 1000);
TextOut(hdc, x, y, szBuf, (int)strlen(szBuf));
if (strcmp(szBuf, "00:00:00") == 0)
return TRUE;
return FALSE;
}
タイマーの残り時間を表示する関数です。GetHMS関数を利用して、inidata構造体のszTimerTimeメンバの"XX:XX:XX"形式の文字列から時、分、秒を取得します。これから、セットした時間の秒数をdwTimerSecに格納します。
timeGetSystemTime関数で現在のシステム時間を取得します。
現在のシステム時間から、スタート時のシステム時間の差を1000で割ったものを、 dwTimerSecから引くと残り時間(秒)がわかります。
秒を"XX:XX:XX"形式の文字列に変換するのが、SetHMS関数です。
変換後の文字列が"00:00:00"となった場合はTRUEを返し、そうでない場合はFALSEを返します。
BOOL SetHMS(char *lpszBuf, DWORD dwTm)
{
int h, m, s;
h = dwTm / (60 * 60);
m = (dwTm - h * 60 * 60) / 60;
s = dwTm - h * 60 * 60 - m * 60;
if (h > 23) {
h = 0;
m = 0;
s = 0;
}
wsprintf(lpszBuf, "%02d:%02d:%02d", h, m, s);
return TRUE;
}
時、分、秒の値から"XX:XX:XX"形式の文字列を作ります。
これは、眺めるとわかりますね。今回は、ちょっと面倒くさいところもありましたが比較的簡単でした。
Update 22/Jan/2003 By Y.Kumei