GDI+ C++ 中的双缓冲

发布于 2024-08-25 07:23:46 字数 969 浏览 3 评论 0原文

一段时间没有用 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);
}

我已经有 有效(一切都渲染得很完美),但它会闪烁。如果我将 Graphicsgraphics(hdc); 更改为 Graphicsgraphics(hdcBuffer);,我什么也看不到(尽管我应该对 buffer->hWnd hdc 进行 bitblt'ing)底部)。

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

I'我可能采用了错误的方法来做到这一点,有什么想法吗? MSDN 文档充其量是晦涩难懂的。

I haven't written anything with GDI for a while now (and never with GDI+), and I'm just working on a fun project, but for the life of me, I can't figure out how to double buffer 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);
}

The above works (everything renders perfectly), but it flickers. If I change Graphics graphics(hdc); to Graphics graphics(hdcBuffer);, I see nothing (although I should be bitblt'ing the buffer->hWnd hdc at the bottom).

My message pipeline is set up properly (WM_PAINT calls DrawStuff), and I'm forcing a WM_PAINT message every program loop by calling RedrawWindow(window, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);

I'm probably going about the wrong way to do this, any ideas? The MSDN documentation is cryptic at best.

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

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

发布评论

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

评论(4

天气好吗我好吗 2024-09-01 07:23:46

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

编辑:

闪烁是由 WM_ERASEBKGND 引起的,当您

hdc = BeginPaint(hWnd, &ps);

在对 BeginPaint 的调用中执行此操作时,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 调用之外

CreateCompatibleDC(hdc) creates a DC with a 1x1 pixel monochrome bitmap as its drawing surface. You need to also CreateCompatibleBitmap and select that bitmap into the hdcBuffer if you want a drawing surface larger than that.

Edit:

the flickering is being caused by WM_ERASEBKGND, when you do this

hdc = BeginPaint(hWnd, &ps);

Inside the call to BeginPaint, Windows sends your WndProc a WM_ERASEBKGND message if it thinks the background needs to be redrawn, if you don't handle that message, then DefWindowProc handles it by filling the paint rectangle with your class brush, so to avoid the flickering, you should handle it and return TRUE.

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

Windows thinks your background should be erased because you tell it that it should, that's what RDW_ERASE means, so you should probably leave that out of your RedrawWindow call

烙印 2024-09-01 07:23:46

您可以尝试以下方法:

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

You can try the following way:

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;
}
颜漓半夏 2024-09-01 07:23:46

您正在处理 WM_ERASEBKGND 吗?我相信它会在 WM_PAINT 之前被调用,并且通常会位图窗口的背景颜色,而您可能不希望发生这种情况。

Are you handling WM_ERASEBKGND? I believe it gets called right before WM_PAINT and usually blits the window's background color which you probably don't want to happen.

世态炎凉 2024-09-01 07:23:46

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

Given "Graphics graphics(hdc)", you seem to be clearing hdc instead of hdcBuffer. Sure enough, that will cause flicker.

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