Windows定时器的使用
来源:互联网 发布:北京中信网络 编辑:程序博客网 时间:2024/06/05 06:11
//本文借鉴万立中老师的一篇博客,增加了些注释,感觉是很好的sdk编程的案例之一。
#include <windows.h>#include <time.h>#include <iostream>using namespace std; int bX, bY;//记录方块移动的坐标(方块左上角坐标)int b_Speed;//方块移动的速度(一次移动的数目)RECT WinRect;//窗口的大小//声明回调函数LONG CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM);//========================================================//WinMain函数//========================================================int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; HWND hWnd; WNDCLASSEX wnd; wnd.cbSize = sizeof(WNDCLASSEX); wnd.style = CS_HREDRAW | CS_VREDRAW; wnd.lpfnWndProc = (WNDPROC)MyWndProc; wnd.cbClsExtra = 0; wnd.cbWndExtra = 0; wnd.hInstance = hInstance; wnd.hIcon = NULL; wnd.hCursor = LoadCursor(NULL, IDC_ARROW); wnd.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wnd.lpszMenuName = NULL; wnd.lpszClassName = "TimerApp"; wnd.hIconSm = NULL; RegisterClassEx(&wnd); hWnd = CreateWindow( "TimerApp", "Timer测试程序", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 690, 520, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}//========================================================//回调函数//======================================================== LONG CALLBACK MyWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc; HGDIOBJ mbrush, oldbrush;//定义画刷句柄 int r;//为下面保存随机数设定变量 GetClientRect(hWnd, &WinRect);//获取窗口的大小,从而为下面的方块坐标设定范围 switch (message) { case WM_CREATE: srand((unsigned int)time(NULL)); bX = (WinRect.right-100)/2;//方块的初始化坐标 bY = (WinRect.bottom-100)/2; b_Speed = 5; //设置定时器,间隔时间为10毫秒 SetTimer(hWnd, 1, 10, (TIMERPROC) NULL); return 0; case WM_TIMER: r = rand()%2;//随机数取余数 if(r > 0) //(因为可能会有随机负数,大于0则x移动,否则y轴移动) bX = bX + b_Speed; else bY = bY + b_Speed; if(bX>WinRect.right-100 || bY>WinRect.bottom-100 || bX<0 || bY<0) {//下面是为了使方块不发越界 if(bX>WinRect.right-100) bX = WinRect.right-100; if(bY>WinRect.bottom-100) bY = WinRect.bottom-100; if(bX<0) bX = 0; if(bY<0) bY = 0; b_Speed = -b_Speed;//当方块碰到边框后,让方块向相反的方向移动 } //调用WM_PAINT重绘(并且擦除背景) InvalidateRect(hWnd, &WinRect, TRUE); return 0; case WM_PAINT: PAINTSTRUCT ps; hdc = BeginPaint(hWnd, &ps); mbrush = CreateSolidBrush(RGB(255, 0, 0)); oldbrush = SelectObject(hdc, mbrush); WinRect.left = bX; WinRect.right = WinRect.left + 100; WinRect.top = bY; WinRect.bottom = WinRect.top+100; FillRect(hdc, &WinRect, (HBRUSH)mbrush);//填充矩形方块 SelectObject(hdc, oldbrush); DeleteObject(mbrush); EndPaint(hWnd,&ps); return 0; case WM_CLOSE: if(IDOK==MessageBox(NULL,"你确定要退出吗?", "提示", MB_OKCANCEL|MB_ICONQUESTION)) { DestroyWindow(hWnd); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, message, wParam, lParam);}
定时器在实际编程中使用频率比较高,例如一些需要间隔一定时间自动执行的任务,如果任务执行对时间精度要求不是太苛求,使用简单的定时器就是一个较好的选择。当然,由于定时器在系统的优先级较低,有时在执行具体任务时可能会遇到一些意想不到的问题。如果这样的话,可以考虑直接使用线程或调用GetTickCount函数自己处理。对于一些简单的游戏编程,定时器完全可以胜任。本文以VC6.0为环境说明定时器的使用方法。
在Windows编程中,可以使用SetTimer函数设置并启动定时器。该函数在SDK的API定义中有四个参数,原型定义如下:
UINT SetTimer( HWND hWnd,
UINT nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc );
参数含义:
n hWnd
与定时器关联的窗口句柄。该窗口必须被调用的线程所拥有。如果该参数设为NULL,则意味着定时器没有需要关联的窗口,那么第二个参数nIDEvent就会被忽略;
n nIDEvent
指定一个非0的标识。如果hWnd参数为NULL,该参数被忽略;
n uElapse
定时器间隔的时间,以毫秒为单位;
n lpTimerFunc
指定的间隔时间自动执行的回调函数的指针;如果该参数为NULL,系统则自动向英勇程序队列发送WM_TIMER 消息;如果不为NULL,则会自动执行所指定的回调函数。该回调函数的定义如下:
void CALLBACK TimerProc(HWND hwnd,
UINT uMsg,
UINT idEvent,
DWORD dwTime );
回调函数的参数含义:
l hwnd: 要与定时器关联的窗口句柄;
l uMsg: 指定WM_TIMER消息;
l idEvent:定时器的标识;
l dwTime:指定自系统启动后的已经过去的毫秒数,该值由GetTickCount函数获得。
从以上SetTimer函数的定义可以看出,使用定时器时,有两个地方可以用来编写定时器要执行的任务代码:(1)WM _TIMER消息中;(2)自定义的TIMERPROC类型的任务函数。
为了说明问题,我们就在窗口实现一个随机移动的方块作为我们的定制绘制任务。下面分别对SetTimer函数的两种使用方式进行举例说明。
(1) 在WM _TIMER消息中编写任务代码:
首先,由于要用到随机函数以及时间函数,需要在以上代码的include部分增加下面的引用及变量的定义,具体作用见代码注释:
#include <time.h>
#include <iostream>
using namespace std;
int bX, bY;//记录方块移动的坐标
int b_Speed;//方块移动的速度
RECT WinRect;//窗口的大小
接下来,在MyWndProc回调函数中增加WM_CREATE、WM_TIMER消息,其中在WM_CREATE消息中调用SetTimer函数并初始化,需要注意的是,SetTimer函数的第三个参数需要设置为NULL,然后在WM_TIMER消息中改变方块的坐标位置、检测边界并调用InvalidateRect函数发送重绘消息,最后在WM_PAINT消息中编写具体的绘制代码。对修改后的代码重新进行编译,然后执行代码,会在窗口中看到一个不断随机移动的红色方块,当方块达到边界后会返回朝相反的方向移动。
我们知道,sdk的方式是调用函数,所以我们可以把处理定时器的一部分封装成函数,如下:
void CALLBACK TimerFunc(HWND hWnd,UINT nMsg,UINT
nTimerid,DWORD dwTime)
{
GetClientRect(hWnd, &WinRect);
int r = rand()%2;
if(r > 0)
bX = bX + b_Speed;
else
bY = bY + b_Speed;
if(bX>WinRect.right-100 || bY>WinRect.bottom-100 || bX<0 || bY<0)
{
if(bX>WinRect.right-100) bX = WinRect.right-100;
if(bY>WinRect.bottom-100) bY = WinRect.bottom-100;
if(bX<0) bX = 0;
if(bY<0) bY = 0;
b_Speed = -b_Speed;
}
//调用WM_PAINT重绘(并且擦除背景)
InvalidateRect(hWnd, &WinRect, TRUE);
}
最后注意将SetTimer函数的最后一个参数修改为函数入口的地址,如下:
SetTimer(hWnd, 1, 10, (TIMERPROC)TimerFunc);
改变后的代码如下:
#include <windows.h>#include <time.h>#include <iostream>using namespace std; int bX, bY;//记录方块移动的坐标(方块左上角坐标)int b_Speed;//方块移动的速度(一次移动的数目)RECT WinRect;//窗口的大小//声明回调函数LONG CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM);void CALLBACK TimerFunc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime);//========================================================//WinMain函数//========================================================int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; HWND hWnd; WNDCLASSEX wnd; wnd.cbSize = sizeof(WNDCLASSEX); wnd.style = CS_HREDRAW | CS_VREDRAW; wnd.lpfnWndProc = (WNDPROC)MyWndProc; wnd.cbClsExtra = 0; wnd.cbWndExtra = 0; wnd.hInstance = hInstance; wnd.hIcon = NULL; wnd.hCursor = LoadCursor(NULL, IDC_ARROW); wnd.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wnd.lpszMenuName = NULL; wnd.lpszClassName = "TimerApp"; wnd.hIconSm = NULL; RegisterClassEx(&wnd); hWnd = CreateWindow( "TimerApp", "Timer测试程序", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 690, 520, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam;}//========================================================//回调函数//======================================================== LONG CALLBACK MyWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc; HGDIOBJ mbrush, oldbrush;//定义画刷句柄 int r;//为下面保存随机数设定变量 GetClientRect(hWnd, &WinRect);//获取窗口的大小,从而为下面的方块坐标设定范围 switch (message) { case WM_CREATE: srand((unsigned int)time(NULL)); bX = (WinRect.right-100)/2;//方块的初始化坐标 bY = (WinRect.bottom-100)/2; b_Speed = 5; //设置定时器,间隔时间为10毫秒 SetTimer(hWnd, 1, 10, (TIMERPROC)TimerFunc); return 0; case WM_PAINT: PAINTSTRUCT ps; hdc = BeginPaint(hWnd, &ps); mbrush = CreateSolidBrush(RGB(255, 0, 0)); oldbrush = SelectObject(hdc, mbrush); WinRect.left = bX; WinRect.right = WinRect.left + 100; WinRect.top = bY; WinRect.bottom = WinRect.top+100; FillRect(hdc, &WinRect, (HBRUSH)mbrush);//填充矩形方块 SelectObject(hdc, oldbrush); DeleteObject(mbrush); EndPaint(hWnd,&ps); return 0; case WM_CLOSE: if(IDOK==MessageBox(NULL,"你确定要退出吗?", "提示", MB_OKCANCEL|MB_ICONQUESTION)) { DestroyWindow(hWnd); } return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, message, wParam, lParam);}void CALLBACK TimerFunc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime){ GetClientRect(hWnd, &WinRect); int r = rand()%2; if(r > 0) bX = bX + b_Speed; else bY = bY + b_Speed; if(bX>WinRect.right-100 || bY>WinRect.bottom-100 || bX<0 || bY<0) { if(bX>WinRect.right-100) bX = WinRect.right-100; if(bY>WinRect.bottom-100) bY = WinRect.bottom-100; if(bX<0) bX = 0; if(bY<0) bY = 0; b_Speed = -b_Speed; } //调用WM_PAINT重绘(并且擦除背景) InvalidateRect(hWnd, &WinRect, TRUE); }
- Windows定时器的使用
- [windows+cocos2dx]定时器的使用
- windows driver 定时器的使用
- windows下C的定时器timeSetEvent使用
- 关于Windows下定时器的使用
- windows服务中的定时器timer的使用
- windows下C的定时器timeSetEvent使用
- 关于Windows下定时器的使用
- windows下C的定时器timeSetEvent使用
- 关于Windows下定时器的使用
- windows下C的定时器timeSetEvent使用
- 『windows』定时器的使用
- windows下C的定时器timeSetEvent使用
- windows下C的定时器timeSetEvent使用
- windows定时器详解,如何使用windows定时器
- Windows控制台的定时器
- windows定时器的总结
- C++的console使用windows的消息机制,定时器等
- 基于Mysql的通用分页存储过程
- 迟到和睡觉究竟影响到谁
- 黑马程序员-java的配置文件
- C# 根据当前时间获取,本周,本月,本季度等时间段 .Net中Exception
- IT项目管理之系统测试
- Windows定时器的使用
- 安装bugfree2.1.2
- windows 32位操作系统中,每个进程最大可用内存空间为3GB
- 怎样招聘出色的产品经理
- Snort 使用手册,第 1 部分: 安装与配置
- unicode码表 及 unicode转utf8规则
- Java HotSpot Client VM 和 Java HotSpot Server VM
- php 的函数参数值类型限定
- ZF的页面跳转