Search code examples
c++framegdi+flush

C++ GDI+ clearing previous screen


So I'm trying to draw my cursor's position next to it, and so far it's working pretty well. Expect that it sometimes leaves a "trail" from the previous frames, so I'm wondering how could I clear them? Is there a quick trick to do so?

Here's a quick GIF: https://i.imgur.com/uVrzi0m.gif

Here's my code:

void DrawCursorCoords(Gdiplus::Graphics &graphics, Gdiplus::Font &font, Gdiplus::Brush &brush)
{
    POINT cursorPos;
    GetCursorPos(&cursorPos);

    std::wstring x = std::to_wstring(cursorPos.x);
    std::wstring y = std::to_wstring(cursorPos.y);

    graphics.DrawString(x.c_str(), x.length(), &font, Gdiplus::PointF(cursorPos.x, cursorPos.y), &brush);
    graphics.DrawString(y.c_str(), y.length(), &font, Gdiplus::PointF(cursorPos.x, cursorPos.y + 50), &brush);
}


int main()
{
    // Start GDI+
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    // Initialize graphics, brushes etc...
    HWND hWnd = GetDesktopWindow();
    HDC hdc = GetDC(hWnd);
    Gdiplus::Graphics * gfx = new Gdiplus::Graphics(hdc);
    Gdiplus::Pen * pen = new Gdiplus::Pen(Gdiplus::Color(255, 0, 255));
    Gdiplus::Font * cursorFont = new Gdiplus::Font(L"Consolas", 16);
    Gdiplus::SolidBrush * cursorBrush = new Gdiplus::SolidBrush(Gdiplus::Color(255, 0, 0, 150));
    Gdiplus::SolidBrush * clearBrush = new Gdiplus::SolidBrush(Gdiplus::Color::Transparent);

    while (!GetAsyncKeyState(VK_INSERT))
    {
        printf("Drawing!\n");

        DrawCursorCoords(*gfx, *cursorFont, *cursorBrush);

        // 1. Super slow + just fills the screen black
        //gfx->Clear(Gdiplus::Color::Transparent);

        // 2. Doesn't "flush" anything?
        //gfx->Flush();

        // 3. Super slow + does nothing
        //gfx->FillRectangle(clearBrush, Gdiplus::Rect(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)));
    }

    printf("Stopped drawing!\n");

    delete gfx;
    delete pen;
    delete cursorFont;
    delete cursorBrush;
    delete clearBrush;
    ReleaseDC(hWnd, hdc);
    Gdiplus::GdiplusShutdown(gdiplusToken);

    return 0;
}

Solution

  • You are not supposed to draw on desktop. You should draw in your own window only. If you draw on desktop, or anybody else's window, it will get cleared the next paint cycle for that window. It is not possible to control that.

    You cannot draw on the console either. The Windows console has its own window and its own paint routine which is not accessible. The console does provide a number of functions such as SetConsoleCursorPosition to allow printing text at various positions.

    Example:

    #include <Windows.h>
    #include <iostream>
    
    int main()
    {
        HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);
        while(true)
        {
            COORD coord = { 0, 0 };
            SetConsoleCursorPosition(hout, coord);
            std::cout << "Move the mouse and click a key\n";
            system("pause");
    
            POINT pt;
            GetCursorPos(&pt);
            HWND hwnd = GetConsoleWindow();
    
            RECT rc;
            GetClientRect(hwnd, &rc);
            ScreenToClient(hwnd, &pt);
    
            CONSOLE_SCREEN_BUFFER_INFO inf;
            GetConsoleScreenBufferInfo(hout, &inf);
    
            coord.X = (SHORT)MulDiv(pt.x, inf.srWindow.Right, rc.right);
            coord.Y = (SHORT)MulDiv(pt.y, inf.srWindow.Bottom, rc.bottom);
    
            SetConsoleCursorPosition(hout, coord);
            std::cout << "X";
        }
        return 0;
    }
    

    The console has limited drawing options. For actual drawing, you have to create a window using CreateWindow, and a window message loop to respond to WM_PAINT for painting, as well as handling other window messages.

    See Walkthrough: Creating Windows Desktop Applications for introduction to windows programming, or see an introductory book to Windows programming.