您的位置:首页 > 其它

MFC制作双缓冲无闪烁的字幕滚动条

2010-11-12 22:25 441 查看
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。/article/7245182.html

最近一段时间由于项目需要,需要一个字幕滚动条,所以了解了一下双缓冲的绘图方法。

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+的双缓冲的方法,可以参考http://zjyzjy.blog.51cto.com/329429/67374 (Java)/article/7245180.html (GDI+)。
关于具体的实现,可以参考本文的附件,同样推荐国外的牛人的多线程的实现方法。

本文出自 “持之以恒,刨根问底” 博客,请务必保留此出处/article/7245182.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: