下面只是简要介绍了防止窗口闪烁的一般方法,也是我最常用到的。
- 窗口的移动或改变大小是要导致窗口重绘的,所以如果客户区上存在两个子窗口A和B,且A和B都需要移动或改变大小(参考分隔条的情况),那么势必会导致客户区重绘两次。当然MoveWindow和SetWindowPos貌似都提供了处理窗口但不重绘的参数,不过我还是建议使用DeferWindowPos。
- 在DC上画图,如果绘制的内容过多,那么将会导致DC的频繁闪烁。这个问题的解决方法是为目标DC创建一块兼容DC,然后在兼容DC上绘制,待绘制完毕后再将所有内容贴至原始DC上。这种方法也就是常说的“双缓冲”。
- 当然,有的时候即使采用了双缓冲,仍然会看到明显的闪烁(比如在定时器中调用InvalidateRect刷新客户区)。这是由于在窗口重绘的时候,首先要用窗口的画刷填充整个窗口DC,然后再执行WM_PAINT中的内容。根本的解决办法是将窗口类的画刷设为NULL_BRUSH,这样就看不到闪烁了。
- 此外,还可以通过发送WM_SETREDRAW消息、处理WM_ERASEBKGND消息、用InvalidateRect进行局部刷新、去掉窗口类的CS_HREDRAW/CS_VREDRAW样式、为窗口添加WS_CLIPCHILDREN/WS_CLIPSIBLINGS样式的方法来解决某些特定的闪烁问题。这些方法我没有尝试过,因为它们只是在闪烁的根本原因上打了擦边球,没有触及本质。
当然可能还存在更好的办法,欢迎大家一起讨论。