好的,所以在我的应用程序中,有一堆winAPI和一些自定义控件。耶...
现在,通常情况下,他们会悄悄地重新绘制自己的动画,状态变化等等......一切正常。
但我有一个名为fix()的类Window方法。只要整个窗口需要更新,就会调用此方法。它调整控件的大小并使窗口无效。
当发生这种情况时,绘制背景,然后绘制标签控件,然后绘制顶部的所有其他标签。这会引起非常恼人的眨眼,特别是在调整窗口大小时(因为不断调用fix())。
我尝试过:
所以:我需要一个技术/方法/任何允许我完全双重缓冲窗口的东西。我认为自己处理WM_PAINT消息可能是一个解决方案,但我不知道从哪里开始。我有一种可怕的感觉,甚至不可能......
请帮助,这是一个关键问题。当这个愚蠢的小问题得到解决时,我会非常放心。
答案 0 :(得分:5)
正是在这个时候,人们意识到微软的深度无视本土开发者。事实上,人们可能开始怀有偏执狂的妄想,微软有意破坏本土绘画,以迫使本土开发者转向WPF。
首先,考虑WS_EX_COMPOSITED
。 WS_EX_COMPOSITED
似乎是芥末: - 它表示它对子控件强制执行顶部绘制顺序,并且基本上WM_PAINT消息可以批量处理。它说它是在Windows 2000(5.0)中添加的,并且,几行,它不适用于启用桌面组合。即它在Windows Vista(6.0)中停止工作,除非关闭航空玻璃并且谁会这样做?
然后,有两种可能的“黑客”试图让无闪烁的绘画工作:
WS_EX_CLIPCHILDREN | WS_EX_CLIPSIBLINGS
是必要的,以确保窗口的任何特定区域仅涂一次。批量调整操作以确保瞬态状态(一个窗口与另一个窗口重叠)不会发生(例如,窗口A已调整大小但窗口B没有)时,BeginDeferWindowPos
也是必要的。当然,当您尝试绘制蒙皮对话框,或使用“组”框或选项卡控件或任何其他限制时,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中重新编写控件从不使用本机控件,因此他们可以在那里进行缓冲绘画。还有alpha支持。
答案 1 :(得分:1)
嗯。在人们涌入并关闭这个主题作为重复之前,我最好提一下你的问题不是双缓冲本身,而是重新定位控件时闪烁,“手动”双缓冲只是几种解决方案中的一种。
可能是这样的,例如BeginDeferWindowPos
&朋友们可以解决这个问题。
免责声明:我曾经知道Win16 API的几乎所有细节,但是自从我进行API级编程已经有好几年了。
干杯&第h。,
- Alf
答案 2 :(得分:0)
没有代码,我很难想象实际情况是什么...... 但是你可以尝试处理WM_ERASEBKGND,每当你收到它们时都返回TRUE以跳过擦除。
答案 3 :(得分:0)
为您的窗口处理WM_ERASEBKGND
并在实现中排除每个子控件的部分,然后适当地填充剩余的背景,并通过返回true
告诉框架您已经绘制了背景。 。
对所有其他子控件执行相同的操作,而这些控件又支持其他控件,例如选项卡控件。
有关使用MFC的示例,请参阅here。
答案 4 :(得分:0)
在.net中有ControlStyle.AllPaintingInWmPaint
应该在每个容器窗口上设置(所以主窗口和选项卡)。我找不到相同的winapi。但这样做的目的是将背景绘画从WM_ERASEBKGND移动到WM_PAINT。
它还从父级中减去子控件的区域以避免闪烁,可能需要手动执行此操作。
我很惊讶WS_EX_COMPOSITED没有帮助。如果你在顶级窗口设置它,并且不在子控件上调用RedrawWindow,那应该可行。
还要确保使用和不使用DWM / Aero进行测试。你可以得到不同的结果。