C++ 中的 GDI+ 双缓冲

Posted

技术标签:

【中文标题】C++ 中的 GDI+ 双缓冲【英文标题】:GDI+ double buffering in C++ 【发布时间】:2010-03-18 22:33:19 【问题描述】:

我已经有一段时间没有用 GDI 写过任何东西了(也从来没有用过 GDI+),我只是在做一个有趣的项目,但是对于我的生活,我不知道如何加倍缓冲GDI+

void DrawStuff(HWND hWnd) 
    HDC          hdc;
    HDC          hdcBuffer;
    PAINTSTRUCT  ps;
    hdc = BeginPaint(hWnd, &ps);
    hdcBuffer = CreateCompatibleDC(hdc);
    Graphics graphics(hdc);
    graphics.Clear(Color::Black);

    // drawing stuff, i.e. bunnies:

    Image bunny(L"bunny.gif");
    graphics.DrawImage(&bunny, 0, 0, bunny.GetWidth(), bunny.GetHeight());  

    BitBlt(hdc, 0,0, WIDTH , HEIGHT, hdcBuffer, 0,0, SRCCOPY);
    EndPaint(hWnd, &ps);

上述工作(一切都完美呈现),但它闪烁。如果我将 Graphics graphics(hdc); 更改为 Graphics graphics(hdcBuffer);,我什么也看不到(尽管我应该在底部对缓冲区进行 bitblt->hWnd hdc)。

我的消息管道设置正确(WM_PAINT 调用 DrawStuff),我通过调用 RedrawWindow(window, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); 在每个程序循环中强制发送 WM_PAINT 消息

我可能会采取错误的方式来做到这一点,有什么想法吗? MSDN 文档充其量是神秘的。

【问题讨论】:

【参考方案1】:

CreateCompatibleDC(hdc) 使用 1x1 像素单色位图作为其绘图表面创建 DC。如果您想要一个更大的绘图表面,您还需要CreateCompatibleBitmap 并将该位图选择到 hdcBuffer 中。

编辑:

闪烁是由 WM_ERASEBKGND 引起的,当你这样做时

hdc = BeginPaint(hWnd, &ps);

在对 BeginPaint 的调用中,如果 Windows 认为需要重绘背景,则 Windows 会向您的 WndProc 发送 WM_ERASEBKGND 消息,如果您不处理该消息,则 DefWindowProc 会通过使用您的类画笔填充绘制矩形来处理它,所以为了避免闪烁,你应该处理它并返回TRUE。

case WM_ERASEBKGND:
   return TRUE; // tell Windows that we handled it. (but don't actually draw anything)

Windows 认为你的背景应该被删除,因为你告诉它应该删除,这就是 RDW_ERASE 的意思,所以你应该把它排除在你的 RedrawWindow 调用之外

【讨论】:

谢谢,我添加了 hBmp = CreateCompatibleBitmap(hdc,WIDTH,HEIGHT);选择对象(hdcBuffer,hBmp);到代码(并且 BitBlt 有效),但它仍然闪烁。【参考方案2】:

您可以尝试以下方法:

void DrawAll(CDC *pDC)

    CRect rect;
    GetClientRect(&rect);

    Bitmap *pMemBitmap = new Bitmap(rect.Width(), rect.Height());

    Graphics* pMemGraphics = Graphics::FromImage(pMemBitmap);

    Graphics graphics(pDC->m_hDC);

    // use pMemGraphics  do something....

    Status status = graphics.DrawImage(pMemBitmap, 0, 0);   
    if (status != Ok)
    
        //some error
    

   delete pMemGraphics;
   delete pMemBitmap;

【讨论】:

请在您的代码中添加描述,以便更好地解释您的解决方案。我们在这里学习如何在下次遇到此问题时获得答案,而不是如何复制它们。 这不会泄露 pMemBitmap 吗?【参考方案3】:

您在处理 WM_ERASEBKGND 吗?我相信它会在 WM_PAINT 之前被调用,并且通常会破坏您可能不希望发生的窗口背景颜色。

【讨论】:

【参考方案4】:

鉴于“Graphics graphics(hdc)”,您似乎正在清除 hdc 而不是 hdcBuffer。果然会导致闪烁。

【讨论】:

以上是关于C++ 中的 GDI+ 双缓冲的主要内容,如果未能解决你的问题,请参考以下文章

C 和 Windows GDI 中的双缓冲 *framework*

GDI双缓冲绘图

GDI双缓冲的一些学习

实例解说双缓冲

将 c++ 双缓冲区传递给 Node Js(直接)[Node JS : V8 c++ : Nan]

C++ fmtlib:如何将双精度转换为现有的 wchar_t 缓冲区?