繪圖

CDC雙緩衝繪圖

一、雙緩衝實現過程如下:      
  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:新的剪切區域包含當前剪切區域與當前路徑的並集但不包含重疊的區域。

發佈了30 篇原創文章 · 獲贊 67 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章