使用 GDI+ 和 C++ 减少闪烁

2024-06-02

我在 C++/MFC 应用程序中使用 GDI+,每当调整窗口大小时,我似乎都无法避免闪烁。

我已经尝试过以下步骤:

  • 返回 TRUEOnEraseBkGnd();
  • 返回 NULLOnCtlColor();
  • 根据此代码使用双缓冲:
void vwView::OnDraw(CDC* pDC) 
{
   CRect rcClient;
   GetClientRect(rcClient);

   Bitmap bmp(rcClient.Width(), rcClient.Height());
   Graphics graphics(&bmp);

   graphics.DrawImage(m_image, rcClient.left, rcClient.top);

   Graphics grph(pDC->m_hDC);
   grph.DrawImage(&bmp, 0, 0);
}

难道我做错了什么?或者还有其他方法可以实现这一目标吗?


要完全避免闪烁,您需要完成all在屏幕更新之间的间隔中绘制。 Windows 没有提供任何简单的方法来完成正常的窗口绘制(Vista 通过DWM https://en.wikipedia.org/wiki/Desktop_Window_Manager,但即使在运行 Vista 的系统上也不能依赖这一点)。因此,要尽量减少闪烁,最好的办法就是尽快绘制所有内容(reduce通过增加在刷新周期内完成所有绘制的机会来避免撕裂),并避免过度绘制(绘制屏幕的一部分,然后在顶部绘制其他内容:存在向用户呈现部分绘制的屏幕的风险)。

让我们讨论一下到目前为止所介绍的技术:

  • 不执行任何操作 OnEraseBkgnd():通过防止窗口的无效区域被窗口的背景颜色填充来帮助避免过度绘制。当您在 WM_PAINT 处理期间再次绘制整个区域时很有用anyway,就像双缓冲绘图的情况一样...但请参阅通过防止在 WM_PAINT 方法之后进行绘图来避免过度绘制的注释

  • OnCtlColor() 返回 NULL: 这实际上不应该做anything...除非您的表单上有子控件。在这种情况下,请参阅关于通过防止在 WM_PAINT 方法之后进行绘制来避免过度绘制的注释

  • 双缓冲绘图:通过将实际的屏幕绘图减少到单个,有助于避免撕裂(也可能是过度绘制)BitBLT https://en.wikipedia.org/wiki/Bit_blit。但可能会影响绘图所需的时间:无法使用硬件加速(尽管使用 GDI+,使用任何硬件辅助绘图的机会非常小),每次重绘都必须创建并填充离屏位图,并且每次重绘都必须重新绘制整个窗口。看高效双缓冲的注意事项.

  • 对 BitBlt 使用 GDI 调用而不是 GDI+:这通常是个好主意 -Graphics::DrawImage()可能会很慢。我什至找到了正常的GDIBitBlt() https://msdn.microsoft.com/en-us/library/dd183370.aspx在某些系统上调用速度更快。尝试一下这个,但前提是先尝试一些其他建议。

  • 避免在每次调整大小时强制完全重绘的窗口类样式(CS_VREDRAWCS_HREDRAW:这会有帮助,但前提是你不这样做need当大小改变时重画整个窗口。

有关通过在 WM_PAINT 方法之前防止绘制来避免过度绘制的注意事项

当窗口的全部或部分失效时,它将被擦除并重新绘制。如前所述,如果您打算重新绘制整个无效区域,则可以跳过擦除。However,如果您正在使用子窗口,则必须确保父窗口不会同时擦除您的屏幕区域。应在所有父窗口上设置 WS_CLIPCHILDREN 样式 - 这将防止在子窗口(包括您的视图)占用的区域上进行绘制。

有关通过在 WM_PAINT 方法之后防止绘制来避免过度绘制的注意事项

如果你有any如果您的窗体上托管有子控件,您将需要使用 WS_CLIPCHILDREN 样式来避免在它们上绘制(并随后被它们过度绘制)。请注意,这会在一定程度上影响 BitBlt 例程的速度。

高效双缓冲的注意事项

现在,每次视图自行绘制时,您都会创建一个新的后台缓冲区图像。对于较大的窗口,这可能表示正在分配和释放大量内存,并且will导致严重的性能问题。我建议在视图对象中保留动态分配的位图,并根据需要重新分配它以匹配视图的大小。

请注意,在调整窗口大小时,这将导致与当前系统一样多的分配,因为每个新大小都需要分配一个新的后台缓冲区位图来匹配它 - 您可以通过向上舍入尺寸来稍微减轻痛苦到 4、8、16 等的下一个最大倍数,这样您就可以避免在大小的每个微小变化上重新分配。

请注意,如果自上次渲染到后台缓冲区以来窗口的大小没有更改,则在窗口失效时无需重新渲染它 - 只需将已渲染的图像移出到屏幕。

另外,分配与屏幕位深度匹配的位图。构造函数为Bitmap您当前使用的默认为 32bpp、ARGB 布局;如果这与屏幕不匹配,则必须对其进行转换。考虑使用GDI方法CreateCompatibleBitmap() https://msdn.microsoft.com/en-us/library/dd183488.aspx以获得匹配的位图。

最后...我假设您的示例代码只是一个说明性片段。但是,如果您实际上除了将现有图像渲染到屏幕上之外什么都不做,那么您实际上根本不需要维护后台缓冲区 - 只需直接从图像进行 Blt(并提前将图像的格式转换为与屏幕匹配)。

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

使用 GDI+ 和 C++ 减少闪烁 的相关文章

随机推荐

  • 路由是否会影响具有绑定源地址的套接字?

    假设我有两个网络接口 eth0有地址10 0 0 1 eth1有地址192 168 0 1 Using route or ip route add我已将其设置为路由 所有地址至eth0 1 2 3 4只为了eth1 所以数据包到1 2 3
  • 使垂直网格线出现在跨区表格单元格的顶部

    我正在开发一个 ASP Net 项目 我有一个
  • ModelBinder 验证在使用反射的 getter 上中断

    我遇到了一个似乎与反射和模型绑定验证有关的问题 并且FormatterParameterBinding ExecuteBindingAsync 特别是 虽然我可以使用方法来做我想做的事情 但如果我可以使用属性 我会更喜欢它 在这里 我正在寻
  • 修改排序比较器内的字符串

    我有以下代码 在排序比较器中 它在进行比较之前删除前缀字符串 print for sort a s STRING b s STRING foo a cmp foo b a 尽管比较和顺序是正确的 但前缀字符串已从输出中删除 以下保留前缀字符
  • Facebook 扩展权限

    更新2 好的 通过更改使其 有点 工作 loginUrl facebook gt getLoginUrl array canvas gt 1 fbconnect gt 0 req perms gt publish stream next g
  • 具有非零“内容”的 QTMovieLayer 的 iOS 替代品?

    背景 QTKit QuickTime Kit 是一个来自 10 3 天的 Mac 框架 在 10 5 中添加了一些层 例如QTMovieLayer QTMovieLayer 的好处之一是您可以使用常规访问电影内容content图层上的属性并
  • 获取 Cocoa 中文件的类型

    我成功找到了指定文件的扩展文件类型 JPEG 图像 TIFF 图像等 但我正在寻找更通用的东西 可以对 大类别 中的文件进行分类 如图像 moovies 文本文件等 有没有办法在可可 或 Objective C 中实现这一点 感谢您的帮助
  • 如何解决此浏览器或应用程序可能不安全。使用selenium java时出错[重复]

    这个问题在这里已经有答案了 import org openqa selenium By import org openqa selenium chrome ChromeDriver import io github bonigarcia w
  • VSCode Live Server 和 Node Live Server 的区别

    我正在开始使用 JS 所以我已经到了必须使用 npm 安装实时服务器的地步 VSCode 有一个很多人都知道的流行扩展 称为 Live Server Ritwick Dey 我的问题是使用该扩展和使用 Node 安装包有什么区别 是否有任何
  • 使用星号更改多个源文件的 CMake 编译器标志

    我正在尝试调试与编译器优化相关的问题 O2 或以下版本没有问题 O3 出现段错误 并且我希望能够切换我的源代码块的编译器标志 以便我可以尝试缩小段错误的来源范围 我可以将全局优化级别设置为 O2 并更改单个文件的属性 如下所示 SET SO
  • Bootstrap 4alpha - 更改手机/桌面/平板电脑的徽标

    我有一个使用 bootstrap 4 alpha 的标头 div class container div class row div class col md 6 text md left text center div class nav
  • XCode 调试 - 我可以绕过反汇编代码的单步执行吗

    调试项目时 在 XCode 中设置断点后 我将开始单步执行代码 然后我会遇到反汇编代码 我认为这些代码是对没有可用源代码的各种框架的调用 这是一个正确的假设吗 有没有一种方法 可能通过我尚未找到的项目设置 来抑制此汇编代码的显示 而不必单步
  • 如何从 GWT 的序列化策略中删除实现类型?

    这个问题的反面是 如何将类型添加到 GWT 的序列化策略白名单 https stackoverflow com questions 138099 how do i add a type to gwts serialization polic
  • 如何将输入文件中的子字符串作为要在 GNU 并行中执行的程序的参数?

    我正在尝试执行一个程序 例如 biotool 使用 GNU 并行 它需要 3 个参数 i o and a 输入文件 i 要写入的输出文件名 o 一个参数 它从输入文件名中获取子字符串 a 例如 假设我有 10 个这样的文本文件 1 a te
  • ngbModal 作为通用确认框

    我正在尝试使用 ngbmodal 创建通用确认框 它将在整个应用程序中使用 其中 标题和消息将从调用组件传递到模态 我创建为 DialogService 并添加到 EntryComponents 中 现在我可以显示确认框 但无法得到结果 下
  • 如何在 Rails 中将随机日期时间四舍五入到小时开始?

    基本上我想获得去年内的随机日期时间 rand 1 year ago gt Sun 22 Sep 2013 18 37 44 UTC 00 00 example 但是我该如何指定或限制这个时间呢 例如 Sun 22 Sep 2013 18 0
  • 当内存排序放宽时,C++ 延迟会增加

    我在 Windows 7 64 位 VS2013 x64 发行版 上尝试内存排序 我想使用最快的同步来共享对容器的访问 我选择了原子比较和交换 我的程序产生两个线程 写入器推送到向量 读取器检测到这一点 最初我没有指定任何内存顺序 所以我假
  • 添加自定义字段到编辑视图 - SugarCRM

    我正在尝试修改 SugarCRM SugarPro 6 1 2 实例的 EditView 中自定义字段 复选框 的行为 具体来说 我希望每当有人单击该复选框时都会显示一个 div 该字段按预期出现在 编辑 视图中 并且我添加了一些执行 on
  • 将新行添加到表后如何更新 datagridview 的行列表

    我有一个 datagridview 在表单的加载事件上填充了表集合 我还有一个由用户填写的表单 并将新行添加到表 onclick 事件 我想在向该表添加新行后更新 datagridview表 我使用绑定到绑定数据源的 sqladapter
  • 使用 GDI+ 和 C++ 减少闪烁

    我在 C MFC 应用程序中使用 GDI 每当调整窗口大小时 我似乎都无法避免闪烁 我已经尝试过以下步骤 返回 TRUEOnEraseBkGnd 返回 NULLOnCtlColor 根据此代码使用双缓冲 void vwView OnDraw