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); } 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;
2) 双缓冲绘图
//每步向左移动距离
//双缓冲绘图 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_iSho wCount]);
//把内存绘图拷贝到屏幕 pDc->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&;memDC,0,0,SRC COPY); //清理释放 this->ReleaseDC(pDc); memDC.DeleteDC(); memBitmap.DeleteObject(); }
5. 总结
采用双缓冲的方法,可以极大的减少闪烁的现象,提高显示质量。关于 Java 和 GDI+的双缓冲的方法,可以参考[url]zjyzjy.blog.51cto/329429/67374[/url] (
Java) [url]zjyzjy.blog.51cto/329429/67370[/url] (GDI+)。