windows - 调整窗口大小时如何平滑丑陋的抖动/闪烁/跳跃,尤其是拖动左/上边框(Win 7-10;bg、bitblt 和 DWM)?

标签 windows winapi resize directx window-resize

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

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

  • 一旦我停止拖动,丑陋的现象就会停止,但在拖动过程中它使应用程序看起来很业余和不专业。
    毫不夸张地说,这个 Windows 问题有 让成千上万的应用开发者疯狂 .
    以下是该现象的两张示例图片,请为 a related question 做好准备来自 Roman Starkov :
    抖动:
    example 1: jitter
    边界:
    example 2: border
    另一个例子显示了来自 Kenny Liu 的邪恶“双像”现象(注意快速闪光) :
    example 2: double-image
    任务管理器现象的另一个示例视频是 here .
    问题:任何遇到过这个问题的开发人员很快就会发现,至少有 30 个 Stack Overflow 问题,有些是最近的,有些是 2008 年的,充满了听起来很有希望但很少奏效的答案。现实是这个问题有多种原因 ,并且现有的 Stack Overflow 问题/答案从未使更广泛的上下文变得清晰。这个问题试图回答:
  • 这种丑陋的抖动/闪烁/跳跃的最可能原因是什么?
  • 我怎么知道我看到的是哪个原因?
  • 这是特定于特定图形驱动程序的原因还是 Windows 的一般原因?
  • 我如何解决每个原因?一个应用程序可以修复它吗?

  • (这是一个规范的问答,用于解释窗口调整大小抖动的所有不同原因,以便用户可以确定是哪个原因导致了他们的问题并解决了它。正如答案所解释的,上面的所有排列( native /托管,窗口/dialog, XP-10) 归结为只有两个根本原因,但确定您拥有的是哪个是棘手的部分。)
    此问题的范围:对于这个问题的范围,这种现象发生在:
  • native Win32 和托管 .NET/WPF/Windows 窗体应用程序
  • 普通 Win32 窗口和 Win32 对话框窗口
  • Windows 版本,包括 XP、Vista、7、8 和 10(但请参阅下文了解多种原因的黑暗真相)

  • 不在此问题的范围内:
  • 如果您的应用程序有一个或多个子窗口(子 HWND),则此问题中的信息对您很有用(因为我们将描述的 jerk-causing BitBlts 与父窗口一起应用于您的子窗口),但在窗口调整大小您有一个额外的问题需要处理,这超出了这个问题的范围:您需要让所有子窗口自动移动并与父窗口同步。对于此任务,您可能需要 BeginDeferWindowPos/DeferWindowPos/EndDeferWindowPos你可以了解他们herehere .
  • 这个问题假设如果您的应用程序使用 GDI、DirectX 或 OpenGL 绘制到窗口,那么您已经实现了 WM_ERASEBKGND您的 wndproc 中的处理程序只返回 1。WM_ERASEBKGND是来自 WM_PAINT 之前的 Windows 3.1 的神秘 Windows 残余让您的应用程序有机会在您绘制窗口之前“删除背景”……嗯。如果你让WM_ERASEBKGND留言进入DefWindowProc() ,这将导致您的整个窗口在每次重绘时都被涂上纯色,通常是白色,包括在实时窗口调整大小期间发生的重绘。结果是丑陋的全窗口闪烁,但不是我们在这个问题中谈论的抖动/闪烁/跳跃类型。拦截WM_ERASEBKGND立即修复此问题。
  • 这个问题主要是关于通过用鼠标拖动窗口边框来实时调整大小。然而,这里写的大部分内容也适用于当应用程序使用 SetWindowPos() 手动调整一次性窗口大小时您可以看到的丑陋工件。 .但它们不太明显,因为它们只在屏幕上轻弹一瞬间,而不是长时间拖动。
  • 这个问题不是关于如何让你的特定于应用程序的绘图代码运行得更快,尽管这样做在许多情况下可能是解决丑陋的调整大小问题的方法。如果您的应用程序在实时窗口调整大小期间确实需要大量时间来重新显示其内容,请考虑优化您的绘图代码,或者至少在调整大小期间通过拦截 WM_ENTERSIZEMOVE/WM_EXITSIZEMOVE 切换到更快、质量较低的绘图模式。消息来检测调整大小。
  • 如果您的应用程序在调整大小期间根本无法调整大小(例如,在调整大小期间“挂起”,特别是如果它是使用 GLFW 或其他库的 OpenGL),请参阅这些其他问题,这些问题解释了 Microsoft 在 WM_SYSCOMMAND 中可怕的嵌套/模态事件循环拖动过程中:here特别this good answer , here , here , here , 和 here .
  • 最佳答案

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

  • 第 1 部分:What Makes Resize Look Good or Bad?
  • 第 2 部分:Identifying and Fixing Windows Resize Problems
  • 2a:调整大小问题来自 SetWindowPos() BitBlt和背景填充
  • 2b:从 DWM 组合填充调整大小问题
  • 2c:如何诊断您的问题


  • 以及可以帮助其他人收集见解的源 Material 列表:
  • 第 3 部分:Gallery of Sorrow: Annotated List of Related Links

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

    关于windows - 调整窗口大小时如何平滑丑陋的抖动/闪烁/跳跃,尤其是拖动左/上边框(Win 7-10;bg、bitblt 和 DWM)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53000291/

    相关文章:

    windows - 如何使用 VBScript、命令行或其他方式获取 .m4v 格式电影的运行时长度?

    c - PostMessage 和 HWND_BROADCAST

    c++ - 编辑 EDIT 导致程序崩溃

    wxpython - wx小部件/wxPython : Resizing a wxFrame while keeping aspect ratio

    html - CSS 防止表格单元格垂直扩展

    javascript - 如何禁用 _moz_resizing?

    c++ - 为什么 MinGW-w64 需要手动包含 winsock2?

    c++ - 如何在 Windows 中比较可能的替代文件名?

    windows - 批处理脚本不再起作用?

    c - 如何并行化 Windows 消息循环和 Hook 回调逻辑及其创建的 Ruby 线程?