Condividi tramite


Disegno a intervalli di tempo

È possibile disegnare a intervalli temporali creando un timer con la funzione SetTimer . Usando un timer per inviare messaggi WM_TIMER alla routine finestra a intervalli regolari, un'applicazione può eseguire un'animazione semplice nell'area client mentre altre applicazioni continuano a essere in esecuzione.

Nell'esempio seguente l'applicazione rimbalza un star da un lato all'altro nell'area client. Ogni volta che la routine della finestra riceve un messaggio di WM_TIMER, la routine cancella il star nella posizione corrente, calcola una nuova posizione e disegna il star all'interno della nuova posizione. La procedura avvia il timer chiamando SetTimer durante l'elaborazione del messaggio WM_CREATE .

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); 
} 

Questa applicazione usa un contesto di dispositivo privato per ridurre al minimo il tempo necessario per preparare il contesto del dispositivo per il disegno. La procedura della finestra recupera e inizializza il contesto del dispositivo privato durante l'elaborazione del messaggio WM_CREATE, impostando la modalità di operazione raster binaria per consentire l'cancellazione e il disegno della star usando la stessa chiamata alla funzione Polyline. La routine della finestra imposta anche l'origine del riquadro di visualizzazione per consentire il disegno del star utilizzando lo stesso set di punti indipendentemente dalla posizione del star nell'area client.

L'applicazione usa il messaggio WM_PAINT per disegnare il star ogni volta che la finestra deve essere aggiornata. La routine della finestra disegna il star solo se non è visibile, ovvero solo se è stato cancellato dal messaggio di WM_ERASEBKGND. La routine della finestra intercetta il messaggio WM_ERASEBKGND per impostare la variabile fVisible , ma passa il messaggio a DefWindowProc in modo che il sistema possa disegnare lo sfondo della finestra.

L'applicazione usa il messaggio WM_SIZE per arrestare il timer quando la finestra è ridotta a icona e riavviare il timer quando viene ripristinata la finestra ridotta a icona. La routine della finestra usa anche il messaggio per aggiornare la posizione corrente del star se le dimensioni della finestra sono state ridotte in modo che il star non sia più presente nell'area client. L'applicazione tiene traccia della posizione corrente del star usando la struttura specificata da rcCurrent, che definisce il rettangolo di delimitazione per il star. Mantenere tutti gli angoli del rettangolo nell'area client mantiene la star nell'area. La routine della finestra centra inizialmente il star nell'area client durante l'elaborazione del messaggio WM_CREATE.