从左侧调整大小时,窗口会闪烁

时间:2014-01-06 20:21:28

标签: c++ c winapi

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

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

注意:从右侧调整大小时不会出现闪烁,这意味着窗口不一定会移动其原点X和Y.

2 个答案:

答案 0 :(得分:5)

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

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

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

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

禁用此行为的最简单方法是为您的窗口设置CS_HREDRAW和CS_VREDRAW Class Styles

答案 1 :(得分:0)

2018年更新。

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

但是,Microsoft又做了一次,并且在Windows 8/10上,DWM窗口管理器在旧版BitBlt SetWindowPos的顶部添加了BitBlt的另一层,这可能导致相同的问题并且更难解决。

有关不想要的BitBlt导致闪烁的原因的解释,以及WM_NCCALCSIZE WVR_VALIDRECTS技巧的示例代码以及一些有关如何防止Windows 8/10 Aero出现的代码提示这样做,请参阅:

How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?