以定时间隔绘制

可以通过使用 SetTimer 函数创建计时器,按定时间隔绘制。 通过使用计时器定期向窗口过程发送 WM_TIMER 消息,应用程序可以在其他应用程序继续运行时在工作区中执行简单的动画。

在以下示例中,应用程序在工作区中将star从一边弹跳到另一边。 每当窗口过程收到WM_TIMER消息时,该过程都会擦除当前位置的star,计算新位置,并绘制新位置内的star。 该过程通过在处理WM_CREATE消息时调用 SetTimer 来启动计时器。

RECT rcCurrent = {0,0,20,20}; 
POINT aptStar[6] = {10,1, 1,19, 19,6, 1,6, 19,19, 10,1}; 
int X = 2, Y = -1, idTimer = -1; 
BOOL fVisible = FALSE; 
HDC hdc; 
 
LRESULT APIENTRY WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    PAINTSTRUCT ps; 
    RECT rc; 
 
    switch (message) 
    { 
        case WM_CREATE: 
 
            // Calculate the starting point.  
 
            GetClientRect(hwnd, &rc); 
            OffsetRect(&rcCurrent, rc.right / 2, rc.bottom / 2); 
 
            // Initialize the private DC.  
 
            hdc = GetDC(hwnd); 
            SetViewportOrgEx(hdc, rcCurrent.left, 
                rcCurrent.top, NULL); 
            SetROP2(hdc, R2_NOT); 
 
            // Start the timer.  
 
            SetTimer(hwnd, idTimer = 1, 10, NULL); 
            return 0L; 
 
        case WM_DESTROY: 
            KillTimer(hwnd, 1); 
            PostQuitMessage(0); 
            return 0L; 
 
        case WM_SIZE: 
            switch (wParam) 
            { 
                case SIZE_MINIMIZED: 
 
                    // Stop the timer if the window is minimized. 
 
                    KillTimer(hwnd, 1); 
                    idTimer = -1; 
                    break; 
 
                case SIZE_RESTORED: 
 
                    // Move the star back into the client area  
                    // if necessary.  
 
                    if (rcCurrent.right > (int) LOWORD(lParam)) 
                    {
                        rcCurrent.left = 
                            (rcCurrent.right = 
                                (int) LOWORD(lParam)) - 20; 
                    }
                    if (rcCurrent.bottom > (int) HIWORD(lParam)) 
                    {
                        rcCurrent.top = 
                            (rcCurrent.bottom = 
                                (int) HIWORD(lParam)) - 20; 
                    }
 
                    // Fall through to the next case.  
 
                case SIZE_MAXIMIZED: 
 
                    // Start the timer if it had been stopped.  
 
                    if (idTimer == -1) 
                        SetTimer(hwnd, idTimer = 1, 10, NULL); 
                    break; 
            } 
            return 0L; 
 
        case WM_TIMER: 
 
            // Hide the star if it is visible.  
 
            if (fVisible) 
                Polyline(hdc, aptStar, 6); 
 
            // Bounce the star off a side if necessary.  
 
            GetClientRect(hwnd, &rc); 
            if (rcCurrent.left + X < rc.left || 
                rcCurrent.right + X > rc.right) 
                X = -X; 
            if (rcCurrent.top + Y < rc.top || 
                rcCurrent.bottom + Y > rc.bottom) 
                Y = -Y; 
 
            // Show the star in its new position.  
 
            OffsetRect(&rcCurrent, X, Y); 
            SetViewportOrgEx(hdc, rcCurrent.left, 
                rcCurrent.top, NULL); 
            fVisible = Polyline(hdc, aptStar, 6); 
 
            return 0L; 
 
        case WM_ERASEBKGND: 
 
            // Erase the star.  
 
            fVisible = FALSE; 
            return DefWindowProc(hwnd, message, wParam, lParam); 
 
        case WM_PAINT: 
 
            // Show the star if it is not visible. Use BeginPaint  
            // to clear the update region.  
 
            BeginPaint(hwnd, &ps); 
            if (!fVisible) 
                fVisible = Polyline(hdc, aptStar, 6); 
            EndPaint(hwnd, &ps); 
            return 0L; 
    } 
    return DefWindowProc(hwnd, message, wParam, lParam); 
} 

此应用程序使用专用设备上下文来最大程度地减少准备设备上下文进行绘制所需的时间。 窗口过程在处理WM_CREATE消息时检索和初始化专用设备上下文,并将二进制光栅操作模式设置为允许使用对 Polyline 函数的相同调用擦除和绘制star。 窗口过程还设置视区原点,以允许使用同一组点绘制star,而不考虑star在工作区中的位置。

每当必须更新窗口时,应用程序都会使用WM_PAINT消息绘制star。 仅当窗口过程不可见时,窗口过程才会绘制star;也就是说,仅当它已被WM_ERASEBKGND消息擦除时。 窗口过程截获 WM_ERASEBKGND 消息以设置 fVisible 变量,但将消息传递给 DefWindowProc ,以便系统可以绘制窗口背景。

应用程序使用 WM_SIZE 消息在最小化窗口时停止计时器,并在还原最小化窗口时重新启动计时器。 如果窗口的大小已减小,使star不再位于工作区中,窗口过程还会使用 消息更新star的当前位置。 应用程序通过使用 rcCurrent 指定的结构跟踪star的当前位置,该结构定义star的边框。 将矩形的所有角保留在工作区中,使star保留在该区域中。 处理WM_CREATE消息时,窗口过程最初将工作区中的star居中