繁体   English   中英

双缓冲winAPI

[英]Double buffering winAPI

好的,因此在我的应用程序中,有一堆winAPI和一些自定义控件。 好极了...

现在,通常情况下,他们将安静地重绘自己以进行动画,状态更改等操作,并且一切正常。

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

发生这种情况时,将绘制背景,然后绘制选项卡控件,然后绘制所有其他控件。 这会引起非常烦人的闪烁,尤其是在调整窗口大小时(由于不断调用fix())。

我尝试过的

  • WS_EX_COMPOSITED。 这只会双重缓冲各个控件。 它是一种改进,但闪烁不可避免。
  • 关闭背景图。 很难解决问题,实际上会使情况更糟。

所以:我需要一种技术/方法/任何东西来允许我对窗口进行整体双重缓冲。 我认为自己处理WM_PAINT消息可能是一种解决方案,但我不知道从哪里开始。 我感到这是不可能的...

请帮助,这是一个关键问题。 这个愚蠢的小问题解决后,我会感到很欣慰。

正是在这个时候,人们意识到了微软对本地开发人员的无视。 实际上,人们可能会开始幻想到,微软故意破坏了本地绘画,以迫使本地开发人员转向WPF。

首先,考虑WS_EX_COMPOSITED WS_EX_COMPOSITED似乎是芥末酱:-它说它对子控件强制执行一个从上到下的绘制顺序,并且基本上是批量处理WM_PAINT消息。 它说它是在Windows 2000(5.0)中添加的,并且只有几行,它在启用桌面合成的情况下不起作用。 即从Windows Vista(6.0)开始,它将停止工作,除非关闭了航空玻璃,然后由谁来做?

然后,有两种可能的“ hacks”尝试使无闪烁的绘画起作用:

  • 首先,您需要最小化过量绘画的数量。 WS_EX_CLIPCHILDREN | WS_EX_CLIPSIBLINGS 必须使用WS_EX_CLIPCHILDREN | WS_EX_CLIPSIBLINGS来确保窗口的任何特定区域仅绘制一次。 BeginDeferWindowPos对于批量调整大小操作也是必要的,以确保不会发生瞬态-在一个窗口与另一个窗口重叠的情况下(即,当窗口A调整大小而窗口B没有调整大小时)。

当然,当您尝试绘制带皮肤的对话框,使用“组”框,选项卡控件或任何其他限制时, WS_EX_CLIPSIBLINGS根本不合适。

  • WM_SETREDRAW是一条神奇的消息。 有没有API来访问此功能: WM_SETREDRAW直接由DefWindowProc函数处理基本上标记窗口隐藏的时间。 WM_SETREDRAW之后WM_SETREDRAW, FALSE将发送WM_SETREDRAW, FALSE ,使用父窗口句柄(及其所有子项)调用GetDC / GetDCEx / GetWindowDC等将返回一个不会在屏幕上绘制的DC。 这样,您就可以对子窗口进行各种处理,完成后发送WM_SETREDRAW,TRUE (然后手动重新绘制窗口)。 当然,所有子窗口都将在自己的时间内绘制,并且在父窗口完成其擦除背景后,因此WM_SETREDRAW并不是万灵药。

破坏WS_EX_COMPOSITED ,在.NET的WinForms和WPF中,从头开始重新编写控件以不使用本机控件,因此它们可以在其中烘焙缓冲绘画。 还有Alpha支持。

在人们匆匆忙忙地重复该主题并将其关闭之前,我要提一下您的问题本身不是双重缓冲,而是在重新放置控件时闪烁,因为“手动”双重缓冲只是几种解决方案之一。

例如, BeginDeferWindowPos和朋友可能可以修复闪烁。

免责声明:我曾经知道Win16 API的几乎所有细节,但是距我进行API级别编程已有好几年了。

干杯,……

–阿尔夫

没有代码,我几乎无法想象实际情况是什么...但是您可以尝试处理WM_ERASEBKGND,只要收到它们就跳过擦除就返回TRUE。

处理窗口的WM_ERASEBKGND ,并在实现中排除每个子控件的rect,然后适当地填充其余背景,并通过返回true告诉框架您自己绘制了背景。 对所有其他子控件执行相同的操作,这些子控件又将其他控件(例如Tab控件)保留在您的案例中。

有关使用MFC的示例,请参见此处

在.net中,应在每个容器窗口(因此主窗口和选项卡)上设置ControlStyle.AllPaintingInWmPaint 我找不到等效的winapi。 但这是将背景绘画从WM_ERASEBKGND移到WM_PAINT。 它还会从父级减去子级控件的面积以避免闪烁,这可能是您需要手动执行此操作。

令我惊讶的是WS_EX_COMPOSITED没有帮助。 如果您在顶级窗口上进行设置,并且不要在子控件上调用RedrawWindow,那应该可以。

还要确保在有和没有DWM / Aero的情况下进行测试。 您可以获得不同的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM