📄 11.4.1 元文件的使用.txt
字号:
11 .4.1 元文件的使用
这时需要用到元文件设备上下文类: CMetaFileDC.该类的派生层次结构如图 1 1. 13所示。
图 1 1.1 3 CMetaFileDC类派生层次结构
从图 1 1. 13可知. CMetaFileDC类是从 CDC类派生的。一个 Windows元文件 DC包含了一系列图形
设备接口命令,在程序中可以重放这些命令,以便创建所需的图形或文本。为了更好地理解元文件 DC
的作用,我们可以进行这样的一个比喻,我们准备一块画布来绘制图形,这块画布就相当于元文件 DC.
然后我们在这块画布上绘制各种各样的图形,但是这些图形并没有被别人所看到。画好之后,如果
有人想看,我们就可以随时打开这块画布,让他们参观,也就是说可以多次重复地打开同一块画布
以展示上面的内容。元文件的工作原理与此类似,它包含的实际上是一系列图形设备接口命令,例
如绘制一条直线、绘制一个椭困、输出一行文本,但这时绘制的图形是看不到的,它们存在于元文
件中,实际上是在内存中绘制的。当在元文件中绘制完成之后,可以播放该元文件,这时就可以在
窗口中看到先前在该文件中绘制的图形了。要注意的是,元文件并没有包含所绘图形的图形数据,
它包含的是图形的绘制命令。
我们可以通过以下步骤来使用 Windows元文件:
①利用 CMetaFileDC构造函数构造一个元文件 DC对象,然后调用该类的 Create成员函数创建一个
Windows元文件设备上下文,并将其与己构造的 CMetaFileDC对象关联起来。该 Create函数的声明
如下所示:
BOOL Create( LPCTSTR lpszFilenarne = NULL };
CMetaFileDC类的 Create函数有一个参数: lpszFilename.它是以 null为结尾的字符串,指定要创
建的元文件的文件名。如果此参数为 NULL,创建的元文件就是一个内存元文件。
给己创建的元文件 DC对象发送一系列的 GDI命令,例如 MoveTo或 LineTo等。
③在给元文件 DC对象发送了需要的命令之后,调用 Close成员函数关闭元文件设备上下文,返回元
文件句柄 (HMETAFILE类型) 0 CMetaFileDC类的 Close成员函数的声明如下所示。
HMETAFILE Close( );
四以得到的元文件句柄为参数,利用 CDC类的 Play MetaFile成员函数播放该元文件。
PlayMetaFile函数的声明如下所示。
BOOL PlayMetaFile( HMETAFILE hMF );
己目播放完其中的图形绘制命令之后,就不再需要该元文件了。因为元文件也是一种资源,所以在
使用结束后,也需要释放,这可以通过调用 DeleteMetaFile函数将其删除。该函数的声明形式如下
所示。
BOOL DeleteMetaFile(HMETAFILE hrnf);
下面就在 Graphic程序中利用元文件来保存图形,并在 OnDraw函数中播放该元文件。
由为 CGraphicView类添加一个 CMetaFileDC类型的私有成员变量 : m_dcMetaFile。然后在该类的
构造函数中调用 CMetaFileDC类的 Create方法(代码如下所示)创建一个内存元文件 DC。
m_dcMetaFile.Create();
(lJ在 CGraphicView类的 OnLButtonUp函数中,将已有的设备上下文对象都换成元文件设备上下文
对象,即把该函数中的 CDC类型的对象 dc都替换为 CMetaFileDC类型的对象: m dcMetaFile。并将
该函数中先前编写的将图形对象保存到集合类对象中的代码注释起来。即这时的 OnLButtonUp函数
如例 11-11所示。
例 11-11
void CGraphicView: :OnLButtonUp(UINT nFlags , CPoint point)
{
// TODO : Add your rnessage handler code here and/or call default
CClientDC dc(this) ;
CPen pen(rn_nLineStyle , rn_nLineWidth , rn_clr);
// dc . SelectObject(&pen) ;
rn_dcMetaFile.SelectObject(&pen) ;
CBrush
*pBrush=CBrush: : FrornH andle( (HBRUSH)GetStockObject(NULL_BRUSH)) ; //
dc.SelectObject(pBrush); rn_dcMetaFile.SelectObject(pBrush) ;
switch(rn_nDra旷I'y pe)
{
case 1:
// dc .S etPixel(point, m_clr) ;
m_dcMetaFile . SetPixel(point , m_clr) ;
break;
case 2: 11 dc . MoveTo(m-ptOrigin); 11
dc . LineTo (point) ;
m_dcMetaFile . MoveTo(m-ptOrigin) ;
m_dcMetaFile . LineTo(po工 nt) ;
break;
case 3:
11
dc . Rectangle(CRect(m-ptOrigin, point)) ; m_dcMetaFile.Rectangle(CRect(m-ptOrigin,
point)) ; break;
case 4:
11 dc . Ellipse(CRect(m-p tOr工 gin, point) ) ; m_dcMetaFile.Ellipse(CRect(m-ptOrigin,
point)) ; break;
11 CGraph graph(m_nDrawType, m-ptOrig工n, point) ; 11 m-ptrArray . Add(&graph) ;
1* OnPrepareDC (&dc) ; dc . DPtoLP(&m-pt Origin) ; dc . DPtoLP(&point) ;
CGraph *pGraph=new CGraph(m_nDrawType , m-ptOrigin, p oint) ; m-ptrArray . Add(pGraph) ;
*1
CScrollView : : OnLButtonUp(nFlags , point) ;
吨
按照上面元文件使用步骤的第三步,接下来应该在窗口重绘时,即在 OnDraw函数中播放元文件,以
实现图形的显示。为了效果更清晰,我们首先将 OnDraw函数先前编写的绘制图形的代码注释起来或
删除,然后添加新代码,结果如例 11-12所示,其中加灰显示的代码为新添代码。
例 11-12
void CGraphicView : : OnDraw(CDC* pDC) {
CGraphicDoc* pDoc = GetDocument() ;
ASSERT_ VALID(pDoc) ;
11 TODO : add draw code for native data here
1. HMETAFILE hmetaFile;
2. hmetaFile=m_dcMetaFile.Close();
3. pDC->PlayMetaFile(hmetaFile);
4. m_dcMetaFile.Create();
5. DeleteMetaFile(hmetaFile);
在新添的这段代码中,首先调用 Close函数关闭元文件设备上下文,获得元文件句柄。然后利用 CDC
类的成员函数 : PlayMetaFile播放该元文件。因为在窗口重绘之后,用户可能希望能够继续绘制图
形,而我们仍采用元文件的方式来实现图形的绘制,所以在播放先前元文件中绘制图形的命令之后,
应该接着再创建-个元文件设备上下文对象,以便用户再次绘制图形使用。最后调用 DeleteMetaFile
函数释放元文件资源。
Build并运行 Graphic程序,利用相应菜单命令在窗口中绘制图形,通过某种手段让窗口发生重绘(例
如改变窗口尺寸)后,就可以看到绘制的图形了。因为我们己经在代码中又创建了一个元文件对象(上
述例 11-12所示的第 4行代码),所以用户可以继续绘制图形,即再次利用相应菜单命令在窗口中绘
制图形,并通过某种手段让窗口重绘,读者会注意到,这时在程序窗口中,我们先前绘制的图形没
有了,只是把我们最新绘制的图形显示出来了。这是因为我们在代码中又重新创建一个新的元文件
设备上下文对象(上述例 11-12所示的第 4行代码),所以先前绘制的图形都不存在了。如果想要保
存先前绘制的图形,那么在创建新的元文件 DC之后,应该用这个新的元文件 DC的 PlayMetaFile
函数去播放先前的元文件。即在上述例 11-12所示的第 3行代码之后添加下面这句代码 :
m_dcMetaFile . PlayMetaFile(hmetaFile) ;
回注意:这时在 OnDraw函数中,当调用 pDC的 PlayM时.le函数播放元文
件时,它会将指定元文件中的 GDI命令在窗口中输出。而调用新的元,文件 DC ( ID_dcMetaFile )
的 PlayMetaFile函数播放元文件时,它会将先前在元文件中绘制的图形在该元文件 DC中绘制,实
际上,这就相当于把先前的困形绘制命令保存到新的 ID_dcMetaFile中了。接下来,用户可以利用
这个新的元文件 DC继续调剂 GDI函数绘制新的图形(即 OnLButtonUp函数中实现的功能 )。这样,
当下一次调用 OnDraw函数时, ID_dcMetaFile中保存的就是所有围形绘制命令,于是得到的元文件
( hmetaFile )中就保存了用户已进行的所有图形绘制的命令,这时调用 pDC的 PlayMetaFile函数
就可以把用户已绘制的所有图形在窗口中显示出来了。
读者可以再次运行 Graphic程序检验一下效果,会发现这时当程序窗口发生重绘后,先前所绘的图
形也能显示出来了。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -