?? 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 + -