注:以下内容为学习笔记,多数是从书本、资料中得来,只为加深印象,及日后参考。然而本人表达能力较差,写的不好。因非翻译、非转载,只好选原创,但多数乃摘抄,实为惭愧。但若能帮助一二访客,幸甚!
以下内容多数来自于《Windows程序设计》
1.计时器基础
Windows计时器是一种输入设备,每到一个指定的时间间隔,它都会周期性地发送WM_TIMER通知应用程序。
一些应用:多任务、保持更新进度报告(不断显式变化的信息)、实现定期自动存储、终止程序的演示版、控制运动速度、多媒体。
Windows应用程序是通过正常的消息队列来接收WM_TIMER消息,所以不用担心程序在处理其他任务时会被突然而来的WM_TIMER消息所“中断”。
WM_TIMER消息被放在正常的消息队列中,并和其他消息一起排队等候处理。因此并不能保证每隔指定时间就收到一个WM_TIMER消息。
WM_TIMER和WM_PAINT消息类似,都是低优先级的,只有当消息队列中没有其他消息时,程序才会收到它们。同样,应用程序也同时不会收到大量的WM_TIMER消息。因此不能通过WM_TIMER消息数来判定过去了多长时间。
2.使用计时器的方法
1)法1:
SetTimer(hwnd, 1, uiMsecInterval, NULL);
KillTimer(hwnd, 1);
在 WM_TIMER消息中,wParam等于计时器的ID。
/*--------------------------------------
BEEPER1.C -- Timer Demo Program ver1
--------------------------------------*/
#include <windows.h>
#include <stdlib.h>
#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("Beeper1");
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("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0 ;
}
hwnd = CreateWindow(szAppName, TEXT ("Beeper1 Timer Demo"),
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;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HBRUSH hBrush;
HDC hdc;
PAINTSTRUCT ps;
RECT rc;
switch (message)
{
case WM_CREATE:
SetTimer(hwnd, ID_TIMER, 1000, NULL);
return 0 ;
case WM_TIMER:
MessageBeep(-1);
InvalidateRect(hwnd, NULL, FALSE);
return 0;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect(hwnd, &rc);
hBrush = CreateSolidBrush(RGB(rand()%255, rand()%255, rand()%255));
FillRect(hdc, &rc, hBrush);
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY:
KillTimer(hwnd, ID_TIMER);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
2)法2:
让Windows把计时器消息发送到程序中的另一个函数。
收到计时器消息的函数被称为“回调”函数。这是程序中被Windows调用的函数。回调函数必须定义为CALLBACK类型,因为Windows是从程序的代码空间以外调用这个函数的。送到回调函数的参数和从回调函数返回的数据是由该函数要实现的功能所决定的。当回调函数与计时器同时使用时,它的参数实际上与窗口过程的参数是一样的,只不过他们的定义不同。
VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime){} SetTimer(hwnd, iTimerID, iMsecInterval, TimerProc);示例:
/*-----------------------------------------------------------
BEEPER2.cpp -- Timer Demo Program ver1
------------------------------------------------------------*/
#include <windows.h>
#include <stdlib.h>
#define ID_TIMER 1
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
VOID CALLBACK TimerProc(HWND, UINT, UINT, DWORD);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("Beeper2");
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("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0 ;
}
hwnd = CreateWindow(szAppName, TEXT ("Beeper2 Timer Demo"),
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;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
SetTimer(hwnd, ID_TIMER, 1000, TimerProc);
return 0 ;
case WM_DESTROY:
KillTimer(hwnd, ID_TIMER);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
HBRUSH hBrush;
HDC hdc;
RECT rc;
MessageBeep(-1);
GetClientRect(hwnd, &rc);
hdc = GetDC(hwnd);
hBrush = CreateSolidBrush(RGB(rand()%255, rand()%255, rand()%255));
FillRect(hdc, &rc, hBrush);
ReleaseDC(hwnd, hdc);
DeleteObject(hBrush);
}
3)法3:
需要多次调用SetTimer,又不想记录哪些计时器ID已经被使用过,可以:
iTimerID = SetTimer(NULL, 0, wMsecInterval, TimerProc);
KillTimer(NULL, iTimerID);
3.使用计时器作为时钟
1)数字时钟
/*-----------------------------------------------------------
digClock.cpp -- Digital Clock
------------------------------------------------------------*/
#include <windows.h>
#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("This 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, fSuppress);
DisplayColon(hdc);
DisplayTwoDigits(hdc, st.wSecond, fSuppress);
}
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);
SetWindowExtEx(hdc, 138, 36, NULL);
SetViewportExtEx(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) ;
}
2)模拟时钟
/*-----------------------------------------------------------
digClock.cpp -- Digital Clock
------------------------------------------------------------*/
#include <windows.h>
#include <math.h>
#define ID_TIMER 1
#define TWOPI (2*3.14159)
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("This 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 SetIsotropic(HDC hdc, int cxClient, int cyClient)
{
SetMapMode(hdc, MM_ISOTROPIC);
SetWindowExtEx(hdc, 1000, 1000, NULL);
SetViewportExtEx(hdc, cxClient/2, -cyClient/2, NULL);
SetViewportOrgEx(hdc, cxClient/2, cyClient/2, NULL);
}
void RotatePoint(POINT pt[], int iNum, int iAngle)
{
int i;
POINT ptTemp;
for (i = 0; i < iNum; i++)
{
ptTemp.x = (int)( pt[i].x * cos(TWOPI*iAngle/360) + pt[i].y * sin(TWOPI*iAngle/360) );
ptTemp.y = (int)( pt[i].y * cos(TWOPI*iAngle/360) + pt[i].x * sin(TWOPI*iAngle/360) );
pt[i] = ptTemp;
}
}
void DrawClock(HDC hdc)
{
int iAngle;
POINT pt[3];
for (iAngle = 0; iAngle < 360; iAngle += 6)
{
pt[0].x = 0;
pt[0].y = 900;
RotatePoint(pt, 1, iAngle);
pt[2].x = pt[2].y = iAngle%5 ? 33 : 100;
pt[0].x -= pt[2].x / 2;
pt[0].y -= pt[2].y / 2;
pt[1].x = pt[0].x + pt[2].x;
pt[1].y = pt[0].y + pt[2].y;
SelectObject(hdc, GetStockObject(BLACK_BRUSH));
Ellipse(hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
}
}
void DrawHands(HDC hdc, SYSTEMTIME* pst, BOOL fChange)
{
static POINT pt[3][5] = {
0, -150, 100, 0, 0, 600, -100, 0, 0, -150,
0, -200, 50, 0, 0, 800, -50, 0, 0, -200,
0, 0, 0, 0, 0, 0, 0, 0, 0, 800
};
int i, iAngle[3];
POINT ptTemp[3][5];
iAngle[0] = (pst->wHour * 30) % 360 + pst->wMinute/2;
iAngle[1] = pst->wMinute * 6;
iAngle[2] = pst->wSecond * 6;
memcpy(ptTemp, pt, sizeof(pt));
for (i = fChange ? 0 : 2; i < 3; i++)
{
RotatePoint(ptTemp[i], 5, iAngle[i]);
Polyline(hdc, ptTemp[i], 5);
}
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static SYSTEMTIME stPrevious;
static int cxClient, cyClient;
BOOL fChange;
HDC hdc;
PAINTSTRUCT ps;
SYSTEMTIME st;
switch (message)
{
case WM_CREATE:
SetTimer(hwnd, ID_TIMER, 1000, NULL);
GetLocalTime(&st);
stPrevious = st;
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0;
case WM_TIMER:
GetLocalTime(&st);
fChange = st.wHour != stPrevious.wHour ||
st.wMinute != stPrevious.wHour;
hdc = GetDC(hwnd);
SetIsotropic(hdc, cxClient, cyClient);
SelectObject(hdc, GetStockObject(WHITE_PEN));
DrawHands(hdc, &stPrevious, fChange);
SelectObject(hdc, GetStockObject(BLACK_PEN));
DrawHands(hdc, &st, TRUE);
ReleaseDC(hwnd, hdc);
stPrevious = st;
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
SetIsotropic(hdc, cxClient, cyClient);
DrawClock(hdc);
DrawHands(hdc, &stPrevious, TRUE);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
KillTimer(hwnd, ID_TIMER);
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
4.在状态报告中使用计时器
/*-----------------------------------------------------------
whatclr.cpp -- Displays Color Under Cursor
------------------------------------------------------------*/
#include <windows.h>
#define ID_TIMER 1
void FindWindowSize(int* , int* );
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WhatClr");
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("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0 ;
}
hwnd = CreateWindow(szAppName, TEXT ("What Color"),
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 FindWindowSize(int* pcxWindow, int* pcyWindow)
{
HDC hdcScreen;
TEXTMETRIC tm;
hdcScreen = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
GetTextMetrics(hdcScreen, &tm);
DeleteDC(hdcScreen);
*pcxWindow = 2 * GetSystemMetrics(SM_CXBORDER) + 12 * tm.tmAveCharWidth;
*pcyWindow = 2 * GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYCAPTION) + 2 * tm.tmHeight;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static COLORREF cr, crLast;
static HDC hdcScreen;
HDC hdc;
PAINTSTRUCT ps;
POINT pt;
RECT rc;
TCHAR szBuffer[16];
switch (message)
{
case WM_CREATE:
hdcScreen = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
SetTimer(hwnd, ID_TIMER, 100, NULL);
return 0;
case WM_TIMER:
GetCursorPos(&pt);
cr = GetPixel(hdcScreen, pt.x, pt.y);
SetPixel(hdcScreen, pt.x, pt.y, 0);
if (cr != crLast)
{
crLast = cr;
InvalidateRect(hwnd, NULL, FALSE);
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rc);
wsprintf(szBuffer, TEXT(" %02X %02X %02X "), GetRValue(cr), GetGValue(cr), GetBValue(cr));
DrawText(hdc, szBuffer, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
DeleteDC(hdcScreen);
KillTimer(hwnd, ID_TIMER);
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}