How to delete drawing from a window?

Davit 136 Reputation points
2020-11-15T17:11:15.38+00:00

Hi,

I have a transparent window:

SetLayeredWindowAttributes(window, RGB(255, 255, 255), 0, LWA_COLORKEY);

and I have some drawing in WM_PAINT

hdc = BeginPaint(hwnd, &ps);

HPEN OldPen = (HPEN)SelectObject(hdc, *currentPen);

//just an example
MoveToEx(hdc, 50, 50, NULL);
LineTo(hdc, 450, 450);

SelectObject(hdc, OldPen);

EndPaint(hwnd, &ps);

How do I delete the drawing? I am calling InvalidateRect(hwnd, NULL, TRUE);:

void DeleteDrawing() 
{
// I need to delete the drawing here
InvalidateRect(hwnd, NULL, TRUE);
}

but this doesn't work.

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,575 questions
0 comments No comments
{count} votes

Accepted answer
  1. Davit 136 Reputation points
    2020-11-17T15:47:47.523+00:00

    I deleted the drawing by handling WM_ERASEBBKGND. Calling InvalidateRect inside DeleteDrawing will trigger WM_ERASEBBKGND. And on WM_ERASEBBKGND I do this:

    case WM_ERASEBKGND:
        {
            RECT rcWin;
            RECT rcWnd;
            HWND parWnd = GetParent( hwnd ); // Get the parent window.
            HDC parDc = GetDC( parWnd ); // Get its DC.
    
            GetWindowRect( hwnd, &rcWnd );
            ScreenToClient( parWnd, &rcWnd ); // Convert to the parent's co-ordinates
    
            GetClipBox(hdc, &rcWin );
            // Copy from parent DC.
            BitBlt( hdc, rcWin.left, rcWin.top, rcWin.right - rcWin.left,
                rcWin.bottom - rcWin.top, parDC, rcWnd.left, rcWnd.top, SRC_COPY );
    
            ReleaseDC( parWnd, parDC );
        }
    
    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Viorel 116.5K Reputation points
    2020-11-15T17:35:49.297+00:00

    Maybe you need something like this:

    bool cleared; // a member or static variable; must be set initially to false
    
    // WM_PAINT:
    hdc = BeginPaint(hwnd, &ps);
    if( ! cleared )
    {
       painting . . .
    }
    EndPaint(hwnd, &ps);
    
    // Clearing:
    cleared = true;
    InvalidateRect(hwnd, NULL, TRUE);
    

  2. Drake Wu - MSFT 991 Reputation points
    2020-11-16T03:35:11.32+00:00

    Hi, @Davit First, InvalidateRect function can indirectly generate WM_PAINT messages for your windows and execute your code in WM_PAINT again.

    How to delete the drawing depends on how you draw it. If you only collect the start and end points as in the second sample, then you only need to invalidate those points in DeleteDrawing() ,like: x=y=-1:

    void DeleteDrawing(HWND hwnd)  
    {  
        m_drawStart = { -1,-1 };  
        m_drawEnd = { -1,-1 };  
        InvalidateRect(hwnd, NULL, TRUE);  
    }  
    

    And when processing the WM_PAINT message, check the POINTS if they are valid. (This is actually similar to @Viorel 's bool cleared)

    I am not sure how to store objects

    If you want to collect not only the start and end points, but a collection of as many points as possible that mouse has moved:

    static std::vector<POINT> m_draw;  
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
    {  
        switch (message)  
        {  
        ...  
        case WM_LBUTTONDOWN:  
        {  
            SetTimer(hWnd, 1, 10, 0);//Send WM_TIMER message every 10ms to collect current mouse point  
            POINT pt;  
            pt.x = GET_X_LPARAM(lParam);  
            pt.y = GET_Y_LPARAM(lParam);  
            m_draw.push_back(pt);  
        }  
        break;  
        case WM_TIMER:  
        {  
            POINT p;  
            GetCursorPos(&p);  
            ScreenToClient(hWnd,&p);  
            m_draw.push_back(p);  
        }  
        break;  
        case WM_LBUTTONUP:  
        {  
            KillTimer(hWnd,1); //stop collection  
            POINT pt;  
            pt.x = GET_X_LPARAM(lParam);  
            pt.y = GET_Y_LPARAM(lParam);  
            m_draw.push_back(pt);  
            InvalidateRect(hWnd, NULL, FALSE);//Do not erase the background to keep the previous image  
        }  
        break;  
        case WM_PAINT:  
        {  
            PAINTSTRUCT ps;  
            HDC hdc = BeginPaint(hWnd, &ps);  
            // TODO: Add any drawing code that uses hdc here...  
            HPEN currentPen = CreatePen(PS_SOLID,4, RGB(255, 0, 0));  
            HPEN OldPen = (HPEN)SelectObject(hdc, currentPen);  
            //just an example  
            if (!m_draw.empty())  
            {  
                if (m_draw.size() == 1)  
                {  
                    MoveToEx(hdc, m_draw[0].x, m_draw[0].y, NULL);  
                    LineTo(hdc, m_draw[0].x, m_draw[0].y);  
                }  
                else  
                {  
                    for (int i = 0; i < m_draw.size() - 1; i++)  
                    {  
                        MoveToEx(hdc, m_draw[i].x, m_draw[i].y, NULL);  
                        LineTo(hdc, m_draw[i + 1].x, m_draw[i + 1].y);  
                    }  
                }  
            }  
            SelectObject(hdc, OldPen);  
            DeleteObject(currentPen);  
            m_draw.clear();  
            EndPaint(hWnd, &ps);  
        }  
        break;  
        ...  
        return 0;  
    }  
    

    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.