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

本文介绍了在Windows编程中使用双缓冲技术解决绘图闪烁问题的方法。通过在内存中完成绘图再一次性复制到屏幕,有效避免了复杂的绘图操作导致的画面闪烁。文章详细展示了使用CreateCompatibleDC、CreateCompatibleBitmap等API实现双缓冲的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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.总结

采用双缓冲的方法,可以极大的减少闪烁的现象,提高显示质量。关于 JavaGDI+的双缓冲的方法,可以参考 [url]http://zjyzjy.blog.51cto.com/329429/67374[/url] (Java) [url]http://zjyzjy.blog.51cto.com/329429/67370[/url] (GDI+)
关于具体的实现,可以参考本文的附件,同样推荐国外的牛人的多线程的实现方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值