方法一: 在VS 2010中有一个类CMemDC, 在MFC下可解决绘图闪烁。
看看MSDN钟怎么说的:
CMemDC Class
A helper class for a memory device context. The memory device context supports offscreen drawing.
在库中的声明如下
1 class CMemDC
2 {
3 public:
4 AFX_IMPORT_DATA static BOOL m_bUseMemoryDC;
5 CMemDC(CDC& dc, CWnd* pWnd);
6 CMemDC(CDC& dc, const CRect& rect);
7 virtual ~CMemDC();
8 CDC& GetDC() { return m_bMemDC ? m_dcMem : m_dc; }
9 BOOL IsMemDC() const { return m_bMemDC; }
10 BOOL IsVistaDC() const { return m_hBufferedPaint != NULL; }
11 protected:
12 CDC& m_dc;
13 BOOL m_bMemDC;
14 HANDLE m_hBufferedPaint;
15 CDC m_dcMem;
16 CBitmap m_bmp;
17 CBitmap* m_pOldBmp;
18 CRect m_rect;
19 使用方法: // 1、响应WM_ERASEBKGND消息,返回FALSE,这样就不擦除背景了。
1 BOOL CDemoView::OnEraseBkgnd(CDC* pDC)
2 {
3 return FALSE;
4 // 2、在需要作图的地方使用CMemDC。
1
2 void CDemoView::OnDraw(CDC* pDC)
3 {
4 CGestureDemoDoc* pDoc = GetDocument();
5 ASSERT_VALID(pDoc);
6 CMemDC dcMem(*pDC, this);
7 CDC& dc = dcMem.GetDC();
8 //do anything with graphic object dc;
9
10
11
12 二: 网上有另外一种利用CMemDC继承CDC的方式如下:
1 MemDC.h
2 #ifndef _MEMDC_H_
3 #define _MEMDC_H_
4 //////////////////////////////////////////////////
5 // CMemDC - memory DC
6 //
7 // Author: Keith Rule
8 // Email: keithr@europa.com
9 // Copyright 1996-1999, Keith Rule
10 //
11 // You may freely use or modify this code provided this
12 // Copyright is included in all derived versions.
13 //
14 // History - 10/3/97 Fixed scrolling bug.
15 // Added print support. - KR
16 //
17 // 11/3/99 Fixed most common complaint. Added
18 // background color fill. - KR
19 //
20 // 11/3/99 Added support for mapping modes other than
21 // MM_TEXT as suggested by Lee Sang Hun. - KR
22 //
23 // This class implements a memory Device Context which allows
24 // flicker free drawing.
25 class CMemDC : public CDC {
26 protected:
27 CBitmap m_bitmap; // Offscreen bitmap
28 CBitmap* m_oldBitmap; // bitmap originally found in CMemDC
29 CDC* m_pDC; // Saves CDC passed in constructor
30 CRect m_rect; // Rectangle of drawing area.
31 BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
32 void Construct(CDC* pDC)
33 {
34 ASSERT(pDC != NULL);
35 // Some initialization
36 m_pDC = pDC;
37 m_oldBitmap = NULL;
38 m_bMemDC = !pDC->IsPrinting();
39 if (m_bMemDC) {
40 // Create a Memory DC
41 CreateCompatibleDC(pDC);
42 pDC->LPtoDP(&m_rect);
43 m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
44 m_oldBitmap = SelectObject(&m_bitmap);
45 SetMapMode(pDC->GetMapMode());
46 pDC->DPtoLP(&m_rect);
47 SetWindowOrg(m_rect.left, m_rect.top);
48 } else {
49 // Make a copy of the relevent parts of the current DC for printing
50 m_bPrinting = pDC->m_bPrinting;
51 m_hDC = pDC->m_hDC;
52 m_hAttribDC = pDC->m_hAttribDC;
53 }
54 // Fill background
55 FillSolidRect(m_rect, pDC->GetBkColor());
56 }
57 // TRK begin
58 public:
59 CMemDC(CDC* pDC ) : CDC() { pDC->GetClipBox(&m_rect); Construct(pDC); }
60 CMemDC(CDC* pDC, const RECT& rect) : CDC() { m_rect = rect ; Construct(pDC); }
61 // TRK end
62 virtual ~CMemDC()
63 {
64 if (m_bMemDC) {
65 // Copy the offscreen bitmap onto the screen.
66 m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
67 this, m_rect.left, m_rect.top, SRCCOPY);
68 //Swap back the original bitmap.
69 SelectObject(m_oldBitmap);
70 } else {
71 // All we need to do is replace the DC with an illegal value,
72 // this keeps us from accidently deleting the handles associated with
73 // the CDC that was passed to the constructor.
74 m_hDC = m_hAttribDC = NULL;
75 }
76 }
77 // Allow usage as a pointer
78 CMemDC* operator->()
79 {
80 return this;
81 }
82 // Allow usage as a pointer
83 operator CMemDC*()
84 {
85 return this;
86 }
87 };
88 使用方法类同前面所述:
1 ///////////////////////////////////////////////////////////
2 // How to use:
3 ///////////////////////////////////////////////////////////
4 // 1、响应WM_ERASEBKGND消息,返回FALSE,这样就不擦除背景了。
5 BOOL CDemoView::OnEraseBkgnd(CDC* pDC)
6 {
7 return FALSE;
8 }
9 /////////////////////////////////////////////////////////
1 // 2、在需要作图的地方使用CMemDC。
2 void CDemoView::OnDraw(CDC* pDC)
3 {
4 CFont font;
5 font.CreateFontIndirect(&m_lf);
6 CMemDC pMemDC(pDC);
7 CFont* oldfont = pMemDC->SelectObject(&font);
8 //..Draw something here.
9 pMemDC->SelectObject(oldfont);
10 }
11 ///////////////////////////////////////////////////////////
12 // 别忘了加include头文件!
13 /////////////////////////////////////////////////////////
CMemDC其实就是对内存DC的创建与删除进行一个包装。
1、在CMemDC的构造函数中创建内存DC;
2、用户可以在CMemDC dc中进行图像的绘制;
3、在CMemDC的析构函数中进行内存DC到目标DC的拷贝,并做相应的GDI对象清理工作。
使用这样的类可以让你的代码有很大程度的简洁。
举个例子:
如果我们不使用CMemDC,一般我们会写下面的一段的代码,
CView::OnDraw(CDC* pDC)
{
CRect rcClient;
GetClientRect(&rcClient);
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
CBitmap bmpMem;
bmpMem.CreateCompatibleBitmap(pDC,rcClient.Width(),rcClient.Height());
CBitmap *pBmpOld = dcMem.SelectObject(&bmpMem);
//下面进行图像的绘制
dcMem.DrawText();
dcMem.FillSolidRect();
pDC->BitBlt(rcClient.left,rcClient.top,rcClient.Width(),rcClient.Height(),
&dcMem,0,0,SRCCOPY);
//GDI对象的清理
dcMem.SelectObject(pBmpOld);
bmpMem.DeleteObject();
dcMem.DeleteDC();
}
如果我们使用了CMemDC,那么代码就可以这样写,简洁了很多,更便于维护而且不容易出错。CView::OnDraw(CDC* pDC)
{
CMemDC dcMem(pDC);
//下面进行图像的绘制
dcMem.DrawText();
dcMem.FillSolidRect();
}
一般不用自己写个类,不过有封装更好.简单来说,步骤这样:(比如你真正的使用CDC *dc来绘制)1.建立dc的内存DCm_MemDc.CreateCompatibleDC(dc);2.创建画布m_bmp.CreateCompatibleBitmap(dc,宽度,高度);3.选择画布m_oldBmp = m_MemDc.SelectObject(&m_bmp);4.内存Dc绘制东西......绘制自己需要的东西5.使用真正绘图的dc拷贝内存dc的内容dc.BitBlt(left,top,宽度,高度,&m_MemDc,m_MemDc中的起始X,m_MemDc中的起始y,SRCCOPY)6.最后这个内存DC释放掉m_MemDc.DeleteDC(); CMemDC类
其主要功能其实就是提供一个内存DC用于绘制,用于消除绘制时的闪烁,即双缓存机制。
一般来说,我们将将要显示的图首先绘制在内存DC上,然后在要显示的时候整个更新到前台DC上(使用BitBlt)。我们首先来看一下CMemDC类的数据成员private: CBitmap m_bitmap; // Offscreen bitmap CBitmap* m_oldBitmap; // 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.可以看到这当中有两个重要的元素:m_bitmap和m_pDC。打个也许不大恰当的比方,
m_pDC指向的CDC对象好比是一张画板,我们将画画在上面,画好的画就是m_bitmap。
当我们将内存DC用BitBlt到前台DC的时候,正好就是将刚刚画的画显示到前台。