最近一段時間由於項目需要,需要一個字幕滾動條,所以瞭解了一下雙緩衝的繪圖方法。
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+)。
關於具體的實現,可以參考本文的附件,同樣推薦國外的牛人的多線程的實現方法。