A common problem when drawing with GDI in VC++ is that the screen might flicker when you’re doing a lot of drawing. This problem can be overcome by drawing on a so called back buffer. The back buffer is then drawn at once.
I’ve created a Win32 project in VC++ to demonstrate this. The first example draws a rectangle on the screen without using a back buffer. This illustrates the flickering. The second example draws the rectangle on the back buffer and displays it on the screen.
Drawing a rectangle without using a back buffer
A brush has been created within the WndProc function for drawing the rectangle.
HBRUSH hRectangleBrush = CreateSolidBrush(RGB(0,0,0));
The WM_PAINT case statement has been modified to draw the rectangle.
case WM_PAINT: // Get the device context hdc = BeginPaint(hWnd, &ps); // Select the rectangle brush SelectObject(hdc,hRectangleBrush); // Draw the rectangle Rectangle(hdc,0,0,20,20); // Repaint the screen InvalidateRect(hWnd,NULL,true); EndPaint(hWnd, &ps); break;
The picture below illustrates the rectangle being drawn when you run the program.
Flickering should occur and this is unwanted if you would like to have smooth graphics.
Drawing a rectangle using a back buffer
The following global variables are defined.
RECT rect; // Struct for the window width and height HDC hdc; // Device context HDC hdcBackBuffer; // Back buffer device context HBRUSH hRectangleBrush = CreateSolidBrush(RGB(0,0,0)); // Rectangle brush int width, height; // Window width and height HBITMAP hBitmap; // Bitmap
WndProc additionally contains a WM_CREATE case statement and WM_PAINT has been modified.
case WM_CREATE: // Get the width and height of the window GetClientRect(hWnd,&rect); width = rect.right; height = rect.bottom; // Create the back buffer hdcBackBuffer = CreateCompatibleDC(NULL); // Get the device context hdc = GetDC(hWnd); // Create a bitmap hBitmap = CreateCompatibleBitmap(hdc, width, height); // Select the bitmap SelectObject(hdcBackBuffer, hBitmap); ReleaseDC(hWnd, hdc); break;
case WM_PAINT: // Get the device context hdc = BeginPaint(hWnd, &ps); BitBlt(hdcBackBuffer,0,0,width,height, NULL, NULL, NULL, WHITENESS); // Select the rectangle brush SelectObject(hdcBackBuffer,hRectangleBrush); // Draw the rectangle on the back buffer Rectangle(hdcBackBuffer,0,0,20,20); // Display the back buffer BitBlt(hdc, 0, 0, width, height, hdcBackBuffer, 0, 0, SRCCOPY); // Repaint the screen InvalidateRect(hWnd,NULL,false); EndPaint(hWnd, &ps); break;
Drawing should now be done on the back buffer and the back buffer should in turn be displayed on the screen as a bitmap. Moving the rectangle at a certain interval should also demonstrate that there is no flickering.
You may download the VS 2010 project from here.