到了mfc里面由于有了封装所有的hdc被隐藏在对象中做为隐藏参数传递(就是DC类的this啦~~)所以我们的关键话题就转变为了怎样得到想要的DC类而已这个过程其实大同小异的在消息响应的过程中WM_PAINT被转变为OnDraw()OnPaint()一系列函数来响应这些函数一般都有个参数CDC *pDC传入进来因此在这些函数里面我们就只需要直接画图就可以了和以前sdk的方式一样
但是WM_PAINT消息响应的频度太高了比如最小化最大化移动窗体覆盖等等都引起重绘经常的这样画图很是消耗性能在有些场合比如随机作图的场合每一次就改变还导致了程序的无法实现怎么解决后一种问题呢
ms在msdn的例子里面交给我们document/view的经典解决办法将图形的数据存储在document类里面view类只是根据这些数据绘图比如你要画个圆只是将圆心和半径存在document里面view类根据这个里面的数据在屏幕上面重新绘制那么我们只需要随机产生一次数据就可以了
这样还是存在性能的问题于是我们开始考虑另外的解决方法我们知道将内存中的图片原样输出到屏幕是很快的这也是我们在dos时代经常做的事情能不能在windows也重新利用呢?答案就是内存缓沖绘图我们今天的主题
我们还是回到DC上来既然DC是绘图对象我们也就可以自己来在内存里面造一个让它等于我们想要的图图(CBitmap)可以存储在document类里面每一次刷新屏幕都只是将这个图输出到屏幕上面每一次作图都是在内存里面绘制保存在document的图里面必要时还可以将图输出到外存保存这样既保证了速度也解决了随机的问题在复杂作图的情况下对内存的开销也不大(总是一副图片的大小)这是一个很好的解决办法现在让我们来实现它们
我们在document类里面保存一个图片
CBitmap m_bmpBuf;//这里面保存了我们做的图存在于内存中
在view类里面我们需要将这个图拷贝到屏幕上去
位于OnDraw(CDC *pDC)函数中
CDC dcMem;//以下是输出位图的标准操作
CBitmap *pOldBitmap = NULL;
dcMemCreateCompatibleDC(NULL);
pOldBitmap = dcMemSelectObject(&pDoc>m_bmpBuf);
BITMAP bmpinfo;
pDoc>m_bmpBufGetBitmap(&bmpinfo);
pDC>BitBlt(bmpinfobmWidthbmpinfobmHeight&dcMemSRCCOPY);
dcMemSelectObject(pOldBitmap);
dcMemDeleteDC();
在我们需要画图的函数里面我们完成绘图工作
CBmpDrawDoc *pDoc = GetDocument(); //得到document中的bitmap对象
CDC *pDC = GetDC();
CDC dcMem;
dcMemCreateCompatibleDC(NULL);//这里我们就在内存中虚拟建造了DC
pDoc>m_bmpBufDeleteObject();
pDoc>m_bmpBufCreateCompatibleBitmap(pDC);//依附DC创建bitmapCBitmap *pOldBitmap = dcMemSelectObject(&pDoc>m_bmpBuf);//我们调入了我们bitmap目标
dcMemFillSolidRect(RGB());//这些时绘图操作随便你^_^
dcMemTextOut(Helloworld!);
dcMemRectangle();
dcMemFillSolidRect(RGB());
pDC>BitBlt(&dcMemSRCCOPY);//第一次拷贝到屏幕
dcMemSelectObject(pOldBitmap);
dcMemDeleteDC();
全部的过程就是这样很简单吧以此为例子还可以实现个缓沖或者多个缓沖等等视具体情况而定当然在缓沖区还可以实现很多高级的图形操作比如透明合成等等取决于具体的算法需要对内存直接操作(其实就是当年dos怎么做现在还怎么做)
再来解释一下前面说的为什么不能用全局变量保存DC问题其实DC也是用句柄来标识的所以也具有句柄的不确定性就是只能随用随取不同时间两次取得的是不同的(使用过文件句柄地话应该很容易理解的)那么我们用全局变量保存的DC就没什么意义了下次使用只是什么也画不出来(这一点的理解可以这样DC需要占用一定的内存那么在频繁的页面调度中位置难免改变于是用来标志指针的句柄也就不同了)
[] []