如何在调整窗口大小时平滑丑陋的抖动/闪烁/跳跃,尤其是拖动左/上边框(Win 7-10;bg、bitblt 和 DWM)? [英] How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?

查看:22
本文介绍了如何在调整窗口大小时平滑丑陋的抖动/闪烁/跳跃,尤其是拖动左/上边框(Win 7-10;bg、bitblt 和 DWM)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:当我抓取我的 Windows 应用程序的调整大小边框,尤其是顶部或左边框,并调整窗口大小时,窗口的内容会调整实时"大小.当我拖动时,但它们以一种可怕的方式调整大小,即使对于最新手的用户来说,这看起来也是一个明显的错误:窗口对面边缘的内容我正在疯狂地拖动抖动/闪烁/来回跳跃.根据情况,现象可能如下所示:

  • 当我们放慢速度或停止拖动时,内容似乎会离开窗口边缘并弹回
  • 似乎进入窗口的内容,被不同颜色的边框间歇性地取代,通常是黑色或白色
  • 严重丑陋的双重形象"内容的两个重叠副本位移的距离与我们拖动的速度/速度成正比

一旦我停止拖动,丑陋的现象就会停止,但在拖动过程中它使应用程序看起来很业余和不专业.

可以毫不夸张地说,这个 Windows 问题让成千上万的应用开发者发疯.

以下是该现象的两张示例图片,为 的现象(注意快速闪光):

任务管理器现象的另一个示例视频是这里.

问题:任何遇到此问题的开发人员都会很快发现至少有 30 个 Stack Overflow 问题,有些是最近的,有些是 2008 年的,其中充满了听起来很有希望但很少奏效的答案.现实情况是,这个问题有多种原因,现有的 Stack Overflow 问题/答案从未使更广泛的上下文变得清晰.这个问题试图回答:

  • 这种难看的抖动/闪烁/跳跃的最可能原因是什么?
  • 如何判断我看到的是哪个原因?
  • 这是特定图形驱动程序的特定原因还是 Windows 的通用原因?
  • 我该如何解决每个原因?应用程序可以修复它吗?

(这是一个规范的问答,用于解释窗口调整大小抖动的所有不同原因,以便用户可以确定导致问题的原因并解决它.正如答案所解释的,上述所有排列(本机/托管、窗口/对话框、XP-10)归结为只有两个根本原因,但确定您拥有的是哪个是棘手的部分.)

这个问题的范围:对于这个问题的范围,这种现象发生在:

  • 本机 Win32 和托管 .NET/WPF/Windows Forms 应用
  • 普通的 Win32 窗口和 Win32 对话框窗口
  • Windows 版本,包括 XP、Vista、7、8 和 10(但请参阅下文了解多种原因的黑暗真相)

