设置窗口像素的正确方法(无闪烁)吗? [英] Correct (and flicker-free) way of setting window pixels?

查看:78
本文介绍了设置窗口像素的正确方法(无闪烁)吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力寻找在WM_PAINT期间将纯RGBA值数组转储到Win32窗口的客户区中的正确方法.我有以下代码,但它似乎已经令人费解,甚至还没有完成:

I'm struggling to figure out the proper way of dumping an array of plain RGBA values into the client area of a Win32 window during WM_PAINT. I have the following code but it already seems convoluted and I'm not even finished:

case WM_ERASEBKGND:
  return 1;
case WM_PAINT:
{
  PAINTSTRUCT paintInfo{};
  HDC device = BeginPaint(window, &paintInfo);
  if (device == nullptr)
    throw runtime_error(RG_LOCATION());
  ScopeExit endPaint([&] { EndPaint(window, &paintInfo); });

  HDC offscreenDevice = CreateCompatibleDC(device);
  ScopeExit deleteOffscreenDevice([&] { DeleteDC(offscreenDevice); });
  HBITMAP offscreenBitmap = CreateCompatibleBitmap(device, Distance(paintInfo.rcPaint.left, paintInfo.rcPaint.right),
                                                   Distance(paintInfo.rcPaint.top, paintInfo.rcPaint.bottom));
  ScopeExit deleteOffscreenBitmap([&] { DeleteObject(offscreenBitmap); });
  HBITMAP previousBitmap = reinterpret_cast<HBITMAP>(SelectObject(offscreenDevice, offscreenBitmap));

  // now I need to blit the available pixel data...
  vector<array<uint8_t, 4>> mypixels;
  // ...onto the client area of the window.

  // What do I do next?
  // CreateDIBSection ?
  // BitBlt ?

  return 0;
}

关于源图像"内存格式,我有一些回旋余地,因此我可以使它与目标所需的内容相匹配.

I have some wiggle room with regards to the source "image" memory format so I can make that match whatever the target requires.

我这样做正确吗?有更好的方法吗?

Am I doing this correctly? Is there a better way?

P.S .:显然,每次WM_PAINT出现时,我都会存储而不是重新创建大多数对象.这只是一个示例/在制品.

P.S.: Obviously I would be storing and not recreating most of the objects each time a WM_PAINT comes along. This is just an example/WIP.

:添加了对WM_ERASEBKGND的处理.

Added handling of WM_ERASEBKGND.

好的,看来我需要更具体一些.我不是在查找发布的代码的实际问题.这只是到目前为止我在工作流程方面的一个例子.这意味着我有一个窗口HDC,一个离屏HDC,一个离屏HBITMAP和一个指向我的像素的指针,这些像素位于假设的R8G8B8A8内存布局中.这些对象我该怎么办?我是否可以通过CreateDIBSection创建另一个HBITMAP并将像素写入其中?以后我该怎么办?

Edit 2: Ok, it seems I need to be more specific. I am not looking for actual issues with the code I posted. It is only an example of what I have so far in terms of workflow. That means I have the window HDC, an offscreen HDC, an offscreen HBITMAP and a pointer to my pixels which are in, let's say, a hypothetical R8G8B8A8 memory layout. What do I do with these objects? Do I create another HBITMAP via CreateDIBSection and write my pixels into that? What do I do with it after?

请参阅Barmak Shemirani的答案以获取适当的解决方案(我的示例代码有问题).也请查看Paul Sanders的答案以获取一些现代WinAPI提示.

Edit 3: See answer from Barmak Shemirani for proper solution (my example code has issues). Check also Paul Sanders' answer for some modern WinAPI tips.

谢谢!

推荐答案

要打印mypixels矢量,请使用SetDIBitsToDevice绘制设备上下文.或使用SetDIBits创建一个新的HBITMAP对象.

To print mypixels vector use SetDIBitsToDevice to draw to device context. Or use SetDIBits to create a new HBITMAP object.

为简单起见,本示例直接绘制到HDC中.但是您可以使用CreateCompatibleDC进行缓冲,也可以使用其他答案中所示的缓冲方法.

For simplicity, this example draw directly in to HDC. But you can use CreateCompatibleDC for buffering, or use the buffer method shown in the other answer.

case WM_PAINT:
{
    //int w = width of source bitmap
    //int h = height of source bitmap
    //optional: make sure width and height are correct
    assert(mypixels.size() == w * h);

    PAINTSTRUCT ps;
    auto hdc = BeginPaint(hwnd, &ps);

    BITMAPINFOHEADER bi{ sizeof(bi) };
    bi.biWidth = w;
    bi.biHeight = h;
    bi.biPlanes = 1;
    bi.biBitCount = 32;
    bi.biCompression = BI_RGB;

    SetDIBitsToDevice(hdc, 0, 0, w, h, 0, 0, 0, h, &mypixels[0],
        (BITMAPINFO*)&bi, DIB_RGB_COLORS);

    EndPaint(hwnd, &ps);

    return 0;
}

使用内存dc:

case WM_PAINT:
{
    RECT rc;
    GetClientRect(hwnd, &rc);
    int canvas_width = rc.right;
    int canvas_height = rc.bottom;

    PAINTSTRUCT ps;
    auto hdc = BeginPaint(hwnd, &ps);

    //create memory dc:
    auto memdc = CreateCompatibleDC(hdc);
    auto hbmp = CreateCompatibleBitmap(hdc, canvas_width, canvas_height);
    auto oldbmp = SelectObject(memdc, hbmp); //<- memdc is ready

    //draw on memory dc:
    BITMAPINFOHEADER bi{ sizeof(bi), w, h, 1, 32, BI_RGB };
    SetDIBitsToDevice(memdc, 0, 0, w, h, 0, 0, 0, h, mypixels.data(),
        (BITMAPINFO*)&bi, DIB_RGB_COLORS);

    //draw on actual dc:
    BitBlt(hdc, 0, 0, canvas_width, canvas_height, memdc, 0, 0, SRCCOPY);

    //clean up:
    SelectObject(memdc, oldbmp);
    DeleteObject(hbmp);
    DeleteDC(memdc);
    EndPaint(hwnd, &ps);

    return 0;
}

这篇关于设置窗口像素的正确方法(无闪烁)吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