windows基础应用程序编程(十三)定时器

简介

    定时器相对来讲比较简单,主要用于我们程序中的定时功能,当我们需要使用定时器的时候,需要用一个SetTimer函数来建立一个定时器,如果建立成功,系统会在指定的时间内调用SetTimer函数所指定的回调函数,或者向指定的窗口过程发送WM_TIMER消息。需要注意的是,WM_TIMER是一个低级别的消息,也就是说Windows只有在消息队列中没有其他的消息的情况下才会发送WM_TIMER消息,如果窗口过程忙于处理其他消息而没有返回,使得消息队列中有消息积累起来,那么WM_TIMER消息就会被丢弃,在消息队列再度空闲的时候,被丢弃的WM_TIMER消息也不会被补发,另外,消息队列中不会有多条WM_TIMER消息,如果消息队列中已经有了一条WM_TIMER消息,还没有来得及处理,又到了定时的时刻,那么两条WM_TIMER消息会被合并。所以说,我们不能够实用定时器来完成某一项高精度的事情。

使用方法

    在讨论定时器的使用方法之前,我们首先来看一下,SetTimer函数。
    UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc );
  •     hWnd:需要发送定时器消息的窗口句柄,如果为NULL,则第二个参数被忽略。
  •     nIDEvent:用户指定的定时器ID,我们可能在程序中设置不止一个定时器,这个参数用来区分是哪一个定时器。
  •     uElapse:以毫秒为单位的一个时间,在每隔这个时间后会发送一个定时器消息。
  •     lpTimerFunc:定时器过程,当间隔时间到,会调用这个过程,如果为NULL,则系统会发送一个WM_TIMER消息到应用程序的消息队列中去。定时器过程函数一般定义为:
    VOID CALLBACK TimerProc(
        HWND hwnd, // handle to window
        UINT uMsg, // WM_TIMER message
        UINT_PTR idEvent, // timer identifier
        DWORD dwTime // current system time
    );


    当我们不再需要一个定时器的时候,我们需要使用KillTimer函数来结束一个定时器,这个函数有两个参数,第一个参数传入窗口句柄,第二个参数表示定时器的ID,以表示要结束的是哪一个定时器。
    提到定时器,就不得不说的是,Windows为我们提供的获取系统时间的函数。获取系统时间的函数有2个,一个是GetLocalTime函数,一个是GetSystemTime函数,GetLocalTime返回当前的时间,GetSystemTime返回当前的格林威治标准时间,这两个函数都需要传入一个指向SYSTEMTIME结构的指针,函数会把时间数据返回到这个缓冲区中。与此相对应的,我们可以使用SetLocalTime函数和SetSystemTime函数来设置系统时间。
    了解了这么多,我们现在可以看看定时器的使用方法了,设置定时器一般有两种使用方法,第一种类似:
    
 SetTimer( hwnd, ID_TIMER1, 1000, NULL );

    这样我们就设置了一个每隔1秒钟就会发送一个WM_TIMER消息的定时器,其ID是ID_TIMER1,这时,别忘了在程序中处理WM_TIMER消息。第二种如下使用:
     SetTimer( hwnd, ID_TIMER2, 1000, TimerProc );


    同样,我们定义了一个间隔时间是1秒钟的定时器,只不过,在每1秒钟后,其不会发送定时器消息,而是调用TimerProc函数,TimeProc函数的定义如上所示。最后,在结束的时候,这两种情况都需要调用KillTimer函数。

实例

     我们通过一个一个时钟程序来观察一下定时器的使用,其运行界面和完整代码如下所示:(除去资源定义)
windows基础应用程序编程(十三)定时器_第1张图片
// clock.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include 
#include "resource.h"

#define ID_TIMER 1
#define PI  3.14159

LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
void ShowTime( HWND, HDC, int, int );
void DrawDot( HDC, double, int, LONG, POINT );
void DrawLine( HDC, double, int, LONG, POINT );

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    MSG msg;
    WNDCLASSEX wndcls = {0};
    wndcls.cbSize = sizeof(WNDCLASSEX);
    wndcls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wndcls.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndcls.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(ICO_MAIN));
    wndcls.hInstance = hInstance;
    wndcls.lpfnWndProc = WndProc;
    wndcls.lpszClassName = "Clock";
    wndcls.style = CS_HREDRAW | CS_VREDRAW;

    RegisterClassEx( &wndcls );
    
    HWND hWnd = CreateWindowEx( WS_EX_CLIENTEDGE, "Clock", "Clock",
        WS_OVERLAPPEDWINDOW, 100, 100, 250, 270,
        NULL, NULL, hInstance, NULL );

    ShowWindow( hWnd, SW_SHOWNORMAL );
    UpdateWindow( hWnd );

    while( GetMessage(&msg,NULL,0,0) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    
     return msg.wParam;
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    HDC hdc;
    PAINTSTRUCT ps;
    static int cxWidth,cyHight;
    switch(uMsg)
    {
    case WM_SIZE:
        cxWidth = LOWORD(lParam);
        cyHight = HIWORD(lParam);
        return 0;
    case WM_TIMER:
        // 每隔一秒钟刷新一次界面,发送WM_PAINT消息
        InvalidateRect( hWnd, NULL, TRUE );
        return 0;
    case WM_PAINT:
        hdc = BeginPaint( hWnd, &ps );
        // 显示当前时间
        ShowTime( hWnd, hdc, cxWidth, cyHight);
        EndPaint( hWnd, &ps );
        return 0;
    case WM_CREATE:
        // 定义一个间隔时间为1秒的定时器。
        SetTimer( hWnd, ID_TIMER, 1000, NULL);
        return 0;
    case WM_CLOSE:
        // 结束一个定时器。
        KillTimer( hWnd, ID_TIMER );
        DestroyWindow( hWnd );
        PostQuitMessage( 0 );
        return 0;
    }
    return DefWindowProc( hWnd, uMsg, wParam, lParam );
}


void ShowTime( HWND hWnd, HDC hdc, int cxWidth, int cyHight )
{

    // Compute Radius,and center point
    int radius;
    POINT center;

    center.x = cxWidth / 2;
    center.y = cyHight / 2;

    if( cyHight < cxWidth )
        radius = cyHight / 2;
    else
        radius = cxWidth / 2;

    // draw dot
    HBRUSH hBrush,hOldBrush;
    hBrush = (HBRUSH)GetStockObject( BLACK_BRUSH );
    hOldBrush = (HBRUSH)SelectObject( hdc, hBrush );
    DrawDot( hdc, 360 / 12, 3, radius, center);
    DrawDot( hdc, 360 / 60, 1, radius, center);
    SelectObject( hdc, hOldBrush );
    DeleteObject( hBrush );
    // Get local time
    SYSTEMTIME systime;
    GetLocalTime( &systime );
    // draw line
    double degree = systime.wSecond * 360 / 60;
    HPEN hPen,hOldPen;
    hPen = CreatePen( PS_SOLID, 1, RGB(255, 0, 0) );
    hOldPen = (HPEN)SelectObject( hdc, hPen );
    DrawLine( hdc, degree, 15, radius, center );
    SelectObject( hdc, hOldPen );
    DeleteObject( hPen );

    degree = systime.wMinute * 360 / 60;
    hPen = CreatePen( PS_SOLID, 2, NULL );
    hOldPen = (HPEN)SelectObject( hdc, hPen );
    DrawLine( hdc, degree, 20, radius, center );
    SelectObject( hdc, hOldPen );
    DeleteObject( hPen );

    int hour = systime.wHour;
    if (hour >= 12)
    {
        hour -= 12;
    }
    degree = hour * 360 / 12 + systime.wMinute / 2;
    hPen = CreatePen( PS_SOLID, 3, NULL );
    hOldPen = (HPEN)SelectObject( hdc, hPen );
    DrawLine( hdc, degree, 30, radius, center );
    SelectObject( hdc, hOldPen );
    DeleteObject( hPen );

}


void DrawDot( HDC hdc, double degreeInc, int length, LONG radius, POINT center )
{
    double degreeNow = 0;
    POINT dotNow;
    radius -= 10;
    while( degreeNow <= 360 )
    {
        dotNow.x = (LONG)(center.x + radius * sin( degreeNow * PI / 180 ));
        dotNow.y = (LONG)(center.y - radius * cos( degreeNow * PI / 180 ));
        Ellipse( hdc, dotNow.x - length, dotNow.y - length, dotNow.x + length, dotNow.y + length );
        degreeNow += degreeInc;
    }
    
}

void DrawLine( HDC hdc, double degree, int length, LONG radius, POINT center )
{
    POINT start, end;
    start.x = (LONG)(center.x + 10 * sin( (degree + 180) * PI / 180 ));
    start.y = (LONG)(center.y - 10 * cos( (degree + 180) * PI / 180 ));

    end.x = (LONG)(center.x + (radius - length) * sin( degree * PI / 180 ));
    end.y = (LONG)(center.y - (radius - length) * cos( degree * PI / 180 ));

    MoveToEx( hdc, start.x, start.y, NULL );
    LineTo( hdc, end.x, end.y );
}


你可能感兴趣的:(windows基础应用程序编程)