如何编写减少闪烁的代码?需要您的代码帮助。 win32 VC++闪烁

发布于 2024-08-06 16:26:03 字数 3895 浏览 4 评论 0原文

我正在尝试使用鼠标 movemont.bitblt 位图到鼠标光标位置。但是存在闪烁问题。

我读过有关双缓冲以减少闪烁的内容,但我不知道如何...... 这会导致极度闪烁。我读过有关双缓冲以减少闪烁的内容,但我不确定如何在本例中实现它。 请问你能帮忙吗? 感谢

下面的代码。感谢您的帮助!

// 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) ;
}

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) ;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

披肩女神 2024-08-13 16:26:03

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

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

编辑(回应评论):

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

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

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.

谁与争疯 2024-08-13 16:26:03

删除你的计时器。即使窗口没有更改,计时器也会导致您无效。此外,每次计时器结束时您都会擦除窗口。

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

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

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

ˇ宁静的妩媚 2024-08-13 16:26:03

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

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

The cause of the flicker (and eventual program crash) is multifold:

  1. There is the background brush - set hbrBackground to inhibit the generation of WM_ERASEBKGND messages.
  2. You are creating (and leaking) a bufferBMP per WM_PAINT.
  3. 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
白云不回头 2024-08-13 16:26:03

为了避免闪烁,请使用双缓冲方法。
在此方法中,我们在屏幕外 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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文