Win32API学习笔记第四章

这次记录的是计时器的消息和部分相应API的使用如与标准(本人学的是Win程序设计第五版)有偏差,或哪里有不妥,欢迎大家给予斧正!

消息:

WM_TIMER

这个消息是由Windows处理硬件中断的产生的,Windows保存一个每次硬件计时器滴答减少的次数,当这个计数减到0时就会产生一个WM_TIMER消息,这个消息其实时不会造成异步的(类似键盘和鼠标,由硬件来处理异步硬件中断时间)所以,这个消息同样要进入消息队列等待消息循环的读取,所以这个消息的产生并不是非常准确的,这要取决于计算机硬件和之前消息的处理速度,如果之前的消息没有处理完,同样WM_TIMER这个消息也比需等待,所以这个时间实际上并不是特别的准确。
顺带一提,这个消息和WM_PAINT是同样的最低优先级,因为这一点就可以防止异步处理消息,并且同样的,这个消息Winows也不会同时在消息队列内插入多个,而是会将多个此消息合并为一个(类似WM_PAINT)

相关API

要使用这个计时器,按照常理我们有:

SetTimer(hWnd,计时器ID,时间间隔,一个函数指针(可为NULL))

KillTimer(hWnd,计时器ID)

通常我们会在消息WM_CREATE和WM_DESTROY两个消息里分别设置SetTimer和KillTimer,当然,我们发现,SetTimer这个函数后面跟了一个特殊的函数指针,实际上这个函数指针里面的语句就是WM_TIMER消息,只是此时这个消息的执行方式由:计时器滴答计数为0->向消息队列内插入WM_TIMER->等待WndProc接收并处理此消息变为:计时器滴答计数为0->调用函数指针所指向的函数
这个函数是一个时间消息过程(类似于窗口过程)TimeProc的形式是:void CALLBACK TimeProc(hWnd,message,计时器ID,一个从GetTickCount函数返回值兼容的值)(这个GetTickCount的返回值是Windows启动后所进过的毫秒数)

SYSTEMTIME结构

这个结构包含了年月日时分秒毫秒,相当的准确

GetLocalTime和GetSystemTime函数

这两个函数的参数都是(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);
}

这个程序是做了一个简易的电子时钟,一个值得注意的点是在获取时间消息那里,它强制性的刷新了客户区,虽然会导致出现是不是的闪烁问题,但是这个是美妙刷新一次显示最好的解决方法了

你可能感兴趣的:(windows程序设计)