WinAPI. Can't erase window background with ellipse

I am just trying to draw an ellipse:

case WM_PAINT:
        hdc = BeginPaint(parentWindow, &ps);
        Ellipse(hdc, x, y, width, height);
        EndPaint(parentWindow, &ps);

      

and then remove it with a new ellipse with new parameters every second using a timer:

case WM_CREATE:
        SetTimer(hWnd, 1, 1000, NULL);
        break;
case WM_TIMER:
        x += 5;
        InvalidateRect(hWnd, NULL, TRUE);
        break;

      

But the ellipses are not erased and are layered:

Ellipses

However, I tried to keep track of WM_ERASEBKGND and it does indeed get sent every InvalidateRect.

Complete code:

#include <Windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <iostream>


TCHAR szWindowClass[] = TEXT("CreateThreadWindow");
TCHAR szAppName[] = TEXT("CreateThreadExample");

BOOL InitWindow(HINSTANCE, int);
ATOM MyRegisterClass(HINSTANCE);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

HWND parentWindow;
MSG msg;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MyRegisterClass(hInstance);
    if (!InitWindow(hInstance, nCmdShow))
        return FALSE;
    BOOL bRet;
    while ((bRet = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0)
    {
        if (bRet == -1)
            return FALSE;
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASS wndClass;
    memset(&wndClass, 0, sizeof(wndClass));
    wndClass.lpfnWndProc = WndProc;
    wndClass.hInstance = hInstance;
    wndClass.lpszMenuName = NULL;
    wndClass.lpszClassName = szWindowClass;
    return RegisterClass(&wndClass);
}

BOOL InitWindow(HINSTANCE hInstance, int nCmdShow)
{
    parentWindow = CreateWindow(szWindowClass, szAppName, WS_OVERLAPPEDWINDOW,
        300, 0, 600, 600, NULL, NULL, hInstance, NULL);
    ShowWindow(parentWindow, nCmdShow);
    return TRUE;
}



LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    static int x = 0, y = 0, width = 200, height = 100;
    switch (message) {
    case WM_ERASEBKGND:
        _RPT1(0, "%s\n", "erase");
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        Ellipse(hdc, x, y, width, height);
        EndPaint(hWnd, &ps);
        break;
    case WM_CREATE:
        SetTimer(hWnd, 1, 1000, NULL);
        break;
    case WM_TIMER:
        x += 5;
        InvalidateRect(hWnd, NULL, TRUE);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hWnd, message, wparam, lparam);
    }
}

      

+3


source to share


1 answer


Your code doesn't erase anything. It just draws an ellipse at the specified coordinates. The previously drawn ellipse still exists.

You mentioned the post WM_ERASEBKGND

, but there are two reasons why this doesn't work for you:

  • In your window procedure ( WndProc

    ), you handle the message WM_ERASEBKGND

    explicitly, which means it does not go to the default window procedure ( DefWindowProc

    ). The best way to write your window procedure would be as follows:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
    {
        static int x = 0, y = 0, width = 200, height = 100;
        switch (message) {
        case WM_ERASEBKGND:
        {
            _RPT1(0, "%s\n", "erase");
            break;
        }
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            Ellipse(hdc, x, y, width, height);
            EndPaint(hWnd, &ps);
            return 0;
        }
        case WM_CREATE:
        {
            SetTimer(hWnd, 1, 1000, NULL);
            break;
        }
        case WM_TIMER:
        {
            x += 5;
            InvalidateRect(hWnd, NULL, TRUE);
            return 0;
        }
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        }
        default:
            break;
        }
    
        return DefWindowProc(hWnd, message, wparam, lparam);
    }
    
          

    Now the default window procedure is called every time unless you explicitly specify return

    inside the label case

    .

  • When you register your window class (internally MyRegisterClass

    ), you zero out all the fields of the structure WNDCLASS

    and then explicitly initialize a couple of them. You are not explicitly initializing the field hbrBackground

    , so it is set to 0. And when it hbrBackground

    is 0,

    When this member is given NULL

    , the application must paint its own background whenever it is asked to paint in its client area. To determine if the background should be colored, the application can process the message WM_ERASEBKGND

    or check the fErase

    structure member PAINTSTRUCT

    filled with the function BeginPaint

    .

    This means that the default window procedure does nothing in response to the message WM_ERASEBKGND

    because you didn't give your window a background brush.

    You either need to set hbrBackground

    to something like COLOR_WINDOW + 1

    , or you will need to add code to the message handler WM_ERASEBKGND

    to erase the background of the background yourself.



Or perhaps an even better option would be to forget about the message WM_ERASEBKGND

altogether, as many Windows programmers do, because this two-step erase and paint method tends to cause flicker. Leave the field hbrBackground

NULL, do nothing in response to the message, WM_ERASEBKGND

and remove it at the top of the handler WM_PAINT

:

case WM_PAINT:
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);

    // Erase background of entire client area.
    RECT rcClient;
    GetClientRect(hWnd, &rcClient);
    FillRect(hdc, &rcClient, reinterpret_cast<HBRUSH>(COLOR_WINDOW+1));

    // Do normal drawing.
    Ellipse(hdc, x, y, width, height);

    EndPaint(hWnd, &ps);
    return 0;
}

      

+5


source







All Articles