双缓冲winAPI

时间:2010-10-11 06:52:48

标签: c++ winapi double-buffering

好的,所以在我的应用程序中,有一堆winAPI和一些自定义控件。耶...

现在,通常情况下,他们会悄悄地重新绘制自己的动画,状态变化等等......一切正常。

但我有一个名为fix()的类Window方法。只要整个窗口需要更新,就会调用此方法。它调整控件的大小并使窗口无效。

当发生这种情况时,绘制背景,然后绘制标签控件,然后绘制顶部的所有其他标签。这会引起非常恼人的眨眼,特别是在调整窗口大小时(因为不断调用fix())。

我尝试过:

  • WS_EX_COMPOSITED。这只会对各个控件进行双重缓冲。它是一种改进,但闪烁不可避免地存在。
  • 关闭背景图。几乎没有解决问题,实际上让事情变得更糟。

所以:我需要一个技术/方法/任何允许我完全双重缓冲窗口的东西。我认为自己处理WM_PAINT消息可能是一个解决方案,但我不知道从哪里开始。我有一种可怕的感觉,甚至不可能......

请帮助,这是一个关键问题。当这个愚蠢的小问题得到解决时,我会非常放心。

5 个答案:

答案 0 :(得分:5)

正是在这个时候,人们意识到微软的深度无视本土开发者。事实上,人们可能开始怀有偏执狂的妄想,微软有意破坏本土绘画,以迫使本土开发者转向WPF。

首先,考虑WS_EX_COMPOSITEDWS_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进行测试。你可以得到不同的结果。