不在本问题的范围内:

  • 如果您的应用有一个或多个子窗口(子 HWND),则此问题中的信息对您有用(因为我们将描述的引起混蛋的 BitBlts 应用于您的子窗口以及父窗口),但是在调整窗口大小期间,您还有一个额外的问题需要处理,这超出了本问题的范围:您需要让所有子窗口自动移动并与父窗口同步.对于此任务,您可能需要 BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos 并且您可以了解它们 此处此处.

  • 这个问题假设如果您的应用程序使用 GDI、DirectX 或 OpenGL 绘制到窗口,那么您已经在您的 wndproc 中实现了一个 WM_ERASEBKGND 处理程序它只是返回 1.WM_ERASEBKGND 是 Windows 3.1 的神秘 Windows 残余,它出现在 WM_PAINT 之前,让您的应用程序有机会擦除背景";在你画你的窗户之前你的窗户......嗯.如果你让 WM_ERASEBKGND 消息进入 DefWindowProc(),这将导致你的整个窗口在每次重绘时都被涂上纯色,通常是白色,包括发生的重绘在实时窗口调整大小期间.结果是丑陋的全窗口闪烁,但不是我们在这个问题中谈论的抖动/闪烁/跳跃类型.拦截 WM_ERASEBKGND 立即修复了这个问题.

  • 这个问题主要是关于通过用鼠标拖动窗口边框来实时调整大小.然而,这里写的大部分内容也适用于当应用程序使用 SetWindowPos() 手动调整一次窗口大小时您可以看到的丑陋工件.但它们不太明显,因为它们只在屏幕上轻弹一瞬间,而不是长时间拖动.

  • 这个问题不是关于如何让你的应用程序特定的绘图代码运行得更快,尽管这样做在许多情况下可能是解决丑陋的调整大小问题的方法.如果您的应用在实时窗口调整大小期间确实需要大量时间来重新显示其内容,请考虑优化您的绘图代码,或者至少在调整大小期间通过拦截 WM_ENTERSIZEMOVE/WM_EXITSIZEMOVE 切换到更快、质量较低的绘图模式 检测调整大小的消息.

  • 如果您的应用程序在调整大小期间根本无法调整大小(例如,在调整大小期间挂起",特别是如果它是使用 GLFW 或其他库的 OpenGL),请参阅这些其他问题,这些问题解释了有关 Microsoft 可怕的嵌套/拖动过程中 WM_SYSCOMMAND 内的模态事件循环:这里 特别是这个好答案a>,这里这里此处,以及此处.

解决方案

目录

因为这是一个复杂的多方面问题,我建议您按以下顺序阅读答案:

以及可以帮助其他人收集见解的源材料列表:

请随时以创造性的方式提供更多答案,以避免出现 2a 尤其是 2b 中描述的问题!

THE PROBLEM: When I grab the resize border of my Windows app, especially the top or left borders, and resize the window, the contents of the window do resize "live" as I drag, but they resize in a hideous manner that looks like a blatant bug to even the most novice user: the contents at the opposite edge of the window from the edge I am dragging jitter/flicker/jump back and forth wildly. Depending on the situation, the phenomenon may look like:

  • contents that seem to walk off the edge of the window and snap back when we slow down or stop dragging
  • contents that seem to pull into the window, intermittently displaced by a border of varying colors, often black or white
  • a seriously ugly "double image" with two overlapping copies of the content displaced by a distance proportional to how much/how fast we are dragging

The ugly phenomenon stops as soon as I stop dragging, but during the dragging it makes the app look amateurish and unprofessional.

It is not an understatement to say this Windows problem has driven thousands of app developers crazy.

Here are two example pictures of the phenomenon, kindly prepared for a related question by Roman Starkov:

Jitter:

Border:

Another example showing the evil "double image" phenomenon (note the quick flash) from Kenny Liu:

Another example video of the phenomenon with Task Manager is here.

THE QUESTION: Any developer who has experienced this problem quickly finds that there are at least 30 Stack Overflow questions, some recent and some dating from 2008, full of promising-sounding answers that rarely work. The reality is that this one problem has many causes, and the existing Stack Overflow questions/answers never make the wider context clear. This question seeks to answer:

  • what are the most likely causes of this kind of ugly jitter/flicker/jumping?
  • how do I tell which cause I am seeing?
  • is this cause specific to particular graphics drivers or general for Windows?
  • how do I fix each cause? can an app fix it?

(This is meant as a canonical Q&A to explain all the different causes of window resize jitter so that users can identify which of the causes is causing their problem and solve it. As the answers explain, all the permutations above (native/managed, window/dialog, XP-10) boil down to only two root causes, but identifying which you have is the tricky part.)

SCOPE OF THIS QUESTION: For the scope of this question, the phenomenon happens with:

  • both native Win32 and managed .NET/WPF/Windows Forms apps
  • both normal Win32 windows and Win32 Dialog windows
  • Windows versions including XP, Vista, 7, 8, and 10 (but see below for the dark truth of multiple causes)

NOT IN SCOPE OF THIS QUESTION:

  • If your app has one or more child windows (child HWNDs), the info in this question is useful to you (since the jerk-causing BitBlts we will describe are applied to your child windows along with the parent window), but during window resize you have an additional problem to handle that is beyond the scope of this question: you need to make all your child windows move atomically and in sync with the parent window. For this task, you will probably want BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos and you can find out about them here and here.

  • This question assumes that if your app draws to a window using GDI, DirectX, or OpenGL, then you have already implemented a WM_ERASEBKGND handler in your wndproc that simply returns 1. WM_ERASEBKGND is an arcane Windows remnant from Windows 3.1 that comes before WM_PAINT to give your app a chance to "erase the background" of your window before you draw your window...uh huh. If you let the WM_ERASEBKGND message go into DefWindowProc(), that will cause your entire window to get painted a solid color, usually white, on each redraw, including redraws that happen during live window resizing. The result is an ugly full-window flicker that is gross, but not the type of jitter/flicker/jumping we are talking about in this question. Intercepting WM_ERASEBKGND fixes this problem immediately.

  • This question is primarily about live-resize by dragging window borders with the mouse. However, much of what is written here also applies to ugly artifacts you can see when an app manually does a one-time window resize using SetWindowPos(). These are less visible though because they only flick on the screen for one instant, rather than over a long period of dragging.

  • This question is not about how to make your app-specific drawing code go faster, even though doing so may be a solution to the ugly resizing problem in many cases. If your app really does take huge amounts of time to redisplay its contents during live window resize, consider optimizing your drawing code in general or at least switching to a faster, lower-quality drawing mode during resize by intercepting the WM_ENTERSIZEMOVE/WM_EXITSIZEMOVE messages to detect resize.

  • If your app fails to resize at all during app resizing (e.g. it "hangs" during resizing, especially if it is OpenGL using GLFW or other library), see these other questions which explain about Microsoft's hideous nested/modal event loop inside WM_SYSCOMMAND during dragging: here especially this good answer, here, here, here, and here.

解决方案

Table of Contents

Because this is a complex, multi-faceted issue, I recommend reading the answers in this order:

as well as a list of source material which may help others glean insights:

Please feel free to contribute more answers with creative ways of avoiding the problems described in 2a and especially 2b!

这篇关于如何在调整窗口大小时平滑丑陋的抖动/闪烁/跳跃,尤其是拖动左/上边框(Win 7-10;bg、bitblt 和 DWM)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