zoukankan      html  css  js  c++  java
  • Duilib的双缓冲实现,附带GDI、WTL的双缓冲实现

    前言:

     闪烁问题,之前的经验是使用双缓冲,借此机会,把双缓冲的研究心得总结下。

    双缓冲的含义:

               缓冲这个词,相信大家都不陌生,Cache。主要是为了解决上下游(或者模块、或者系统)等性能不匹配问题。如果把上游看成“生产者”,下游看成“消费者”,当“生产者”与“消费者”的处理速度不同时,为了避免干等,中间会加一些缓冲区。

                         

                                                                          无缓冲,双方都容易阻塞。

                        

                                        最常用的生产者-消费者模型,增加弹性缓冲,缺点是每生产+每消费都需要加锁

                 

                                双缓冲,等消费者队列为空时加锁,执行exchange(如swap方法),大大减少了加锁次数。

         

    双缓冲在界面的使用:

                          

            在图形图象处理编程过程中,双缓冲是一种基本的技术。我们知道,如果窗体在响应WM_PAINT消息的时候要进行复杂的图形处理,那么窗体在重绘时由于过频的刷新而引起闪烁现象。解决这一问题的有效方法就是双缓冲技术。因为窗体在刷新时,总要有一个擦除原来图象的过程OnEraseBkgnd,它利用背景色填充窗体绘图区,然后在调用新的绘图代码进行重绘,这样一擦一写造成了图象颜色的反差。当WM_PAINT的响应很频繁的时候,这种反差也就越发明显。于是我们就看到了闪烁现象。
             双缓冲我们会很自然的想到,避免背景色的填充是最直接的办法。但是那样的话,窗体上会变的一团糟。因为每次绘制图象的时候都没有将原来的图象清除,造 成了图象的残留,于是窗体重绘时,画面往往会变的乱七八糟。所以单纯的禁止背景重绘是不够的。我们还要进行重新绘图,但要求速度很快,于是我们想到了使用 BitBlt函数。它可以支持图形块的复制,速度很快。我们可以先在内存中作图,然后用此函数将做好的图复制到前台,同时禁止背景刷新,这样就消除了闪 烁。以上也就是双缓冲绘图的基本的思路。
     

    GDI双缓冲:

           WM_ERASEBKGND : 返回1,禁止背景重绘

             

    HDC hDc = ::GetDC( m_hWnd) ;
    RECT rcDest;
    HDC hMemDc = CreateCompatibleDC(hDc);
    HBITMAP hMemBitmap = CreateCompatibleBitmap(hDc);  //内存画布,放到内存DC中就可以在内存中画图了
    HBITMAP hOldBitmap = ::SelectObject (hDC, hBitmap);
    //....hMemDc作画
    ::BitBlt (m_hDestDC, rc.left, rc.top, rc.Width(), rc.Height(), hDC, rc.left, rc.top, SRCCOPY); //拷贝到显示器缓冲
    
    //资源释放与还原
    ::SelectObject (hDC, hOldBitmap);
    DeleteObject(hMemBitmap);
    DeleteDC(hMemDc);
    ReleaseDC(m_hWnd,hDc);
    

      

    WTL双缓冲:

    CDoubleBufferImpl 在AtlFrame.h中。

    1.首先继承自CDoubleBufferImpl

    class TCtrl: 
            public CWindowImpl< TCtrl>,  
            public WTL::CDoubleBufferImpl<TCtrl>  // 继承双缓冲类

    2.由于双缓冲类中已经处理了WM_ERASEBKGND 和WM_PAINT消息,所以需要从你的代码中删除对这些消息的处理。然后加上双缓冲的消息处理即可。

        BEGIN_MSG_MAP(TCtrl)
    //        MESSAGE_HANDLER(WM_PAINT,        OnPaint)
            CHAIN_MSG_MAP( WTL::CDoubleBufferImpl<TCtrl>)
        END_MSG_MAP()

    3.增加一个DoPaint函数,函数声明如下:

    void DoPaint(CDCHandle dc);

    4.将原来OnPaint函数中的代码移到DoPaint中,注意原来的CPaintDC需要改用参数中的CDCHandler

    void TCtrl::DoPaint( CDCHandle dc )
    {
        //CPaintDC dc(m_hWnd);

    dc.MoveTo( xx… )
    }

    Duilib双缓冲:

        Duilib使用的GDI+引擎,也已经支持双缓冲,这里简单介绍下它的实现过程

        1、Duilib也默认处理了WM_REASEBKGND 并返回1;

            

        2、IRenderContext  类负责渲染。

              目前由RenderContext_GdiPlus来实现。

              1)构造函数中,创建内存DC

             

            2) 获取绘图区域后,创建内存Bitmap

            

         

        

             然后作画,细节暂时略,后续源码剖析会补充,敬请期待。

            

              最后,拷贝到显示器缓冲。

            

  • 相关阅读:
    vue 对图片进行拖拽到另一个位置
    vue自定义拖动指令
    使用pm2启动nodejs+express+mysql管理系统步骤
    重新学习html和css
    vue监听页面大小变化重新刷新布局
    Docker可视化管理工具DockerUI ,Portainer ,Shipyard对比(转)
    js删除html标记 去掉所有html标记 百度文库内容copy
    安卓模拟器连接端口一览表
    springmvc在使用@ModelAttribute注解获取Request和Response会产生线程并发不安全问题(转)
    常用软件测试工具的对比
  • 原文地址:https://www.cnblogs.com/xuhuajie/p/14952268.html
Copyright © 2011-2022 走看看