从左侧resize时,窗口会闪烁

每当我移动窗口并同时resize时,我的窗口似乎都会闪烁。 当从窗口左侧进行尺寸调整时,通常会发生这种情况。

为什么会发生这种闪烁? 换句话说,当您重新定位窗口时,操作系统在做什么?

注意:从右侧resize时,我不会遇到闪烁,这意味着窗口不一定会移动其原点X和Y.

在Windows下调整窗口大小涉及在OS和窗口处理程序之间发送的几条消息(用于注册窗口类的WNDCLASSEX结构的lpfnWndProc成员)。 您可以使用一些消息监视工具自己发现它们。 Visual Studio附带的Spy ++就是这样一个工具。

一个有趣的消息是WM_NCCALCSIZE :在窗口大小调整期间调用的此消息可以生成两个矩形(当设置WVR_VALIDRECTS标志时):source和target指定旧窗口的客户区域的哪些内容可以在新窗口的位置“重用”。 默认情况下,假设左上角是一个枢轴:

  • 调整左边框或上边框的大小会导致旧窗口的内容被复制以保留枢轴;
  • 调整右侧底部边框的大小不会复制任何内容,因为窗口的左上角没有移动。

如果它与重绘期间定位视觉效果的方式不对应,则此默认复制可能会导致闪烁。 例如,从左边框或上边框resize后,相对于右边框或下边框显示的所有内容都会放错位置:这些对象会在resize后不必要地移动,留下奇怪的新旧内容混合,因为只有非复制的像素将被重新粉刷。 如果你试图用InvalidateRect来治愈这个混乱,比如WM_SIZE,你会得到闪烁(事情错位的时间间隔很短,但它仍然存在)。

禁用此行为的最简单方法是为窗口设置CS_HREDRAW和CS_VREDRAW 类样式 。

2018年的更新。

WM_NCCALCSIZE WVR_VALIDRECTS技巧仍然是阻止Windows XP / Vista / 7 SetWindowPos执行导致闪烁的不必要的BitBlt的好方法。

但是,微软再次这样做,在Windows 8/10上,DWM窗口管理器在传统的SetWindowPos BitBlt之上添加了另一层BitBlt ,这可能会导致同样的问题并且更难以解决。

有关不需要的BitBlt导致闪烁的原因的解释,以及WM_NCCALCSIZE WVR_VALIDRECTS技巧的示例代码以及如何防止Windows 8/10 Aero执行相同操作的一些代码提示,请参阅:

如何在调整窗口大小时平滑丑陋的抖动/闪烁/跳跃,尤其是拖动左/上边框(Win 7-10; bg,bitblt和DWM)?