1

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, NULL, 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) ;
}
4

4 回答 4

7

在这种情况下,看起来您实际上并不需要双缓冲——事实上,它可能根本对您没有帮助。

闪烁的主要原因是擦除背景,然后立即对其进行绘制。由于您显然在 WM_PAINT 中绘制了窗口的整个客户区域,因此只需为 WM_ERASEBKGND 添加一个处理程序,该处理程序只返回 TRUE 以指示背景已被擦除。

编辑(回应评论):

为了更完整,闪烁的结果(几乎)在您用一种颜色绘制区域时,然后快速用另一种颜色重新绘制。当/如果您的前景有许多不同颜色的叠加元素时,双缓冲会有所帮助。您将(至少)覆盖区域绘制到后台缓冲区中,然后只有当您拥有正确的颜色时,您才会将它们绘制到屏幕上。在这种情况下,原始代码会进行双缓冲,但它仍然在绘制背景,然后是前景,并且您仍然会闪烁。

另一个答案提到将 false 作为第二个参数传递给 InvalidateRect。这将有很大帮助,因为它不会重新绘制背景以响应 InvalidateRect。只有前景会被绘制,所以它不会闪烁。不幸的是,当(至少部分)窗口的矩形因任何其他原因无效时,您仍然会闪烁,因为它仍然会绘制背景,然后是前景。

于 2009-10-09T02:15:04.203 回答
3

删除你的计时器。即使窗口没有更改,计时器也会导致您无效。此外,您正在擦除每个计时器经过的窗口。

基本上,你的概念是正确的。当您需要 WM_PAINT 时,复制您的后台缓冲区。当您需要更新图形时,更新您的后台缓冲区,然后只失效一次。

另一个技巧是使用 GetUpdateRect() 来获取 WM_PAINT 中的更新区域。仅从后台缓冲区复制脏的区域。这进一步优化了您的双缓冲

于 2009-10-09T02:14:33.430 回答
1

闪烁(以及最终的程序崩溃)的原因是多方面的:

  1. 有背景刷——设置hbrBackground来禁止生成WM_ERASEBKGND消息。
  2. 您正在为每个 WM_PAINT 创建(并泄漏)一个 bufferBMP。
  3. 您没有正确绘制窗口 - 为什么要绘制到光标位置?如果您想让“锤子”跟踪鼠标,您可以将锤子绘制到屏幕外位图的适当位置,然后将屏幕外位图blit 以覆盖客户区域,即到 0,0,cx,cy
于 2009-10-09T11:57:57.083 回答
1

为避免闪烁,请使用双缓冲方法。在这种方法中,我们在屏幕外DC (hdcBuffer) 上执行绘制过程,然后将该DC的内容复制到实际屏幕DC (hdc)。还可以通过向WM_ERASEBKGND消息返回非零来避免擦除背景。这是算法:

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
于 2015-02-23T05:25:16.037 回答