我开发了一个应用程序来显示JPEG图像。 它可以显示4个图像,每个象限在屏幕上一个。 它使用4个窗口。 窗户没有边框(框架)也没有标题栏。 加载新图像时,会调整新图像的窗口大小,然后显示图像。
特别是当窗户变大时,通常会有闪烁。 用我的眼睛来看,在显示新的内容之前,似乎旧的内容在resize时被移动。
我咨询了很多资源,并使用了所有的技巧:
该窗口只有样式CS_DBLCLKS(无CS_HREDRAW或CS_VREDRAW);
后台刷子是NULL;
WM_ERASEBKGND返回1;
WM_NCPAINT返回0;
WM_NCCALCSIZE告诉alignment到没有移动的一面(你能告诉它放弃客户区?
WM_WINDOWPOSCHANGING返回0;
SetWindowPos有标志SWP_NOCOPYBITS | SWP_DEFERERASE | SWP_NOREDRAW | SWP_NOSENDCHANGING。
但是,当窗口resize时,闪烁(或内容移动)发生。 我想要的是:
将SetWindowPos设置为新的大小和位置;
InvalidateRect(hWnd,NULL,FALSE);
UpdateWindow(HWND);
没有任何绘画,背景删除或内容移动,直到WM_PAINT。 WM_PAINT使用:
hDC= BeginPaint (hWnd, &ps); hMemDC= CreateCompatibleDC (hDC); hOldBitmap = SelectObject (hMemDC, hNewBitmap); BitBlt (hDC,...,hMemDC,0,0,SRCCOPY); SelectObject (hMemDC, hOldBitmap); DeleteDC (hMemDC); EndPaint (hWnd, &ps);
任何人都可以告诉我,如果/我犯了一个错误,导致窗口的旧内容被移动?
硬件等:HP EliteBook Core7 64位上的Windows 7,NVIDIA Quadro K1000m驱动程序9.18.13.3265(更新至341.44)。
更新 (七月七日)
我在另一台Windows电脑(Windows 8/10)上也看到了该程序的行为。 它似乎不是NVIDIA显示驱动程序。
调整屏幕中心(左下angular= w / 2,h / 2)到左上angular或左上angular(0,0)的大小时,行为最明显。
我可能会遇到WM_NCCALCSIZE消息的计算问题,告诉Windows不要做任何事情。 任何人都可以为我的目的举一个计算例子吗? 另请参见当用户调整对话框大小时,如何强制窗口不重绘对话框中的任何内容?
你有一个令人印象深刻的反闪烁技巧列表:-)
我不知道这是否是重要的(因为它取决于如何创建工具窗口,特别是如果他们是一个共同父母的子窗口):尝试在工具窗口的父窗口中设置窗口样式WS_CLIPCHILDREN
(如果有是一个)。
如果没有设置,父窗口将擦除(整个)背景,然后将画图消息转发到子窗口,这将导致闪烁。 如果设置了WS_CLIPCHILDREN
则父窗口对子窗口占用的客户区域不做任何处理。 因此,儿童窗户的面积不是两次绘制,也没有闪烁的机会。
这不仅仅是一个理论而是一个理论:
默认情况下,在现代Windows中,窗口只是显卡上的纹理,桌面窗口管理器将其映射到屏幕上的矩形。 你似乎已经做了一切必要的事情,以确保纹理一举更新。
但是,当您调整窗口大小时,桌面合成器可能立即更新其几何图形,导致(仍然不变)纹理出现在屏幕上的新位置。 只有当你做完绘画之后,纹理才会被更新。
你可以暂时关闭桌面合成来测试这个理论。 在Windows 7上,导航到“系统属性”,选择“高级”选项卡,在“视觉效果”选项卡上的“性能选择设置…”下,取消选择“启用桌面组合”设置。 然后尝试重现该问题。 如果它消失了,那么支持(但不是绝对证明)我的理论。
(请记住重新启用合成,因为这是大多数用户大部分时间都在运行的原因。)
如果这个理论是真的,那么看起来目标就是在窗口调整后尽快到达油漆区。 如果时间窗口足够小,那么两者都可能发生在显示器刷新周期内,并且不会有闪烁。
具有讽刺意味的是,你在这里消除闪烁的努力可能会对你有所帮助,因为你故意压制通常由SetWindowPos导致的失效和重画,直到你在后面的步骤中手动完成。
一个调试技巧:尝试在过程中的关键点引入延迟(例如, Sleep(1000);
),以便您可以看到调整大小和重绘是否实际在屏幕上呈现为两个不同的步骤。
除了你的技巧列表之外。 在使用左/上边缘调整窗口大小的同时,我的戴尔XPS笔记本上的闪烁也有同样的问题。 我已经尝试了你提到的所有技巧。 据我了解,在GPU中绘制窗口边框,并在GDI子系统中准备窗口内容,并将其转移到视频内存以供窗口组成(在Windows 8.1中引入DWM)。 我试图完全删除GDI渲染(设置WS_EX_NOREDIRECTIONBITMAP风格),使窗口没有任何内容,然后直接使用DXGI子系统创建内容表面(使用CreateSwapChainForComposition,有几个例子如何做到这一点)。 但问题依然存在。 渲染窗口框架和调整大小/显示内容表面之间仍然存在滞后。
但是它可以解决你的问题,因为你没有边界,你不会注意到这个滞后。 但是,你将完全控制窗口重绘,它将在GPU端进行。