最近一段时间由于项目需要,需要一个字幕滚动条,所以了解了一下双缓冲的绘图方法。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

1.       闪烁产生原因

首先,介绍一下为什么会产生闪烁。我们在绘图时收到WM_PAINT消息后,系统会调用默认的画刷来填充被Invalidate 的区域,这样由于时间差的原因,会产生闪烁的现象。

2.       双缓冲原理

双缓冲使用内存缓冲区来解决由多重绘制操作造成的闪烁问题。 当启用双缓冲时,所有绘制操作首先呈现到内存缓冲区,而不是屏幕上的绘图图面。所有绘制操作完成后,内存缓冲区直接复制到与其关联的绘图图面。因为在屏幕上只执行一个图形操作,所以消除了由复杂绘制操作造成的图像闪烁。
 

3. 相关的函数介绍

 

1)   为屏幕 DC 创建兼容的内存 DC CreateCompatibleDC()

if(!m_dcMemory.CreateCompatibleDC(NULL)) // CDC m_dcMemory;

{

    ::PostQuitMessage(0);

}

2)   创建位图 CreateCompatibleBitmap()

m_Bmp.CreateCompatibleBitmap(&m_dcMemory, rt.Width(), rt.Height()); // CBitmap m_Bmp;

3)   把位图选入设备环境 SelectObject() 可以理解为选择画布

::SelectObject(m_dcMemory.GetSafeHdc(), m_Bmp);

4)   把绘制好的图形“拷贝“到屏幕上:BitBlt()

pdcView->BitBlt(0, 0, rt.Width(), rt.Height(), &m_dcMemory, 0, 0, SRCCOPY);

详细的函数可以查看MSDN

 

4. 本例中的实现

1)  OnTime的时候调用 DrawHorizontalText 方法

void CScrollMessageDlg :: OnTimer ( UINT nIDEvent )

{

// TODO: Add your message handler code here and/or call default

DrawHorizontalText ();

CDialog :: OnTimer ( nIDEvent );

}

2)  双缓冲绘图

void CScrollMessageDlg :: DrawHorizontalText ()

{

 

       // 若当前要显示的消息为空

       // 清除显示区域

       if (! m_lsShowMessage . size ())

       {

              Invalidate (); // 调用默认画刷 m_Brush 把整个区域涂黑

              return;

       }

 

       // 计算当前滚动文字的文字

       if( m_StringCurrentPos < - ( m_lsShowMessage [ m_iShowCount ]. GetLength ()* \

              m_logFont . lfWidth + m_logFont . lfWidth ))

       {

              m_iShowCount = (++ m_iShowCount ) % m_lsShowMessage . size ();

              m_StringCurrentPos = m_SystemMetricsCX // 回到起始位置

       }

       // 判断是否暂停,若非,右距离减一

       if(! m_isPause )

              m_StringCurrentPos = m_StringCurrentPos - 1;  // 每步向左移动距离

 

 

       // 双缓冲绘图

       CRect rect ;

       CDC * pDc ; // 屏幕绘图设备

       CDC memDC ; // 内存绘图设备

      

       GetClientRect (& rect );     

       pDc = this-> GetDC (); // 指针

       CBitmap memBitmap ;

       // 创建内存绘图设备

       memDC . CreateCompatibleDC ( NULL );              

       memBitmap . CreateCompatibleBitmap ( pDc , rect .right, rect . bottom );

       memDC . SelectObject (& memBitmap );

      

       // 自定义绘图函数

      

       memDC . FillSolidRect (0,0, rect . Width (), rect . Height (), RGB (155,0,0));

       memDC . SelectObject (& m_font );

       memDC . SetTextColor ( RGB (255,180,0));

       memDC . SetBkMode ( TRANSPARENT );

      

       memDC . Rectangle (& rect );

       memDC . FillRect (& rect ,& m_brush );

      memDC . TextOut ( m_StringCurrentPos , m_iYLocation , m_lsShowMessage [ m_iShowCount ]);   

      

      

       // 把内存绘图拷贝到屏幕

       pDc -> BitBlt ( rect .left, rect . top , rect .right, rect . bottom ,& memDC ,0,0, SRCCOPY );

             

       // 清理释放

       this-> ReleaseDC ( pDc );

       memDC . DeleteDC ();

       memBitmap . DeleteObject ();

             

}

5. 总结

采用双缓冲的方法,可以极大的减少闪烁的现象,提高显示质量。关于 Java GDI+ 的双缓冲的方法,可以参考 [url]http://zjyzjy.blog.51cto.com/329429/67374[/url] (Java) [url]http://zjyzjy.blog.51cto.com/329429/67370[/url] (GDI+)

关于具体的实现,可以参考本文的附件,同样推荐国外的牛人的多线程的实现方法。