代码之家  ›  专栏  ›  技术社区  ›  djeidot

使用GDI+和C++减少闪烁

  •  20
  • djeidot  · 技术社区  · 16 年前

    我在C++/MFC应用程序中使用GDI+,每次调整窗口大小时,我似乎都无法避免闪烁。

    我已经尝试了以下步骤:

    • OnEraseBkGnd() ;
    • 在上返回空值 OnCtlColor() ;

    void vwView::OnDraw(CDC* pDC) 
    {
       CRect rcClient;
       GetClientRect(rcClient);
    
       Bitmap bmp(rcClient.Width(), rcClient.Height());
       Graphics graphics(&bmp);
    
       graphics.DrawImage(m_image, rcClient.left, rcClient.top);
    
       Graphics grph(pDC->m_hDC);
       grph.DrawImage(&bmp, 0, 0);
    }
    

    6 回复  |  直到 16 年前
        1
  •  43
  •   Community CDub    4 年前

    全部的 在屏幕更新之间的间隔内绘制。对于普通的窗口绘制,Windows不提供任何简单的方法来实现这一点(Vista通过 DWM ,但这一点即使在运行Vista的系统上也不可靠)。因此,要使闪烁最小化,最好是尽快绘制所有内容( 减少 通过增加在刷新周期内完成所有绘图的机会来进行撕裂),并避免过度绘制(绘制屏幕的一部分,然后在顶部绘制其他内容:可能会给用户呈现部分绘制的屏幕)。

    • 无所事事 OnEraseBkgnd() :通过防止窗口的无效区域被窗口的背景色填充,有助于避免过度绘制。当您将在绘图过程中再次绘制整个区域时非常有用 WM_涂料 处理 无论如何 ,与双缓冲绘图的情况相同。。。但是看到了吗 关于防止在使用后绘图以避免透支的注意事项 WM_涂料 方法 .

    • 为返回空值 OnCtlColor() 任何东西 ... 除非窗体上有子控件。在这种情况下,请参见 WM_涂料 方法 相反

    • 双缓冲绘图 :通过将屏幕上的实际图形减少为单个图形,有助于避免撕裂(以及可能的过度拉伸) BitBLT . 但可能会影响绘图所需的时间:无法使用硬件加速(尽管使用GDI+,使用任何硬件辅助绘图的可能性都很小),必须为每次重画创建并填充屏幕外位图,并且必须为每次重画重新绘制整个窗口。看见 关于有效双缓冲的注记 .

    • 对BitBlt使用GDI调用而不是GDI+ 这通常是个好主意- Graphics::DrawImage() 可能会很慢。我甚至找到了正常的GDI BitBlt() 在某些系统上调用以加快速度。尝试一下这个,但先尝试一些其他建议。

    • 避免在每次调整大小时强制完全重画的窗口类样式( , :这会有帮助,但前提是你不这样做 需要 在大小更改时重新绘制整个窗口。

    WM_涂料

    ,如果使用的是子窗口,则必须确保父窗口不会同时擦除屏幕区域。这个 应在所有父窗口上设置样式-这将防止绘制子窗口(包括视图)占用的区域。

    WM_涂料 方法

    任何 在窗体上托管的子控件中,您将希望使用 WS_儿童 设置样式以避免在它们上面绘制(并随后被它们过度绘制)。请注意,这会在一定程度上影响BitBlt例程的速度。

    现在,每次视图绘制自身时,都要创建一个新的后缓冲区图像。对于较大的窗口,这可能表示分配和释放了大量内存,以及 导致严重的性能问题。我建议在视图对象中保留一个动态分配的位图,根据需要重新分配它以匹配视图的大小。

    请注意,在调整窗口大小时,这将导致与当前系统一样多的分配,因为每个新的大小都需要分配一个新的后缓冲区位图以匹配它-您可以通过将维度舍入到第二大倍数4、8、16等来减轻痛苦。,允许您避免在每个微小的大小变化上重新分配。

    请注意,如果自上次渲染到后台缓冲区后窗口的大小没有改变,则在窗口无效时不需要重新渲染,只需将已渲染的图像拖到屏幕上即可。

    另外,分配一个匹配屏幕位深度的位图。的构造函数 Bitmap 您当前使用的将默认为32bpp,ARGB布局;如果与屏幕不匹配,则必须对其进行转换。考虑使用GDI方法 CreateCompatibleBitmap()

        2
  •  4
  •   Mark Ransom    16 年前

        3
  •  3
  •   Frederik Slijkerman    16 年前

    确保窗口的窗口类在其样式中不包含CS_VREDRAW和CS_HREDRAW标志。

    看见 http://msdn.microsoft.com/en-us/library/ms633574(VS.85).aspx

        4
  •  3
  •   rogerdpack    9 年前

    通过使用,您可能会获得一些牵引力 Direct3D 告诉你什么时候发生vsync等等,这样你就可以在适当的时候进行BitBlt/更新。看见 GDI vsync to avoid tearing (尽管在某些情况下,将事情简化到一个小比特可能“足够好”)。

    还请注意,GDI BitBlt似乎与屏幕vsync不同步。看见 Faster than BitBlt .

        5
  •  2
  •   Liam    11 年前

    此链接包含一些有用的信息: http://www.catch22.net/tuts/flicker-free-drawing

    (我知道这是一个非常晚添加到线程,但这是为任何人(像我一样)谁发现它时,寻找减少闪烁在我的Win32应用程序…)

        6
  •  0
  •   Chris Becke    16 年前

    如果这是你的情况。。。使用Vistas new aero look可以解决您的问题,因为aero桌面窗口管理器会自动进行窗口合成。对于较旧的窗口管理器,这是一个pita。