设置窗口像素的正确(且无闪烁)方法?

2024-05-17

我正在努力找出在 WM_PAINT 期间将纯 RGBA 值数组转储到 Win32 窗口的客户区的正确方法。我有以下代码,但它看起来已经很复杂,我什至还没有完成:

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

对于源“图像”内存格式,我有一些回旋余地,因此我可以使其匹配目标所需的任何内容。

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

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

Edit:添加了 WM_ERASEBKGND 的处理。

Edit 2:好吧,看来我需要更具体一些。我并不是在寻找我发布的代码的实际问题。这只是我迄今为止在工作流程方面所拥有的一个示例。这意味着我有窗口 HDC、屏幕外 HDC、屏幕外 HBITMAP 和指向像素的指针,这些像素位于假设的 R8G8B8A8 内存布局中。我该如何处理这些物体?我是否通过 CreateDIBSection 创建另一个 HBITMAP 并将我的像素写入其中?之后我该怎么办?

Edit 3:请参阅 Barmak Shemirani 的答案以获得正确的解决方案(我的示例代码有问题)。另请查看 Paul Sanders 的回答,了解一些现代 WinAPI 技巧。

谢谢大家!


打印mypixels矢量使用SetDIBitsToDevice绘制到设备上下文。或者使用SetDIBits创建一个新的HBITMAP目的。

为了简单起见,本示例直接绘制为HDC。但你可以使用CreateCompatibleDC用于缓冲,或使用其他答案中显示的缓冲方法。

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

使用内存直流:

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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

设置窗口像素的正确(且无闪烁)方法? 的相关文章

  • 使用 gcc 在 Linux 上运行线程构建块 (Intel TBB)

    我正在尝试为线程构建块构建一些测试 不幸的是 我无法配置 tbb 库 链接器找不到库 tbb 我尝试在 bin 目录中运行脚本 但这没有帮助 我什至尝试将库文件移动到 usr local lib 但这又失败了 任何的意见都将会有帮助 确定您
  • 在模板类中声明模板友元类时出现编译器错误

    我一直在尝试实现我自己的链表类以用于教学目的 我在迭代器声明中指定了 List 类作为友元 但它似乎无法编译 这些是我使用过的 3 个类的接口 Node h define null Node
  • 在 xaml 中编写嵌套类型时出现设计时错误

    我创建了一个用户控件 它接受枚举类型并将该枚举的值分配给该用户控件中的 ComboBox 控件 很简单 我在数据模板中使用此用户控件 当出现嵌套类型时 问题就来了 我使用这个符号来指定 EnumType x Type myNamespace
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • 类型中的属性名称必须是唯一的

    我正在使用 Entity Framework 5 并且有以下实体 public class User public Int32 Id get set public String Username get set public virtual
  • C++11 删除重写方法

    Preface 这是一个关于最佳实践的问题 涉及 C 11 中引入的删除运算符的新含义 当应用于覆盖继承父类的虚拟方法的子类时 背景 根据标准 引用的第一个用例是明确禁止调用某些类型的函数 否则转换将是隐式的 例如最新版本第 8 4 3 节
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • ASP.NET Core 3.1登录后如何获取用户信息

    我试图在登录 ASP NET Core 3 1 后获取用户信息 如姓名 电子邮件 id 等信息 这是我在登录操作中的代码 var claims new List
  • C# 列表通用扩展方法与非通用扩展方法

    这是一个简单的问题 我希望 集合类中有通用和非通用方法 例如List
  • 两个静态变量同名(两个不同的文件),并在任何其他文件中 extern 其中一个

    在一个文件中将变量声明为 static 并在另一个文件中进行 extern 声明 我认为这会在链接时出现错误 因为 extern 变量不会在任何对象中看到 因为在其他文件中声明的变量带有限定符 static 但不知何故 链接器 瑞萨 没有显
  • 为什么这个字符串用AesCryptoServiceProvider第二次解密时不相等?

    我在 C VS2012 NET 4 5 中的文本加密和解密方面遇到问题 具体来说 当我加密并随后解密字符串时 输出与输入不同 然而 奇怪的是 如果我复制加密的输出并将其硬编码为字符串文字 解密就会起作用 以下代码示例说明了该问题 我究竟做错
  • 两个类可以使用 C++ 互相查看吗?

    所以我有一个 A 类 我想在其中调用一些 B 类函数 所以我包括 b h 但是 在 B 类中 我想调用 A 类函数 如果我包含 a h 它最终会陷入无限循环 对吗 我能做什么呢 仅将成员函数声明放在头文件 h 中 并将成员函数定义放在实现文
  • 空指针与 int 等价

    Bjarne 在 C 编程语言 中写道 空指针与整数零不同 但 0 可以用作空指针的指针初始值设定项 这是否意味着 void voidPointer 0 int zero 0 int castPointer reinterpret cast
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 为什么 isnormal() 说一个值是正常的,而实际上不是?

    include
  • 有没有办法让 doxygen 自动处理未记录的 C 代码?

    通常它会忽略未记录的 C 文件 但我想测试 Callgraph 功能 例如 您知道在不更改 C 文件的情况下解决此问题的方法吗 设置变量EXTRACT ALL YES在你的 Doxyfile 中
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置

随机推荐