using a backbuffer but still getting flicker

hello everyone,
i'm hoping someone can help me with this problem. i'm attempting to draw in a window without flicker. the stuff i've read indicates a bacbuffer be used and it BitBlt'd to the actual w as the final act before returning FALSE to windows. a simple program: left click anywhere in its window and a bitmap will be drawn there. Quickly pressing left mouse button and it flickers.

Also if an obscuring window dragged downwards and exposing this window it violently flickers! - i've solved this particular problem.

What is this newbie missing, please.

http://www.catch22.net/tuts/flicker-free-drawing
Last edited on
Can you show us the code. Without code it's impossible to know what's wrong.
thanks for replying. it's 12,000 chars too big to show here limit being 8192. should i zip it or remove some bits of code?
You could upload it to DropBox or sth. else.

Another option is to split it over 2 posts
/*
see mousetest for getting cursor clicked pos
next job - use backbuffer to remove flicker

Hmmm! doesn't stop flicker if left mouse button clicked fast
or if an obscuring window dragged downwards and exposing this window!
*/
#include <windows.h>

// create mem leak report in Debug tab of 'Output' tab of Visual Studio
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>


#define IDI_ICON1 101
#define IDB_BITMAP1 102

HINSTANCE hInst;

//byte IX, IY;
WORD IX= 25;
WORD IY= 30;

int flag = 0;


