网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
源代码在线查看: 11.5 兼容设备描述表和本章小结.txt
11.5 兼容设备描述表 431
下面再介绍另一种图形保存和重绘的方式:利用兼容 DC来实现。关于兼容 DC的知识,在前面的章节
中已经介绍过了,当时主要是利用兼容 DC在内存中准备一幅图像,然后将该图像复制到目的窗口中。
我们也可以利用兼容 DC来保存图形,然后在 OnDraw函数中将兼容 DC保存的图形复制到目的窗口
中。
下面在 Graphic程序中利用兼容 DC来实现图形的保存和重绘。首先需要为 CGraphicView类创建一
个兼容 DC对象,为其增加一个 CDC类型的私有成员变量= m_dcCompatible,然后在该类的
OnLButtonUp函数中,利用兼容 DC实现图形的保存,具体实现代码如例 11-15所示。
例 11-15
1. void CGraphicView::OnLButtonUp(UINT nF1ags , CPoint point)
2. {
3. // TODO: Add your message hand1er code here and/or ca11 defau1t
4. CClientDC dc (this) ;
5. CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)):
6. if(!m_dcCompatible.m_hDC)
7. (
8. m_dcCompatib1e.CreateCompatib1eDC(&dc):
9. CRect rect:
10. GetC1ientRect(&rect);
11. CBitmap bitmap:
12. bitmap.CreateCompatibleBitmap(&dc, rect.Width() , rect.Height());
13. m_dcCompatible.SelectObject(&bitmap);
14. m_dcCompatible.SelectObject(pBrush);
15. }
16. switch(m_nDrawType)
17. {
18. case 1:
19. m_dcCompatible.SetPixel(point ,RGB(O , O, O));
20. break;
21. case 2:
22. m_dcCompatible.MoveTo(m-ptOrigin);
23. m_dcCompatible.LineTo(point);
24. break;
25. case 3:
26. m_dcCompatible.Rectangle{CRect(m-ptOrigin,point));
27. break;
28. case 4:
29. m_dcCompatible.Ellipse(CRect(m-ptOrigin,point));
30. break;
432 I T-T-~
31. }
32. CScrol1飞Tiew: :OnLButtonUp(nFlags, point);
33. }
下面我们来剖析如例 11-15所示代码。'
第6行~第8行:判断是否已经创建了m_dcCompatible这个兼容DC对象,如果没有创建(即
m_dcCompatible对象的m_hDC数据成员为NULL),就创建该对象,并与当前窗口DC (dc)兼容。因为在
Graphic程序运行时,OnLButtonUp函数会被多次调用,所以一定要进行这样的判断,不能重复地创
建这个兼容 DC,只有在第一次判断其还没有被创建时,才创建该兼容DC对象。
第9行~第 12行z在前面已经提到,在兼容DC初始创建时,它会选择一幅单色位图。之前,我们是通
过SelectObject函数将一幅位图选入兼容DC来确定其显示表面的大小。但现在没有这样一幅位图,
需要去创建一个与当前窗口 DC相兼容的DC,它的显示表面大小与当前客户区大小是一致的。可以利
用兼容位图来满足这样的要求。 CBitmap类的成员函数: CreateCompatibleBitmap可以通过指定的
宽和高创建一幅与指定DC相兼容的位图。因此,如例 11-15所示代码中,通过GetClientRect函数获
取当前窗口客户区的大小,然后利用该大小设置兼容位图的宽和高。
第 13行:有了兼容位图之后,就可以把该兼容位图选入兼容DC中,从而确定兼容 DC显示表面的大小。
这里,读者一定要注意,对兼容DC来说,如果想在其上调用 GDI函数,那么必须先为其选入一幅位
图,这幅位图可以是一幅普通位图,也可以通过 CreateCompatibleBitmap函数创建的兼容位圈。只
有经过这一操作之后,才能确定兼容DC显示表面的大小。
第14行:将透明画刷选入兼容DC中。
如例 11-15所示代码中剩余的代码行只是将OnLButtonUp函数中原有的元文件DC都
" ‘ I 433
第 11
替换为新创建的兼容 DC。
因为兼容 DC实际上是一块内存,所以利用它绘制的图形在窗口中是看不到的,因此接下来在
CGraphicView类的 OnDraw函数中就可以利用己创建的兼容 DC对象,将该 DC中的内容复制到目的
DC中,从而实现图形的显示。该函数的具体代码如例 11-16所示。
19IJ 11-16
void CGraphicView : :OnDraw(CDC* pDC)
CGraphicDoc* pDoc = GetDocurnent ( );
ASSERT_VAL工 D (pDoc) ;
// TODO : add draw code for native data here
CRect rect ;
GetClientRect(&rect) ;
pDC->BitBlt(O , O, rect . Width() , rect . Height() ,&rn_dcCornpatible , O, O, SRCCOPY) ;
在上述如例 11-16所示代码中,首先利用 GetC1ientRect函数得到窗口客户区大小,然
后利用前面已经使用过的 BitBlt函数将兼容 DC中的内容复制到当前窗口 DC中,从而实
现图形的显示。
再次运行 Graphic程序,然后利用相应菜单进行给图操作,但是当窗口尺寸发生变化时将会发现程
序出现问题了,程序并没有如我们所愿在窗口中显示出我们刚刚绘制的图形。之所以会出现这样的
问题是因为 CreateCompatibleBitmap函数返回的位图对象只包含相应设备描述表中的位图的位图
信息头,井不包含该位图的颜色表和像素数据块。因此,选入该位图对象的设备描述表不能像选入
普通位图对象的设备描述表一样应用,必须在 SelectObject函数之后,调用 BitBlt函数将原始设
备描述表的颜色表及像素数据块复制到兼容设备描述表。也就是说,需要在上述如例 11-15所示
CGraphicView类的 OnLButtonUp函数的第 13行代码之后添加下面这条语句。
rn_dcCornpatible.BitBlt(O , O, rect.Width() , rect.Height() ,&dc , O, O, SRCCOPY);
这里,如果读者对位图的格式不太了解的话,并没有太大的影响,只需要记住:在调用 SelectObject
操作将兼容位图选入兼容 DC之后,还需要调用 BitBlt函数将原始设备描述表的颜色表及像素数据
块复制到兼容设备描述表。
再次运行Graphic程序,井利用相应菜单命令绘制一些图形,然后再改变窗口大小便窗口重绘,这时
在程序窗口就可以看到刚刚绘制的图形了。以上就是利用兼容设备描述表来完成图形的保存和重绘
功能的实现过程,这里的重绘实际上就是利用 BitBlt函数通过贴图操作来完成的。
如果读者想在图形绘制时,在窗口中也能够看到正绘制的图形,这时在 CGraphicView类的
OnLButtonUp函数中实际上需要进行两次图形绘制函数的调用,一次是利用兼容 DC调用图形绘制函
数在内存中绘制图形,另一次是利用当前窗口 DC调用图形绘制函数在窗口上绘制图形。这样的话,
绘制的图形不仅可以在当前窗口中显示出来,同时也保存到兼
434 I T-T-T-
容 DC中了。读者可以自行实现这样的功能。
飞结
本章主要介绍了图形的保存和重绘方面的内容。首先介绍了一些 Windows图形绘制相关的基础知识,
包括坐标空间和转换, Win32应用程序设计接口 (API)使用四种坐标空间:世界坐标系空间、页面空
间、设备空间和物理设备空间。其中,世界坐标系空间主要是用来对图形进行一些特殊的处理,例
如旋转、斜切或者反射:对于物理设备空间来说,因为我们不能对其进行任何操作,所以不需要考虑。
我们需要考虑的主要是页面空间到设备空间的转换,对页面空间来说,我们通常把它称为逻辑空间。
在绘制图形时,需要将逻辑坐标点转换为设备坐标点。这种转换一般是由 Windows自动完成的,但
在一些特殊的情况下需要程序员自己去操作,例如,如果是在滚动窗口中给制图形的话,就需要进
行一些额外的处理。
另外,本章还介绍了集合类: CP町Array的使用、 OnPaint与 OnDraw在 CView中的关系及实现内幕、
滚动窗口等功能的实现。最后,还介绍了两种图形保存和绘制的方法,分别利用元文件和兼容 DC
实现图形的保存和再现。