c++ - 双缓冲winAPI

标签 c++ winapi double-buffering

好的,所以在我的应用程序中,有一堆 winAPI 和一些自定义控件。耶...

现在,通常情况下,他们会静静地重绘自己以进行动画、状态更改等......并且一切正常。

但是我有一个名为 fix() 的 Window 类方法。每当需要更新整个窗口时都会调用此方法。它会调整控件的大小并使窗口无效。

发生这种情况时,将绘制背景,然后是选项卡控件,然后是顶部的所有其他控件。这会导致非常烦人的闪烁,尤其是在调整窗口大小时(因为不断调用 fix())。

我尝试过的:

  • WS_EX_COMPOSITED。这只会对各个控件进行双重缓冲。这是一种改进,但闪烁不可避免地仍然存在。
  • 关闭背景绘制。几乎没有解决问题,反而使事情变得更糟。

所以:我需要一种技术/方法/任何东西来允许我对整个窗口进行双缓冲。我认为自己处理 WM_PAINT 消息可能是一种解决方案,但我不知道从哪里开始。我有一种可怕的感觉,这甚至是不可能的......

请帮助,这是一个关键问题。当这个愚蠢的小问题得到解决时,我会感到非常欣慰。

最佳答案

正是在这个时候,人们才意识到微软对原生开发者的漠视有多深。事实上,人们可能开始怀有偏执的错觉,认为 Microsoft 故意破坏原生绘画以迫使原生开发人员转向 WPF。

首先,考虑WS_EX_COMPOSITEDWS_EX_COMPOSITED 似乎是芥末:- 它说它对子控件强制执行从底部到顶部的绘制顺序,并且基本上是批量处理 WM_PAINT 消息。它说它是在 Windows 2000 (5.0) 中添加的,并且在几行之后,它不适用于启用的桌面组合。即它从 Windows Vista (6.0) 开始停止工作,除非 aero glass 被关闭,谁来做?

然后,有两种可能的“黑客”尝试让无闪烁绘画工作:

  • 首先,您需要尽量减少过度绘制的数量。 WS_EX_CLIPCHILDREN | WS_EX_CLIPSIBLINGS 是确保窗口的任何特定区域只被绘制一次所必需的。 BeginDeferWindowPos 也是批量调整大小操作所必需的,以确保 transient 状态(一个窗口与另一个窗口重叠)不会发生(即当窗口 A 已调整大小但窗口 B 尚未调整时)。

当然,当您尝试绘制蒙皮对话框、使用组框、选项卡控件或任何数量的其他限制时,WS_EX_CLIPSIBLINGS 是不合适的。

  • WM_SETREDRAW 是一条神奇的信息。没有 API 可以访问此功能:WM_SETREDRAW 由 DefWindowProc 直接处理,以便在持续时间内将窗口标记为隐藏。发送 WM_SETREDRAW, FALSE 后,使用父窗口句柄(及其所有子窗口句柄)调用 GetDC/GetDCEx/GetWindowDC 等将返回一个不会在屏幕上绘制的 DC。这使您有机会对子窗口执行各种操作,完成后发送 WM_SETREDRAW,TRUE(然后手动重新绘制窗口)。所有的子窗口都会——当然——在它们自己的时间绘制,并且在父窗口完成它的删除背景之后,所以 WM_SETREDRAW 不是万灵药。

在破坏 WS_EX_COMPOSITED 后,在 .NET 的 WinForms 和 WPF 中从头开始重新编写控件以不使用 native 控件,因此它们可以在那里烘焙缓冲绘画。还有 alpha 支持。

关于c++ - 双缓冲winAPI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3904028/

相关文章:

java - Visual Studio 2015 中 Visual C++ 开发中的 Jar 依赖项

c++ - 为什么 std::declval 添加引用?

c++ - 使用文件 I/O 正确创建和运行 win32 服务

c# - 如何从虚拟键代码转换为 System.Windows.Forms.Keys

c# - 滚动时拖放事件会中断 GUI 的平滑运动

C++ win32 api双缓冲示例帮助请

c++ - cudaMemcpy2D的未处理异常

c++ - 模板类 - 未解析的外部 C++ SFML

winapi - 如何在win32 C程序中读取摄像机

android - 在 eglSwapBuffers 之后保留后台缓冲区内容