一、雙緩沖實現過程如下:
1、在內存中創建與畫布一致的緩沖區
BufferBmp=new Graphics::TBitmap();
BufferBmp->Canvas->Handle=CreateCompatibleDC(Canvas->Handle);
BufferBmp->Width=Width;
BufferBmp->Height=Height;
2、在緩沖區畫圖
BufferBmp->Canvas->Brush->Color=clBtnFace;
BufferBmp->Canvas->FillRect(Rect(0,0,Width,Height));
BufferBmp->Canvas->MoveTo(…);
…………………………
3、將緩沖區位圖拷貝到當前畫布上
BitBlt(Canvas->Handle,0,0,Width,Height,BufferBmp->Canvas->Handle,0,0,SRCCOPY);
4、釋放內存緩沖區
delete BufferBmp;
二、如何實現雙緩沖
首先給出實現的程序,然后再解釋,同樣是在OnDraw(CDC *pDC)中:
CDC MemDC; //首先定義一個顯示設備對象
CBitmap MemBitmap;//定義一個位圖對象
//隨后建立與屏幕顯示兼容的內存顯示設備
MemDC.CreateCompatibleDC(NULL);
//這時還不能繪圖,因為沒有地方畫 ^_^
//下面建立一個與屏幕顯示兼容的位圖,至於位圖的大小嘛,可以用窗口的大小
MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight);
//將位圖選入到內存顯示設備中
//只有選入了位圖的內存顯示設備才有地方繪圖,畫到指定的位圖上
CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
//先用背景色將位圖清除干凈,這里我用的是白色作為背景
//你也可以用自己應該用的顏色
MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255));
//繪圖
MemDC.MoveTo(……);
MemDC.LineTo(……);
//將內存中的圖拷貝到屏幕上進行顯示
pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY);
//繪圖完成后的清理
MemBitmap.DeleteObject();
MemDC.DeleteDC();
三、實例
(1)
CDC *pDC = this->GetWindowDC();
CDC* DCTemp = new CDC;
DCTemp->CreateCompatibleDC(pDC);
CBitmap* m_pTempImage = new CBitmap;
m_pTempImage->CreateCompatibleBitmap(pDC,240,320);
CBitmap* m_bitOldMap = DCTemp->SelectObject(m_pTempImage);
DCTemp->BitBlt(0,0,240,320,pDC,0,0,SRCCOPY);
pDC->BitBlt(0,0,240,320,DCTemp,0,0,SRCCOPY);
DCTemp->SelectObject(m_bitOldMap);
m_pTempImage->DeleteObject();
if (m_pTempImage)
{
delete m_pTempImage;
m_pTempImage = NULL;
}
DCTemp->DeleteDC();
ReleaseDC(pDC);
(2)
HDC hdc = ::GetDC(GetSafeHwnd());
//-------------------------------------------------
// 繪制區域背景
if (m_pImgTitle)
{
m_pImgTitle->Draw(hdc, CRect(110, 0, 240, 30), NULL);
}
//-------------------------------------------------
HFONT HFont;
InitHFont(HFont, 14);
int nMode = ::SetBkMode(hdc,TRANSPARENT);
HFONT oldHFont = (HFONT)::SelectObject(hdc, HFont);
::SetTextColor(hdc, RGB(255,255, 255));
CString strDrawText;
if (m_bIsChange && m_bWeatherIsShow)
{
strDrawText.Format(TEXT("%s %s %s"), m_cityName, m_weatherInfo, m_temperature);
}
else
{
//CTime time = CTime::GetCurrentTime();
//strDrawText = time.Format(TEXT("%H:%M:%S"));
SYSTEMTIME curTime;
GetLocalTime(&curTime);
strDrawText.Format(_T("%d:%.2d:%.2d"),curTime.wHour,curTime.wMinute,curTime.wSecond);
}
::DrawText(hdc, strDrawText, strDrawText.GetLength(), CRect(110, 0, 235, 30), DT_WORDBREAK | DT_RIGHT | DT_VCENTER);
::SetBkMode(hdc, nMode);
::SelectObject(hdc, oldHFont);
::DeleteObject(HFont);
::ReleaseDC(GetSafeHwnd(), hdc);
void InitHFont(HFONT& argFont, int argHeight)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
argFont = ::CreateFont(
argHeight, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("宋體"));
}
轉自:http://panccp.blog.163.com/blog/static/265560442009415537120/
參考:http://wenku.baidu.com/view/22c68c8ca0116c175f0e4818.html
CImage顯示位圖與CDC雙緩沖沖突,使用路徑層解決.
2010年04月29日 星期四 20:35
位圖閃的問題困擾我很久了,因為程序的需要,我顯示位圖的方式是CImage類.
如果從CImage轉到CBitmap,之后使用Attach到是可以,但我發現這樣之后CImage類的對象會無效.
無奈拖了很久程序一直都在閃,我的程序使用的是多文檔多視圖,昨天通過勾子解決了CHtmlView在子窗口中閃爍的問題,今天下決心把CScrollView使用CImage閃爍的問題也給解決.
我們知道
CImage顯示位圖的方式是
m_Image.Draw(pDC->m_hDC, 0, 0);
通過函數跟蹤發現他也直接使用了內存繪制.
但如果我們添加使用自己的CDC比如繪制先字體,畫刷等等使用內存顯示的話也就是說有2個內存DC要顯示.
因為不同步,存在色差所以閃爍.無奈CImage的資料太少,我也試過加載到自己定義的CDC中去,但都失敗了.
我想如果我先繪制CImage,繪制后的CImage位圖誰都不許動,有什么辦法,那只能使用路徑層.
(在設備描述表中還有一個路徑層(path bracket)的概念,什么是路徑層呢?路徑層的概念就像當年軍閥割據圈地那樣,在地域上划定界線,界線之內的是各自的地盤,別人不能侵犯.)那樣的話當自己的CDC繪制時就不會去動CImage已經繪制好的部分,閃爍也就解決了.
下面看代碼.
void CNotesPrintView::OnDraw(CDC* pDC)
{
CNotesPrintDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rect = 0;
GetClientRect(rect);
CDC MemDC;
CBitmap MemBitmap;
MemDC.CreateCompatibleDC(pDC);
MemBitmap.CreateCompatibleBitmap(pDC,rect.right,rect.bottom);
MemDC.SelectObject(&MemBitmap);
MemDC.FillSolidRect(0,0,rect.right,rect.bottom,RGB(255,255,255));
// 上面的是一般的雙緩存,大家查資料.
if (!pDoc->m_Image.IsNull())
{
pDoc->m_Image.Draw(pDC->m_hDC, 0, 0); // 繪制CImage位圖
pDC->BeginPath(); // 打開路徑層
pDC->Rectangle(0,0,pDoc->m_Image.GetWidth(),pDoc->m_Image.GetHeight()); // 設置路徑層矩形區域
pDC->EndPath(); // 關閉路徑層,關閉后誰都不能在去動這塊區域了.
pDC->SelectClipPath(RGN_DIFF); // 設置裁剪模式
}
pDC->BitBlt(0,0,rect.right,rect.bottom,&MemDC,0,0,SRCCOPY); // 繪制自定定義的CDC
MemBitmap.DeleteObject();
MemDC.DeleteDC();
}
RGN_AND:新的剪切區包括當前剪切區域與當前路徑的一個交集(重疊區域)。
RGN_COPY:新的剪切區域就是當前的路徑。
RGN_DIFF:新的剪切區域包含除了當前路徑外的當前剪切區域。
RGN_OR:新的剪切區域包含當前剪切區域與當前路徑的並集。
RGN_XOR:新的剪切區域包含當前剪切區域與當前路徑的並集但不包含重疊的區域。
轉自:http://hi.baidu.com/250ez/blog/item/c1e5658f28698ff6503d921d.html