好的,所以在我的应用程序中,有一堆 winAPI 和一些自定义控件。耶...
现在,通常情况下,他们会静静地重绘自己以进行动画、状态更改等......并且一切正常。
但是我有一个名为 fix() 的 Window 类方法。每当需要更新整个窗口时都会调用此方法。它会调整控件的大小并使窗口无效。
发生这种情况时,将绘制背景,然后是选项卡控件,然后是顶部的所有其他控件。这会导致非常烦人的闪烁,尤其是在调整窗口大小时(因为不断调用 fix())。
我尝试过的:
- WS_EX_COMPOSITED。这只会对各个控件进行双重缓冲。这是一种改进,但闪烁不可避免地仍然存在。
- 关闭背景绘制。几乎没有解决问题,反而使事情变得更糟。
所以:我需要一种技术/方法/任何东西来允许我对整个窗口进行双缓冲。我认为自己处理 WM_PAINT 消息可能是一种解决方案,但我不知道从哪里开始。我有一种可怕的感觉,这甚至是不可能的......
请帮助,这是一个关键问题。当这个愚蠢的小问题得到解决时,我会感到非常欣慰。
最佳答案
正是在这个时候,人们才意识到微软对原生开发者的漠视有多深。事实上,人们可能开始怀有偏执的错觉,认为 Microsoft 故意破坏原生绘画以迫使原生开发人员转向 WPF。
首先,考虑WS_EX_COMPOSITED
。 WS_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/