////////////////////////////////////////////////////////////////
簡介:內存DC,又名“雙緩沖”,是解決windows窗口自繪中出現“閃屏”的常規手段。
1)、為屏幕 DC 創建兼容的內存 DC
2)、創建位圖
3)、把位圖選入設備環境
4)、把繪制好的圖形“拷貝“到屏幕上
看這個代碼:
首先看構造,從一個CDC構造。然后看了一下成員函數,好像沒幾個,估計這是一個可以完全替換的CDC的省心的東東。
然后看析構:析構是一個BitBit,聯想自己做內存DC的時候,最后一步也是內存到DC的貼圖動作。
公開接口就兩個,重載的CDC* 和 ->操作,直接能當作CDC使用。
這幾個細節需要注意:
1.m_bMemDC = !pDC->IsPrinting(); // 以前關注不多,這是用于判斷這個DC是不是用于print,如果是就不使用“內存DC”,至于為什么還不了解。我理解是沒有需要。
2.FillSolidRect(m_rect, pDC->GetBkColor()); // WM_ERASEBKGND,針對這個消息的細節處理。
這個類持有了一個“前臺”DC,它本身是一個“后臺”DC,每次后臺克隆前臺執行繪畫然后把結果貼回去。
這里還有一個細節,就是SelectObject。為了保證不泄漏,最好的辦法是,每次工作完成將所有的GDI對象復位。
///////////////////////////////////////////////////////////////
class CMemDC : public CDC
{
public:
// constructor sets up the memory DC
CMemDC(CDC* pDC) : CDC()
{
ASSERT(pDC != NULL);
m_pDC = pDC;
m_pOldBitmap = NULL;
#ifndef _WIN32_WCE_NO_PRINTING
m_bMemDC = !pDC->IsPrinting();
#else
m_bMemDC = FALSE;
#endif
if (m_bMemDC) // Create a Memory DC
{
pDC->GetClipBox(&m_rect);
CreateCompatibleDC(pDC);
m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
m_pOldBitmap = SelectObject(&m_bitmap);
#ifndef _WIN32_WCE
SetWindowOrg(m_rect.left, m_rect.top);
#endif
// EFW - Bug fix - Fill background in case the user has overridden
// WM_ERASEBKGND. We end up with garbage otherwise.
// CJM - moved to fix a bug in the fix.
FillSolidRect(m_rect, pDC->GetBkColor());
}
else // Make a copy of the relevent parts of the current DC for printing
{
#if !defined(_WIN32_WCE) || ((_WIN32_WCE > 201) && !defined(_WIN32_WCE_NO_PRINTING))
m_bPrinting = pDC->m_bPrinting;
#endif
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
}
// Destructor copies the contents of the mem DC to the original DC
~CMemDC()
{
if (m_bMemDC)
{
// Copy the offscreen bitmap onto the screen.
m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
this, m_rect.left, m_rect.top, SRCCOPY);
//Swap back the original bitmap.
SelectObject(m_pOldBitmap);
} else {
// All we need to do is replace the DC with an illegal value,
// this keeps us from accidently deleting the handles associated with
// the CDC that was passed to the constructor.
m_hDC = m_hAttribDC = NULL;
}
}
// Allow usage as a pointer
CMemDC* operator->() {return this;}
// Allow usage as a pointer
operator CMemDC*() {return this;}
private:
CBitmap m_bitmap; // Offscreen bitmap
CBitmap* m_pOldBitmap; // bitmap originally found in CMemDC
CDC* m_pDC; // Saves CDC passed in constructor
CRect m_rect; // Rectangle of drawing area.
BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
};