void DrawHello2 ( HWND hwnd, WPARAM wParam, LPARAM lParam, int flag )
{
// uses a backbuffer - should be no flicker but there is.
// placing a breakpoint at
//BitBlt-1 and/or
//BitBlt-2
// below proves nothing direct to screen!?
HDC hDC1;
HBITMAP hBitmap, hBitmap2;
HPALETTE hPalette;
BITMAP bm2;
PAINTSTRUCT ps;

RECT xrect, xrect2;
HDC hBkbDC, hBkbDC2;
int hbkmd, hgetsysc;
HGDIOBJ hBrush = 0, hsavsel = 0, hsavsel2 = 0;
COLORREF colref;
int RGB1 = 0x080; // red
int RGB2 = 0x80FFFF; // yellow
int RGB3 = 0xFFFF80; // cyan
int RGB4 = 0x8F8F80; // grey
int RGB5 = 0xEE8844; //
int RGB6 = 0x88AACC; //
int RGB7 = 0x00FF00; //
int RGB8 = 0x0; //
int RGB9 = 0x0FFFFFF; //
int icbmx = 0;
int icbmy = 0;
int inty = 0;
int nXbmp = 190;
int nYbmp = 70;
int intb = 0;
LPCTSTR lpszImg2;

hPalette = 0;

hDC1 = BeginPaint ( hwnd, &ps ); // when DrawHello replaced with DrawHello2

if (hDC1 != NULL) {

// Followimg so we can copy backbuffer hBitmap to actual screens bitmap buffer
GetClientRect( (HWND) hwnd, &xrect );
icbmx = xrect.right - xrect.left;
icbmy = xrect.bottom - xrect.top;
hBitmap = CreateCompatibleBitmap ( hDC1, icbmx, icbmy );
// Select that bitmap into the object, preserve old for DeleteDC
hBkbDC = CreateCompatibleDC ( hDC1 ); // Create a compatible DC
hsavsel = SelectObject ( hBkbDC, hBitmap );

if ( flag ) {

//+++ Followimg just to draw text in the Client area
hgetsysc = GetSysColor ( COLOR_WINDOW );
hBrush = CreateSolidBrush ( hgetsysc ); // without this no colour chg

colref = SetTextColor ( (HDC) hBkbDC, RGB1 );
if ( colref == CLR_INVALID ) {
inty = 0;
}
colref = SetBkColor ( (HDC) hBkbDC, RGB5 );
if ( colref == CLR_INVALID ) {
inty = 0;
}
hbkmd = SetBkMode ( (HDC) hBkbDC, TRANSPARENT ); // 0=OPAQUE, 1=TRANSPARENT, 2=text bkgnd
// erase main window and backbuffer.
FillRect ( hDC1, &xrect, (HBRUSH) hBrush ); // clear screen
FillRect ( hBkbDC, &xrect, (HBRUSH) hBrush ); // clear backbuff

hbkmd = SetBkMode ( (HDC) hBkbDC, TRANSPARENT ); // 0=OPAQUE, 1=TRANSPARENT, 2=text bkgnd
hgetsysc = GetSysColor ( COLOR_BTNFACE );
SetRect( &xrect2, 30, 60, 140, 90 );
hBrush = CreateSolidBrush ( RGB3 ); // without this no colour chg
DrawText ( (HDC) hBkbDC, "this is no flicker", 18, &xrect2, DT_CENTER );
DeleteObject ( hBrush );

hBkbDC2 = CreateCompatibleDC( NULL );

lpszImg2 = "C:\\cpp\\HiyaWin4\\Iantreemx.bmp";
hBitmap2 = (HBITMAP )LoadImage (0, lpszImg2, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_DEFAULTSIZE );
intb = GetObject( hBitmap2, sizeof(BITMAP), &bm2 );
SetBkMode ( hBkbDC2, TRANSPARENT );
hsavsel2 = SelectObject ( hBkbDC2, hBitmap2 );
inty = BitBlt ( hBkbDC, 100, 0, 200, 220, hBkbDC2, 0, 0, SRCAND ); // SRCCOPY SRCPAINT
DeleteObject( hBitmap2 );
/**/
lpszImg2 = "C:\\Cpp\\HiyaWin4\\aerial1.bmp"; // no go
hBitmap2 = (HBITMAP )LoadImage (0, lpszImg2, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_DEFAULTSIZE );
intb = GetObject( hBitmap2, sizeof(BITMAP), &bm2 );
SetBkMode ( hBkbDC2, TRANSPARENT );
hsavsel2 = SelectObject ( hBkbDC2, hBitmap2 );
inty = BitBlt ( hBkbDC, IX, IY, bm2.bmWidth, bm2.bmHeight, hBkbDC2, 0, 0, SRCAND ); // SRCCOPY SRCPAINT

/*
//z direct to window, no backbuffer
inty = BitBlt ( hDC1, nXbmp, nYbmp, bm2.bmWidth, bm2.bmHeight,
hBkbDC, 0, 0, SRCAND ); // SRCCOPY SRCPAINT
// hBkbDC2, 0, 0, SRCAND ); // SRCCOPY SRCPAINT
*/


// Copy buffer to actual
icbmx = xrect.right - xrect.left;
icbmy = xrect.bottom - xrect.top;
//BitBlt-1
inty = BitBlt ( hDC1, xrect.left, xrect.top, icbmx, icbmy,
hBkbDC, 0, 0, SRCAND ); // SRCCOPY SRCPAINT

}
else {

//+++ Followimg just to draw text in the Client area
hgetsysc = GetSysColor ( COLOR_WINDOW );
hBrush = CreateSolidBrush ( hgetsysc ); // without this no colour chg

colref = SetTextColor ( (HDC) hBkbDC, RGB1 );
if ( colref == CLR_INVALID ) {
inty = 0;
}
colref = SetBkColor ( (HDC) hBkbDC, RGB5 );
if ( colref == CLR_INVALID ) {
inty = 0;
}
hbkmd = SetBkMode ( (HDC) hBkbDC, TRANSPARENT ); // 0=OPAQUE, 1=TRANSPARENT, 2=text bkgnd
// erase main window and backbuffer.
FillRect ( hDC1, &xrect, (HBRUSH) hBrush ); // clear screen
FillRect ( hBkbDC, &xrect, (HBRUSH) hBrush ); // clear backbuff

hbkmd = SetBkMode ( (HDC) hBkbDC, OPAQUE ); // 0=OPAQUE, 1=TRANSPARENT, 2=text bkgnd
hgetsysc = GetSysColor ( COLOR_BTNFACE );
SetRect( &xrect2, 0, 10, 150, 50 );
colref = SetTextColor ( (HDC) hBkbDC, RGB3 );
hBrush = CreateSolidBrush ( RGB5 ); // without this no colour chg
hbkmd = SetBkMode ( (HDC) hBkbDC, OPAQUE ); // 0=OPAQUE, 1=TRANSPARENT, 2=text bkgnd
DrawText ( (HDC) hBkbDC, "definately no flicker", 22, &xrect2, DT_RIGHT );
DeleteObject ( hBrush );


hBkbDC2 = CreateCompatibleDC( NULL );

lpszImg2 = "C:\\cpp\\HiyaWin4\\Iantreemx.bmp";
hBitmap2 = (HBITMAP )LoadImage (0, lpszImg2, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_DEFAULTSIZE );
intb = GetObject( hBitmap2, sizeof(BITMAP), &bm2 );
SetBkMode ( hBkbDC2, TRANSPARENT );
hsavsel2 = SelectObject ( hBkbDC2, hBitmap2 );
inty = BitBlt ( hBkbDC, 100, 0, 200, 220, hBkbDC2, 0, 0, SRCAND ); // SRCCOPY SRCPAINT
DeleteObject( hBitmap2 );
/**/
lpszImg2 = "C:\\Cpp\\HiyaWin4\\aerial1.bmp"; // no go
hBitmap2 = (HBITMAP )LoadImage (0, lpszImg2, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_DEFAULTSIZE );
intb = GetObject( hBitmap2, sizeof(BITMAP), &bm2 );
SetBkMode ( hBkbDC2, TRANSPARENT );
hsavsel2 = SelectObject ( hBkbDC2, hBitmap2 );
inty = BitBlt ( hBkbDC, IX, IY, bm2.bmWidth, bm2.bmHeight, hBkbDC2, 200, 130, SRCAND ); // SRCCOPY SRCPAINT

// Copy buffer to actual screens bitmap
icbmx = xrect.right - xrect.left;
icbmy = xrect.bottom - xrect.top;
//BitBlt-2
inty = BitBlt ( hDC1, xrect.left, xrect.top, icbmx, icbmy,
hBkbDC, 0, 0, SRCAND ); // SRCCOPY SRCPAINT

}

// Select old preserved into hBkbDC & DeleteDC
(HBITMAP) SelectObject ( hBkbDC, hsavsel );
DeleteObject( hBitmap );
DeleteDC ( hBkbDC ); // Delete the Compatible DC
(HBITMAP) SelectObject ( hBkbDC2, hsavsel2 );
// will NOT report memory leak on this if not DeleteObject !
DeleteObject( hBitmap2 );
DeleteDC ( hBkbDC2 ); // Delete the Compatible DC
DeleteObject ( hBrush );
}

DeleteDC( hDC1 );

EndPaint( hwnd, &ps );
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
RECT xrectW, xrectC;
POINT pnt;
HDC hDC;
PAINTSTRUCT ps;

switch(uMsg)
{
/**/
case WM_PAINT:
DrawHello2 ( hwnd, wParam, lParam, flag ); // does EndPaint

return 0; // FALSE 0: TRUE 1:

case WM_DESTROY:
PostQuitMessage(0);
break;

case WM_ERASEBKGND:
return 1;

case WM_LBUTTONDOWN:
/* */
flag = flag ^ 0x1; // XOR
GetCursorPos ( &pnt );
GetWindowRect ( hwnd, &xrectW );
GetClientRect( (HWND) hwnd, &xrectC );
(unsigned short) IX = (unsigned short) pnt.x - (unsigned short) xrectW.left;
(unsigned short) IY = (unsigned short) (pnt.y - 40) - (unsigned short) xrectW.top;
InvalidateRect ( hwnd, NULL, FALSE ); // FALSE TRUE

return 0;
break;

case WM_CTLCOLORSTATIC:
break;

case WM_CTLCOLOREDIT:
break;

default:
return DefWindowProc ( hwnd, uMsg, wParam, lParam );
}

// see WinMain _CrtSetDbgFlag for mem leak report if multiple prog exits

// _CrtDumpMemoryLeaks(); // use this if single prog exit.

return 1;
// return 0;
}

