how to code for reducing flicker? need your help with code. win32 VC++ flicker
I'm trying to bitblt bitmap to mouse cursor position with the mouse movemont.but with flickering problems.
I've read about double buffering to reduce flicker but I'm not sure how to ... this causes extreme flickering. I've read about double buffering to reduce flicker but I'm not sure how to implement it in this example. Please can you help? Thanks
here's code below .thanks for your help!
// screen blinks.trying to use double buffer so solve this problem.
#include <windows.h>
HDC bufferDC = NULL;
HDC hdc=GetWindowDC(NULL) ;
HDC hammerDC = NULL;
HBITMAP hammer1BMP = NULL;
HBITMAP bufferBMP = NULL;
POINT cursorpoint;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("DigClock") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Digital Clock"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, 开发者_如何学PythonNULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
bufferDC=CreateCompatibleDC(hdc);
hammerDC=CreateCompatibleDC(hdc);
hammer1BMP=(HBITMAP)LoadImage(NULL,"star.bmp",IMAGE_BITMAP,160,160,LR_LOADFROMFILE);
SelectObject(hammerDC,hammer1BMP);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL f24Hour, fSuppress ;
static HBRUSH hBrushRed ;
static int cxClient, cyClient ;
HDC hdc ;
PAINTSTRUCT ps ;
TCHAR szBuffer [2] ;
switch (message)
{
case WM_CREATE:
hBrushRed = CreateSolidBrush (RGB (255, 0, 0)) ;
SetTimer (hwnd, ID_TIMER, 1000/24,NULL) ;//1000
// fall through
case WM_SETTINGCHANGE:
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_TIMER:
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
bufferBMP=CreateCompatibleBitmap(hdc,cxClient,cyClient);
SelectObject(bufferDC,bufferBMP);
// SelectObject(bufferDC,hammer1BMP);
GetCursorPos(&cursorpoint);
BitBlt(bufferDC,0,0,cxClient,cyClient,hammerDC,0,0,SRCCOPY);
BitBlt(hdc,cursorpoint.x,cursorpoint.y,cxClient,cyClient,bufferDC,0,0,SRCCOPY);
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_LBUTTONDOWN:
// GetCursorPos(&cursorpoint);
//BitBlt(hdc,cursorpoint.x,cursorpoint.y,cxClient,cyClient,hammerDC,0,0,SRCCOPY);
return 0;
case WM_DESTROY:
KillTimer (hwnd, ID_TIMER) ;
DeleteDC(hammerDC);
DeleteObject (hBrushRed) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
In this case it looks like you don't really need double buffering -- in fact, it probably won't help you at all.
The primary cause of your flickering is erasing the background, then immediately drawing over it. Since you're apparently drawing the whole client area of your window in WM_PAINT, just add a handler for WM_ERASEBKGND that does nothing but return TRUE to indicate that the background has been erased.
Edit (in response to comments):
To be more complete, flickering results (almost) anytime you paint an area in one color, then quickly repaint it in another color. Double buffering helps when/if your foreground has a number of overlaying elements of different colors. You draw (at least the) overlaying areas into the back buffer, then only when you have the right colors, you draw them to the screen. In this case, the original code does double buffering, but it's still drawing the background, then the foreground, and you still get flickering.
Another answer mentioned passing false as the second parameter to InvalidateRect. This will help a lot, as it won't re-draw the background in response to that InvalidateRect. Only he foreground will be drawn, so it'll be flicker-free. Unfortunately, when (at least part of) the Window's rectangle is invalidated for any other reason, you'll still get flicker, because it'll still draw the background followed by the foreground.
Remove your timer. The timer is causing you to invalidate even when there is no change to the window. Furthermore, you are erasing the window with each timer elapse.
Basically , you got the concept correct. When you need to WM_PAINT, copy your back buffer. When you need to update the graphics, update your back buffer and then only invalidate once.
Another tip is to use GetUpdateRect() to get the update region in WM_PAINT. Only copy the region which is dirty from your back buffer. This further optimizes your double buffering
The cause of the flicker (and eventual program crash) is multifold:
- There is the background brush - set hbrBackground to inhibit the generation of WM_ERASEBKGND messages.
- You are creating (and leaking) a bufferBMP per WM_PAINT.
- You are not painting the window correctly - why are you painting to the cursor position? If you want to have the 'hammer' track the mouse, you would paint the hammer onto the offscreen bitmap at the appropriate location, and then blit the offscreen bitmap to cover the client area, i.e. to 0,0,cx,cy
To avoid flickering use double buffering method. In this method we do painting procedure over off screen DC (hdcBuffer) and then copy the content of that DC to actual screen DC (hdc). Also avoid erasing of background by returning non zero to WM_ERASEBKGND message. Here is the algo:
hdc = BeginPaint(hwnd,&ps); // actual screen DC
hdcBuffer = CreateCompatibleDC (hdc) // OFF screen DC
hBitmapBuffer = CreateCompatibleBitmap (hdc,BitmapWidth, BitmapHeight); // create memory bitmap for that off screen DC
SelectObject(hdcBuffer,hBitmapBuffer); // Select the created memory bitmap into the OFF screen DC
/* Then do your painting job using hdcBuffer over off screen DC */
BitBlt(hdc,0,0,BitmapWidth,BitmapHeight,hdcBuffer,0,0,SRCCOPY); // copy the content of OFF screen DC to actual screen DC
DeleteDC (hdcBuffer); // Release the OFF screen DC
DeleteObject (hBitmapBuffer); // Free the memory for bitmap
EndPaint(hwnd,&ps); // Release the actual screen DC
精彩评论