这次记录的是计时器的消息和部分相应API的使用如与标准(本人学的是Win程序设计第五版)有偏差,或哪里有不妥,欢迎大家给予斧正!
这个消息是由Windows处理硬件中断的产生的,Windows保存一个每次硬件计时器滴答减少的次数,当这个计数减到0时就会产生一个WM_TIMER消息,这个消息其实时不会造成异步的(类似键盘和鼠标,由硬件来处理异步硬件中断时间)所以,这个消息同样要进入消息队列等待消息循环的读取,所以这个消息的产生并不是非常准确的,这要取决于计算机硬件和之前消息的处理速度,如果之前的消息没有处理完,同样WM_TIMER这个消息也比需等待,所以这个时间实际上并不是特别的准确。
顺带一提,这个消息和WM_PAINT是同样的最低优先级,因为这一点就可以防止异步处理消息,并且同样的,这个消息Winows也不会同时在消息队列内插入多个,而是会将多个此消息合并为一个(类似WM_PAINT)
要使用这个计时器,按照常理我们有:
通常我们会在消息WM_CREATE和WM_DESTROY两个消息里分别设置SetTimer和KillTimer,当然,我们发现,SetTimer这个函数后面跟了一个特殊的函数指针,实际上这个函数指针里面的语句就是WM_TIMER消息,只是此时这个消息的执行方式由:计时器滴答计数为0->向消息队列内插入WM_TIMER->等待WndProc接收并处理此消息变为:计时器滴答计数为0->调用函数指针所指向的函数
这个函数是一个时间消息过程(类似于窗口过程)TimeProc的形式是:void CALLBACK TimeProc(hWnd,message,计时器ID,一个从GetTickCount函数返回值兼容的值)(这个GetTickCount的返回值是Windows启动后所进过的毫秒数)
这个结构包含了年月日时分秒毫秒,相当的准确
这两个函数的参数都是(L)PSYSTEMTIME,其中,前者时当地的时间,这个依赖于计算机的时区,后者则是和英国格林威治的时间大概相同,两者的精确度完全取决于用户的设定
来看一个书上的例子:
/*-----------------------------------------
DIGCLOCK.c -- Digital Clock
(c) Charles Petzold, 1998
-----------------------------------------*/
#include
#define ID_TIMER 1
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("DigClock");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("Program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, TEXT("Digital Clock"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
void DisplayDigit(HDC hdc, int iNumber)
{
static BOOL fSevenSegment[10][7] = {
1, 1, 1, 0, 1, 1, 1, // 0
0, 0, 1, 0, 0, 1, 0, // 1
1, 0, 1, 1, 1, 0, 1, // 2
1, 0, 1, 1, 0, 1, 1, // 3
0, 1, 1, 1, 0, 1, 0, // 4
1, 1, 0, 1, 0, 1, 1, // 5
1, 1, 0, 1, 1, 1, 1, // 6
1, 0, 1, 0, 0, 1, 0, // 7
1, 1, 1, 1, 1, 1, 1, // 8
1, 1, 1, 1, 0, 1, 1 }; // 9
static POINT ptSegment[7][6] = {
7, 6, 11, 2, 31, 2, 35, 6, 31, 10, 11, 10,
6, 7, 10, 11, 10, 31, 6, 35, 2, 31, 2, 11,
36, 7, 40, 11, 40, 31, 36, 35, 32, 31, 32, 11,
7, 36, 11, 32, 31, 32, 35, 36, 31, 40, 11, 40,
6, 37, 10, 41, 10, 61, 6, 65, 2, 61, 2, 41,
36, 37, 40, 41, 40, 61, 36, 65, 32, 61, 32, 41,
7, 66, 11, 62, 31, 62, 35, 66, 31, 70, 11, 70 };
int iSeg;
for (iSeg = 0; iSeg < 7; iSeg++)
if (fSevenSegment[iNumber][iSeg])
Polygon(hdc, ptSegment[iSeg], 6);
}
void DisplayTwoDigits(HDC hdc, int iNumber, BOOL fSuppress)
{
if (!fSuppress || (iNumber / 10 != 0))
DisplayDigit(hdc, iNumber / 10);
OffsetWindowOrgEx(hdc, -42, 0, NULL);
DisplayDigit(hdc, iNumber % 10);
OffsetWindowOrgEx(hdc, -42, 0, NULL);
}
void DisplayColon(HDC hdc)
{
POINT ptColon[2][4] = { 2, 21, 6, 17, 10, 21, 6, 25,
2, 51, 6, 47, 10, 51, 6, 55 };
Polygon(hdc, ptColon[0], 4);
Polygon(hdc, ptColon[1], 4);
OffsetWindowOrgEx(hdc, -12, 0, NULL);
}
void DisplayTime(HDC hdc, BOOL f24Hour, BOOL fSuppress)
{
SYSTEMTIME st;
GetLocalTime(&st);
if (f24Hour)
DisplayTwoDigits(hdc, st.wHour, fSuppress);
else
DisplayTwoDigits(hdc, (st.wHour %= 12) ? st.wHour : 12, fSuppress);
DisplayColon(hdc);
DisplayTwoDigits(hdc, st.wMinute, FALSE);
DisplayColon(hdc);
DisplayTwoDigits(hdc, st.wSecond, FALSE);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL f24Hour, fSuppress;
static HBRUSH hBrushRed;
static int cxClient, cyClient;
HDC hdc;
PAINTSTRUCT ps;
TCHAR szBuffer[2];
switch (message)
{
case WM_CREATE:
hBrushRed = CreateSolidBrush(RGB(255, 0, 0));
SetTimer(hwnd, ID_TIMER, 1000, NULL);
// fall through
case WM_SETTINGCHANGE:
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, szBuffer, 2);
f24Hour = (szBuffer[0] == '1');
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITLZERO, szBuffer, 2);
fSuppress = (szBuffer[0] == '0');
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_TIMER:
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SetMapMode(hdc, MM_ISOTROPIC);
SetWindowExtEx(hdc, 276, 72, NULL);
SetViewportExtEx(hdc, cxClient, cyClient, NULL);
SetWindowOrgEx(hdc, 138, 36, NULL);
SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);
SelectObject(hdc, GetStockObject(NULL_PEN));
SelectObject(hdc, hBrushRed);
DisplayTime(hdc, f24Hour, fSuppress);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
KillTimer(hwnd, ID_TIMER);
DeleteObject(hBrushRed);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
这个程序是做了一个简易的电子时钟,一个值得注意的点是在获取时间消息那里,它强制性的刷新了客户区,虽然会导致出现是不是的闪烁问题,但是这个是美妙刷新一次显示最好的解决方法了