// only comes here once at start
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR d3, int nCmdShow )
{
MSG msg;
HWND hwnd;
WNDCLASS wndClass;
int * IPAddrArray;
HDC hDC;
LPCTSTR lpszImg;

// create mem leak report in Debug tab of 'Output' tab of Visual Studio
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

hInst = hInstance;

IPAddrArray = (int *)malloc(1024);
memset ( IPAddrArray, 0, 32 ); // zero it out
// free ( IPAddrArray ); // will report mem leak

if (hPrevInstance == NULL)
{
lpszImg = "C:\\cpp\\HiyaWin4\\Ist.ico";

memset(&wndClass, 0, sizeof(wndClass));
wndClass.style = 0; // CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.hInstance = hInstance;
// wndClass.hIcon = LoadIcon ( NULL, ( MAKEINTRESOURCE(32515) ) ); // IDI_WARNING
wndClass.hIcon = LoadIcon ( hInstance, ( MAKEINTRESOURCE(IDI_ICON1) ) );
wndClass.hCursor = LoadCursor ( NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndClass.lpszClassName = "HELLO";
if (!RegisterClass(&wndClass)) return FALSE;
}
hwnd = CreateWindow("HELLO", "HELLO",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 300, 250,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
DispatchMessage(&msg);
return msg.wParam;
}
thanks.
VC++ 6.0 Project settings - for GDI+

- compile step - preprocessor

C:\WinDDK\7600.16385.1\inc\api,C:\Program Files\Microsoft SDKs\Windows\v6.1\Include - for GDI+
change _CONSOLE to _WINDOWS
add ' _CRTDBG_MAP_ALLOC' to Preprocessor definitions

- link step - input
C:\Program Files\Microsoft SDKs\Windows\v6.1\Lib - for GDI+
add gdiplus.lib OR place following in .cpp file - for GDI+
#pragma comment (lib, "Gdiplus.lib") - for GDI+

/subsystem:console to /subsystem:windows
I have copied your code and it runs fine on my PC definitive no flicker.

Why didn't you follow the code from catch22 ?
Call your DrawHello2 from there and pass the hdcMem to it and paint everything on the hdcMem.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
case WM_PAINT:
     hdc = BeginPaint(hwnd, &ps);
 
    // Create an off-screen DC for double-buffering
    hdcMem = CreateCompatibleDC(hdc);
    hOld   = SelectObject(hdcMem, hbmMem);
 
    // Draw into hdcMem here
    DrawHello2 ( hdcMem, flag );

    // Transfer the off-screen DC to the screen
    BitBlt(hdc, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY);
 
    // Free-up the off-screen DC
    SelectObject(hdcMem, hOld);
    DeleteObject(hbmMem);
    DeleteDC    (hdcMem);
 
    EndPaint(hwnd, &ps);
    return 0;
Hmmm! sounds like a good plan thanks Thomas. will try it when i get home. are you saying the oriinal didn't flicker or the change you have implemented? the original does flicker on my XP SP3 - i'm still in the dark ages.
Many thanks.
The original doesn't flicker, but I am using Win7 and VC++ 2010 Express.
i see. me with XP it does flicker. can't wait to get home to try your method. will report back asap. in the meantime Thomas thank you.
my orig paint was thus

case WM_PAINT:
hDC = BeginPaint ( hwnd, &ps ); // when DrawHello replaced with DrawHello2
DrawHello2 ( hwnd, wParam, lParam, flag ); // does EndPaint
EndPaint ( hwnd, &ps );
//Sleep (200);
DeleteDC( hDC );
return 0; // FALSE 0: TRUE 1:

and when i obscured my window with another and slowly dragged it downwards to reveal my window it flickered like crazy man. when i changed it to

case WM_PAINT:
DrawHello2 ( hwnd, wParam, lParam, flag ); // does EndPaint
return 0; // FALSE 0: TRUE 1:

it didn't flicker at all when repeating this operation! It didn't stop the fast mouse button press flicker though. Guess this should have been a huge hint to do what you have proposed.

The good news is that having implemented your suggestion it works with absolutely no flicker removing the need to clear the actual screens bitmap as i had to in the orig program posted above. as in
// FillRect ( hDC1, &xrect, (HBRUSH) hBrush ); // clear screen
I suspect it was this extra FillRect that caused the flicker!?
In fact it was, i've just tried it. writing same pixel twice !

It even works when maximized. Yee-hah!
You're a real star Thomas. Many thanks for your time. Mucho Kudos.
Last edited on
mind you i still don't fully understand one crucial thing. when i commented out the FillRect ( hDC1... in the original posted program the flicker did stop but the old contents remainded and was thus continually added to. perhaps you can let me know what i'm missing on this Thomas?
The problem I see is that FillRect ( hDC1) is the normal DC. All the painting should be on the background DC. That's why I suggested to create a the background DC in WM_PAINT and pass it to DrawHello2.
yes i understand that thanks Thomas. unfortunately in my orig posted prog if i didn't include that then the results on the screen were a combination of all that went before. this is what i don't comprehend as the bacbuffer shuold have overwritten the previous screens contents. i was the last thing done.
perhaps TRANSPARENT has something to do with it? i'll do some more testing.
Cheers.
finally got time to try a few things. silly me had SRCAND in the orig when BitBlt'ng to the main screens bitmap. Oh well at least i understand it now.
my final WM_PAINT is this and works.

case WM_PAINT:
// Draw into hdcMem here
// DrawHello2 ( flag, hwnd, hdc ); //, hbmMem );
DrawHello2 ( hwnd ); // ( flag, hwnd, hdc ); //, hbmMem );
return 0;

Thanks Thomas.
cheers.
Last edited on
Topic archived. No new replies allowed.