zoukankan      html  css  js  c++  java
  • 第8章 计时器

    8.1 计时器的基本知识

    (1)SetTimer时间参数:1毫秒到4294 967 295毫秒(近50天)

    (2)Windows本身处理BIOS中断,应用程序不需介入,Windows会每个计时器保持一个计数值,硬件时钟滴答一次,这个值减1.当计数为0时,发送WM_TIMER到消息队列,同时计数值重新恢复到原始值。

    (3)WIN98的计时器周期约为55毫秒,Windows NT大约为10毫秒。即SetTimer参数小于这个数值,则根据操作系统取其中的一个值。SetTimer会把指定的时间间隔舍入到时钟滴答的整数倍,如1000ms/54.925=18.2个时钟滴答,舍入后为18个时钟滴答,即实际的间隔为989ms。

    (4)计时器消息不是异步的。在指定的时间内可能因程序忙而收到不到WM_TIMER消息。WM_TIMER消息与WM_PAINT消息都是低优先级的,只有当队列没其他消息时,程序才会接收它们。

    8.2 使用计时器的三种方法

    (1)处理WM_TIMER消息

    ①SetTimer(hwnd,ID_TIMER,uiMsecInterval,NULL);//ID_TIMER>0,不能为0.

    ②KillTimer(hwnd,ID_TIMER);

    ③消息参数:wParam=ID_TIMER; lParam =0;

    例: 定义2个计时器

    #define TIMER_SEC 1

    #define TIMER_MIN 2

    //设置定时器

    SetTimer(hwnd,TIMER_SEC,1000,NULL);  //1秒

    SetTimer(hwnd,TIMER_MIN,60000,NULL); //1分钟

    //WM_TIMER处理逻辑

    case WM_TIMER:

       switch(wParam)

       {

    case TIMER_SEC:

        [每秒钟一次的处理]

         Break;

    case TIMER_MIN:

        [每分钟一次的处理]

         Break;

    }

    return 0;

    【Beeper1程序】

    /*------------------------------------------------------------
    BEEPER1.C -- Timer Demo Program No.1
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    #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("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,                  // window class name
            TEXT("Beeper1 Timer Demo"), // window caption
            WS_OVERLAPPEDWINDOW,        // window style
            CW_USEDEFAULT,              // initial x position
            CW_USEDEFAULT,              // initial y position
            CW_USEDEFAULT,              // initial x size
            CW_USEDEFAULT,              // initial y size
            NULL,                       // parent window handle
            NULL,                       // window menu handle
            hInstance,                  // program instance handle
            NULL);                     // creation parameters
    
        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)
    {
        static BOOL fFlipFlop = FALSE;
        HBRUSH hBrush;
        HDC         hdc;
        PAINTSTRUCT ps;
        RECT        rect;
    
        switch (message)
        {
        case WM_CREATE:
            SetTimer(hwnd, ID_TIMER, 1000, NULL);
            return 0;
        case WM_TIMER:
            MessageBeep(-1);
            fFlipFlop = !fFlipFlop;
            InvalidateRect(hwnd, NULL, FALSE);
            return 0;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            GetClientRect(hwnd, &rect);
            hBrush = CreateSolidBrush(fFlipFlop ? RGB(255, 0, 0) : RGB(0, 0, 255));
            FillRect(hdc, &rect, hBrush);
            DeleteObject(hBrush);
            EndPaint(hwnd, &ps);
            return 0;
    
        case WM_DESTROY:
            KillTimer(hwnd, ID_TIMER);
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    (2)利用回调函数处理——将忽略窗口过程中的WM_TIMER消息处理代码

      ①VOID CALLBACK MyTimerProc(HWNDhwnd,UINT message,UINT iTimerID,DWORD dwTime)

      ②SetTimer(hwnd,iTimerID,iMsecInterval,MyTimerProc);

        ★注意:从回调函数中得到的dwTime等于GetTickCount返回的值,指的是自Windows启动到现在的毫秒数。

    【Beeper2程序】

    /*------------------------------------------------------------
    BEEPER2.C -- Timer Demo Program No.2
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    #include <windows.h>
    #define ID_TIMER 1
    VOID CALLBACK TimerProc(HWND, UINT, UINT, DWORD);
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    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,                  // window class name
            TEXT("Beeper2 Timer Demo"), // window caption
            WS_OVERLAPPEDWINDOW,        // window style
            CW_USEDEFAULT,              // initial x position
            CW_USEDEFAULT,              // initial y position
            CW_USEDEFAULT,              // initial x size
            CW_USEDEFAULT,              // initial y size
            NULL,                       // parent window handle
            NULL,                       // window menu handle
            hInstance,                  // program instance handle
            NULL);                     // creation parameters
    
        ShowWindow(hwnd, iCmdShow);
        UpdateWindow(hwnd);
    
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;
    }
    VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
    {
        HBRUSH hBrush;
        HDC         hdc;
        RECT        rect;
        static BOOL fFlipFlop = FALSE;
        MessageBeep(-1);
        fFlipFlop = !fFlipFlop;
        hdc = GetDC(hwnd);
        GetClientRect(hwnd, &rect);
        hBrush = CreateSolidBrush(fFlipFlop ? RGB(255, 0, 0) : RGB(0, 0, 255));
        FillRect(hdc, &rect, hBrush);
        DeleteObject(hBrush);
        ReleaseDC(hwnd, hdc);
    }
    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_TIMER:
            //MessageBeep(-1);
            //fFlipFlop = !fFlipFlop;
            //InvalidateRect(hwnd, NULL, FALSE);
            //return 0;
    
        case WM_DESTROY:
            KillTimer(hwnd, ID_TIMER);
            PostQuitMessage(0);
            return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    (3)方法三——与第2种相似,但SetTimer的设置如下。(一般很少这样用)

    参数

    设置

    备注

    hwnd

    NULL

    SetTimer、KillTimer、回调函数的hwnd都要设为NULL;

    第2个参数

    0

    被忽略,填0

    第4个参数

    TimerProc

    回调函数

    返回值

    计时器的ID

    如返回0,说明没有可用的计时器

    8.3 使用计时器作为时钟

    8.3.1 数字时钟

    (1)获取系统时间:GetLocalTime(当地时间)和GetSystemTime(协调世界时UTC)

    (2)显示数字和冒号——自定义函数DisplayDigit和DisplayColon

     

    ①BOOL fSevenSegment[10][7]——用来控制0-9这10个数字的LED相应段开与关

    ②static POINT ptSegment[7][6]——表示LED中7个六边形的顶点坐标。

    ③数字宽度为42个单位,高度为72个单位,冒号是12个单位宽。6个数字加冒号共276个单位宽度。

    (3)国际化——控制面板【区域和语言选项】中设置格式化日期和时间

        ①显示12或24小时格式。

            //获得是否是24小时格式

            GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_ITIME, szBuffer, 2);

            f24Hour = (szBuffer[0] =='1');

        ②小时数字是0不显示的处理,见DisplayTwoDigits函数。

        //获取是否显示小时的第1个0.

         GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_ITLZERO, szBuffer, 2);

         fSuppress= (szBuffer[0] == '0');

    【DigClock程序】
    【效果图】

    /*------------------------------------------------------------
    DIGCLOCK.C -- Digital Clock
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    #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,                  // window class name
            TEXT("Digital Clock"), // window caption
            WS_OVERLAPPEDWINDOW,        // window style
            CW_USEDEFAULT,              // initial x position
            CW_USEDEFAULT,              // initial y position
            CW_USEDEFAULT,              // initial x size
            CW_USEDEFAULT,              // initial y size
            NULL,                       // parent window handle
            NULL,                       // window menu handle
            hInstance,                  // program instance handle
            NULL);                     // creation parameters
    
        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
        //定义数字8的每个笔划(共7笔,每笔形状为6边形)
        static POINT ptSegment[7][6] = {
            7, 6, 11, 2, 31, 2, 35, 6, 31, 10, 11, 10,       //第0笔
            6, 7, 10, 11, 10, 31, 6, 35, 2, 31, 2, 11,      //第1笔
            36, 7, 40, 11, 40, 31, 36, 35, 32, 31, 32, 11,  //第2笔
            7, 36, 11, 32, 31, 32, 35, 36, 31, 40, 11, 40,  //第3笔
            6, 37, 10, 41, 10, 61, 6, 65, 2, 61, 2, 41,     //第4笔
            36, 37, 40, 41, 40, 61, 36, 65, 32, 61, 32, 41, //第5笔
            7, 66, 11, 62, 31, 62, 35, 66, 31, 70, 11, 70 }; //第6笔
    
        for (int iSeg = 0; iSeg < 7; iSeg++)
        {
            if (fSevenSegment[iNumber][iSeg])
            {
                Polygon(hdc, ptSegment[iSeg], 6);
            }
        }
    }
    void DisplayTwoDigits(HDC hdc, int iNumber, BOOL fSuppress)
    {
        //将0显示为“ 0”或“00”
        if (!fSuppress || (iNumber / 10 != 0))
            DisplayDigit(hdc, iNumber / 10);  //执行到这里,0显示为“00”
        OffsetWindowOrgEx(hdc, -42, 0, NULL);
        DisplayDigit(hdc, iNumber % 10);
        OffsetWindowOrgEx(hdc, -42, 0, NULL);//每个数字的宽度为42个像素
    }
    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);  //冒号的宽度为12像素
    }
    void DisplayTime(HDC hdc, BOOL f24Hour, BOOL fSuppress)
    {
        SYSTEMTIME st;
        GetLocalTime(&st);
        //显示小时,24小时格式变或12小时格式
        if (f24Hour)
        {
            DisplayTwoDigits(hdc, st.wHour, fSuppress);
        }
        else
        {
            //12小时格式,将01224,统一显示为12
            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;
        TCHAR  szBuffer[2];
        HDC         hdc;
        PAINTSTRUCT ps;
    
        switch (message)
        {
        case WM_CREATE:
            SetTimer(hwnd, ID_TIMER, 1000, NULL);
            hBrushRed = CreateSolidBrush(RGB(255, 0, 0));
            //继续执行
        case WM_SETTINGCHANGE:
            //获得是否是24小时格式
            GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ITIME, szBuffer, 2);
            f24Hour = (szBuffer[0] == '1');
            //获取是否显示小时的第1个0.
            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);//共6个数字,每个数字宽42,2对显号,每对宽12
            SetViewportExtEx(hdc, cxClient, cyClient, NULL);
            //输出中心移动到客户区中央
            SetWindowOrgEx(hdc, 138, 36, NULL);
            SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);
            SelectObject(hdc, GetStockObject(NULL_PEN));
            SelectObject(hdc, (HGDIOBJ)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);
    }
     8.3.2 模拟时钟

    (1)坐标系统的设置——各向同性、y轴向上为正,坐标轴原点在客户区中央。

        ①逻辑窗口范围(1000,1000)

        ②视口范围(cxClient/2,cyClient/2);

    (2)坐标旋轴——用来画刻度和时分针

    (3)stPrevious用来判断小时和分钟是否要更新。如果要,用白色画笔在之前的时间位置重绘一遍,相于当抹掉。如果不需要,只有秒针被抹掉。然后,用黑笔画所有指针一次。

    【Clock程序】
    效果图

    /*------------------------------------------------------------
    CLOCK.C -- Analog Clock Program
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    #include <windows.h>
    #include <math.h>
    #define  TWOPI (2*3.14159)
    #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("Clock");
        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,                  // window class name
            TEXT("Analog Clock"),      // window caption
            WS_OVERLAPPEDWINDOW,        // window style
            CW_USEDEFAULT,              // initial x position
            CW_USEDEFAULT,              // initial y position
            CW_USEDEFAULT,              // initial x size
            CW_USEDEFAULT,              // initial y size
            NULL,                       // parent window handle
            NULL,                       // window menu handle
            hInstance,                  // program instance handle
            NULL);                     // creation parameters
    
        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); //y轴向上为正
        SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL); //坐标原点位于客户区中央
    }
    void RotatePoint(POINT pt[], int iNum, int iAngle)
    {
        POINT ptTemp;
        for (int i = 0; i < iNum; i++)
        {
            ptTemp.x = (int)(pt[i].x*cos(iAngle*TWOPI / 360) + pt[i].y*sin(iAngle*TWOPI / 360));
            ptTemp.y = (int)(pt[i].y*cos(iAngle*TWOPI / 360) - pt[i].x*sin(iAngle*TWOPI / 360));
            pt[i] = ptTemp;
        }
    }
    //画针面的刻度
    void DrawClock(HDC hdc)
    {
        POINT pt[3];
        for (int 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; //圆的大小(直径)
    
            //Ellipse左上角的点
            pt[0].x -= pt[2].x / 2;
            pt[0].y -= pt[2].y / 2;
            //Ellipse右下角的点
            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 iAngle[3];
        POINT ptTemp[3][5];
        iAngle[0] = (pst->wHour * 30) % 360 + pst->wMinute / 2; //时针每小时30度。
        iAngle[1] = pst->wMinute * 6; //每分钟,分针走6度。
        iAngle[2] = pst->wSecond * 6; //每秒,秒针走6度。
    
        memcpy(ptTemp, pt, sizeof(pt));
        for (int 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)
    {
        HDC         hdc;
        PAINTSTRUCT ps;
        static SYSTEMTIME stPrevious;
        BOOL fChange;
        SYSTEMTIME st;
        static int cxClient, cyClient;
    
        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.wMinute;
    
            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);
    }

    8.4 在状态报告上使用计时器

    (1)窗口固定大小:其大小从自定义的FindWindowSize函数求得。窗口风格WS_BORDER。

    (2)创建屏幕DC,程序可以从屏幕任何地方获得当前鼠标指针位置的像素颜色。

    【WhatClr程序】

    效果图

    /*------------------------------------------------------------
    WHATCLR.C -- Displays Color Under Cursor
    (c) Charles Petzold, 1998
    ------------------------------------------------------------*/
    #include <windows.h>
    #define ID_TIMER 1
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    void FindWindowSize(int*, int*);
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        PSTR szCmdLine, int iCmdShow)
    {
        static TCHAR szAppName[] = TEXT("WhatClr");
        HWND         hwnd;
        MSG          msg;
        WNDCLASS     wndclass;
        int cxWindow, cyWindow;
        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;
        }
    
        FindWindowSize(&cxWindow, &cyWindow);
        hwnd = CreateWindow(szAppName,                  // window class name
            TEXT("What Color"), // window caption
            WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER,        // window style
            CW_USEDEFAULT,              // initial x position
            CW_USEDEFAULT,              // initial y position
            cxWindow,                   // initial x size
            cyWindow,              // initial y size
            NULL,                       // parent window handle
            NULL,                       // window menu handle
            hInstance,                  // program instance handle
            NULL);                     // creation parameters
    
        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); //屏幕hdc
        GetTextMetrics(hdcScreen, &tm);
        DeleteDC(hdcScreen);
        *pcxWindow = 2 * GetSystemMetrics(SM_CXBORDER) + 12 * tm.tmAveCharWidth; //宽度=2个边框加12个字符的宽度
        *pcyWindow = 2 * GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYCAPTION) + 2 * tm.tmHeight;;
    }
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        static HDC hdcScreen;
        static COLORREF cr, crLast;
        POINT pt;
        TCHAR szBuffer[16];
        HDC         hdc;
        PAINTSTRUCT ps;
        RECT        rect;
    
        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);
            if (cr != crLast)
            {
                crLast = cr;
                InvalidateRect(hwnd, NULL, TRUE);
            }
            return 0;
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
    
            GetClientRect(hwnd, &rect);
            wsprintf(szBuffer, TEXT(" %02X %02X %02X "), GetRValue(cr), GetGValue(cr), GetBValue(cr));
            DrawText(hdc, szBuffer, -1, &rect,
                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);
    }
  • 相关阅读:
    Linux上查找最大文件的 3 种方法
    不念过去,不畏将来
    Weblogic/WAS之Full GC监控与计算
    EntityFramework:An error occurred while executing the command definition. See the inner exception for details.
    1051 复数乘法(C#)
    BACnet开发资料与调试工具
    JS设置cookie、读取cookie、删除cookie
    认识BACnet协议
    Unity WebGL请求Http接口出现的Cors跨域问题
    VS 2017 产品密钥
  • 原文地址:https://www.cnblogs.com/5iedu/p/4658911.html
Copyright © 2011-2022 走看看