文檔與視圖PPT課件_第1頁
文檔與視圖PPT課件_第2頁
文檔與視圖PPT課件_第3頁
文檔與視圖PPT課件_第4頁
文檔與視圖PPT課件_第5頁
已閱讀5頁,還剩80頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第6章,VisualC+面向?qū)ο缶幊蘓isualC+ObjectOrientedProgramming,第6章文檔與視圖,第6章文檔與視圖,內(nèi)容提要,文檔與視圖結(jié)構(gòu)原理菜單編程鼠標(biāo)消息處理工具欄和狀態(tài)欄編程讀寫操作機(jī)制,通過本章的學(xué)習(xí),可以利用VisualC+創(chuàng)建一個完整的文檔/視圖結(jié)構(gòu)應(yīng)用程序。,文檔與視圖結(jié)構(gòu)是MFC應(yīng)用程序最基本的程序結(jié)構(gòu),適用于大多數(shù)Windows應(yīng)用程序。文檔和視圖完成了程序的大部分功能,它們是MFC應(yīng)用程序的核心。文檔與視圖結(jié)構(gòu)是MFC的基石,掌握文檔與視圖結(jié)構(gòu)對于利用MFC編程有著至關(guān)重要的意義。本章對文檔與視圖結(jié)構(gòu)進(jìn)行更深入的討論。,信息管理是計算機(jī)的一個主要應(yīng)用,而信息是用數(shù)據(jù)表示的,因此數(shù)據(jù)的處理是一般軟件都要完成的一項主要工作。采用傳統(tǒng)的編程方法,數(shù)據(jù)處理是一項復(fù)雜的任務(wù),并且每一個程序員都可能有不同的處理方法。為了統(tǒng)一和簡化數(shù)據(jù)處理方法,Microsoft公司在MFC中提出了文檔/視圖結(jié)構(gòu)的概念,其產(chǎn)品Word就是典型的文檔/視圖結(jié)構(gòu)應(yīng)用程序。,6.1文檔與視圖結(jié)構(gòu),標(biāo)題欄主菜單工具欄客戶區(qū)狀態(tài)欄不同程序的相同菜單項和工具欄按鈕表示相同的操作,6.1.1文檔與視圖結(jié)構(gòu)概述,Windows應(yīng)用程序界面特點:,分為數(shù)據(jù)的管理和顯示文檔用于管理和維護(hù)數(shù)據(jù)視圖用來顯示和編輯數(shù)據(jù)MFC通過其文檔類和視圖類提供了大量有關(guān)數(shù)據(jù)處理的方法。,MFC文檔/視圖結(jié)構(gòu)數(shù)據(jù)處理工作分工:,文檔的概念在MFC應(yīng)用程序中的適用范圍很廣,一般說來,文檔是能夠被邏輯地組合的一系列數(shù)據(jù),包括文本、圖形、圖象和表格數(shù)據(jù)。一個文檔代表了用戶存儲或打開的一個文件單位。文檔的主要作用是把對數(shù)據(jù)的處理從對用戶界面的處理中分離出來,集中處理數(shù)據(jù),同時提供了一個與其它類交互的接口。,什么是文檔?,視圖是文檔在屏幕上的一個映像,它就像一個觀景器,用戶通過視圖看到文檔,也是通過視圖來改變文檔,視圖充當(dāng)了文檔與用戶之間的媒介物。應(yīng)用程序通過視圖向用戶顯示文檔中的數(shù)據(jù),并把用戶的輸入解釋為對文檔的操作。一個視圖總是與一個文檔對象相關(guān)聯(lián),用戶通過與文檔相關(guān)聯(lián)的視圖與文檔進(jìn)行交互。當(dāng)用戶打開一個文檔時,應(yīng)用程序就會創(chuàng)建一個與之相關(guān)聯(lián)的視圖。,什么是視圖?,視圖負(fù)責(zé)顯示和編輯文檔數(shù)據(jù),但不負(fù)責(zé)存儲。用戶對數(shù)據(jù)的編輯需要依靠窗口上的鼠標(biāo)與鍵盤操作才得以完成,這些消息都是由視圖類接收后進(jìn)行處理或通知文檔類,如收到窗口刷新消息時調(diào)用視圖類的成員函數(shù)OnDraw()顯示文檔內(nèi)容。視圖還可在打印機(jī)上輸出。文檔負(fù)責(zé)數(shù)據(jù)的讀寫操作,數(shù)據(jù)通常被保存在文檔類的成員變量中,文檔類通過一個稱為序列化的成員函數(shù)將成員變量的數(shù)據(jù)保存到磁盤文件中。MFC應(yīng)用程序為數(shù)據(jù)的序列化提供了默認(rèn)支持。,視圖和文檔的功能:,文檔、視圖、框架窗口之間的關(guān)系,一個視圖是一個沒有邊框的窗口,它位于主框架窗口中的客戶區(qū)。視圖是文檔對外顯示的窗口,但它并不能完全獨(dú)立,它必須依存在一個框架窗口內(nèi)。一個視圖只能擁有一個文檔,但一個文檔可以同時擁有多個視圖。,視圖是文檔在屏幕上的一個映像,它就像一個觀景器,文檔/視圖結(jié)構(gòu)的優(yōu)點:,把數(shù)據(jù)處理類從用戶界面處理類中分離出來,使得每一個類都能集中地執(zhí)行一項工作。把Windows程序通常要做的工作分成若干定義好的類,這樣有助于應(yīng)用程序的模塊化,程序也易于擴(kuò)展,編程時只需修改所涉及的類。雖然文檔/視圖結(jié)構(gòu)牽涉到許多類,其中的也關(guān)系比較復(fù)雜,但MFCAppWizard向?qū)Ы⒌腗FC應(yīng)用程序框架已經(jīng)把程序的主要結(jié)構(gòu)完成了,模塊間的消息傳遞以及各函數(shù)的功能都已確定。MFC應(yīng)用程序框架起到了穿針引線的作用,按照消息處理函數(shù)功能的不同,將不同消息的響應(yīng)分別分布在文檔類和視圖類中。,文檔/視圖結(jié)構(gòu)并沒有完全要求所有數(shù)據(jù)都屬于文檔類,視圖類也可以有自己的數(shù)據(jù)。如果在視圖類中不定義任何數(shù)據(jù),在需要時都從文檔類中獲取,這樣做會影響程序的效率。例如,在文本編輯程序中,往往在視圖中緩存部分?jǐn)?shù)據(jù),這樣可以避免對文檔的頻繁訪問,提高運(yùn)行效率。,在視圖類中定義數(shù)據(jù),包含多個類的MFC文檔/視圖結(jié)構(gòu)應(yīng)用程序要管理這些類中的數(shù)據(jù),除了考慮在程序的哪一部分擁有數(shù)據(jù)和在哪一部分顯示數(shù)據(jù),一個主要的問題是文檔數(shù)據(jù)更改后如何保持視圖顯示的同步,即文檔與視圖如何進(jìn)行交互。在文檔、視圖和應(yīng)用程序框架之間包含了一系列復(fù)雜的相互作用過程,文檔與視圖的交互是通過類的公有成員變量和成員函數(shù)實現(xiàn)的。,6.1.2文檔與視圖之間的相互作用,1視圖類的成員函數(shù)GetDocument()一個視圖對象只有一個與之相關(guān)聯(lián)的文檔對象。在MFC應(yīng)用程序中,視圖對象通過調(diào)用成員函數(shù)函數(shù)GetDocument()得到當(dāng)前文檔。GetDocument()是視圖類的成員函數(shù),調(diào)用它可以返回與視圖相關(guān)聯(lián)的文檔對象的指針,利用這個指針可以訪問文檔類及其派生類的公有成員。當(dāng)利用MFCAppWizard向?qū)?chuàng)建一個SDI單文檔應(yīng)用程序Mysdi時,生成了視圖類的一個派生類,并在派生類中定義了函數(shù)GetDocument()。,文檔和視圖類常用的成員函數(shù),CMysdiDoc*CMysdiView:GetDocument()ASSERT(m_pDocument-IsKindOf(RUNTIME_CLASS(CMysdiDoc);return(CMysdiDoc*)m_pDocument;/m_pDocument是CArchive類的數(shù)據(jù)成員,/指向當(dāng)前文檔對象,GetDocument()的Debug版函數(shù)代碼:,一個文檔對象可以有多個與之相關(guān)聯(lián)的視圖對象,當(dāng)一個文檔的數(shù)據(jù)通過某個視圖被修改后,與它關(guān)聯(lián)的每一個視圖都必須反映出這些修改。因此,視圖在需要時必須進(jìn)行重繪,即當(dāng)文檔數(shù)據(jù)發(fā)生改變時,必須通知到所有相關(guān)聯(lián)的視圖對象,以便更新所顯示的數(shù)據(jù)。更新與該文檔有關(guān)的所有視圖的方法是調(diào)用成員函數(shù)CDocument:UpdateAllViews()。,2CDocument類的成員函數(shù)UpdateAllViews(),如果在文檔派生類的成員函數(shù)中調(diào)用UpdateAllViews()函數(shù),其第一個參數(shù)pSender設(shè)為NULL,表示所有與當(dāng)前文檔相關(guān)的視圖都要重繪(參見例6-3)。如果在視圖派生類的成員函數(shù)中通過當(dāng)前文檔指針調(diào)用UpdateAllViews()函數(shù),其第一個參數(shù)pSender設(shè)為當(dāng)前視圖,如下形式:GetDocument()-UpdateAllViews(this),函數(shù)聲明:voidUpdateAllViews(CView*pSender,LPARAMlHint=0L,CObject*pHint=NULL);,當(dāng)程序調(diào)用CDocument:UpdateAllViews()函數(shù)時,實際上是調(diào)用了所有相關(guān)視圖的OnUpdate()函數(shù),以更新相關(guān)的視圖。需要時,可以直接在視圖派生類的成員函數(shù)中調(diào)用該函數(shù)刷新當(dāng)前視圖。,3視圖類的成員函數(shù)OnUpdate(),voidCView:OnUpdate(CView*pSender,LPARAM/*lHint*/,CObject*/*pHint*/)ASSERT(pSender!=this);UNUSED(pSender);/unusedinreleasebuilds/invalidatetheentirepane,erasebackgroundtooInvalidate(TRUE);/使整個窗口矩形無效,通過調(diào)/用OnDraw()更新整個視圖窗口,基類CView的成員函數(shù),在OnUpdate()中通過調(diào)用函數(shù)CWnd:Invalidate()刷新整個客戶區(qū),我們也可以在自己的CWnd派生類中直接調(diào)用函數(shù)Invalidate()。,總結(jié):刷新視圖時默認(rèn)的函數(shù)調(diào)用過程:CDocument:UpdateAllViews()CView:OnUpdate()CWnd:Invalidate()OnPaint()OnDraw(),MFC基于文檔/視圖結(jié)構(gòu)的應(yīng)用程序分為單文檔和多文檔兩種類型,一個多文檔應(yīng)用程序有一個主窗口,但在主窗口中可以同時打開多個子窗口,每一個子窗口對應(yīng)一個不同的文檔。利用MFCAppWizardexe向?qū)Э梢院芊奖愕亟⒁粋€多文檔應(yīng)用程序,只需在MFCAppWizard向?qū)У?步選擇Multipledocuments程序類型。SDI和MDI使用不同框架窗口。SDI的框架窗口是唯一的主框架窗口,窗口類是CMainFrame,由CFrameWnd派生而來。,6.1.3多文檔,MDI的框架窗口分為主框架窗口和子框架窗口,區(qū)別于SDI,MDI的主框架窗口不包含視圖,分別由每個子框架窗口包含一個視圖。MDI的主框架窗口類不與某個打開的文檔相關(guān)聯(lián),而只與子框架窗口相關(guān)聯(lián)。MDI主框架窗口類CMainFrame由CMDIFrameWnd派生而來,而MDI子框架窗口類CChildFrame由CMDIChildWnd派生而來。,在文檔/視圖結(jié)構(gòu)中,數(shù)據(jù)以文檔類對象的形式存在。文檔對象通過視圖對象顯示,而視圖對象又是主框架窗口的一個子窗口,并且涉及文檔操作的菜單和工具欄等資源也是建立在主框架窗口上。這樣,文檔、視圖、框架類和所涉及的資源形成了一種固定的聯(lián)系,這種固定的聯(lián)系就稱為文檔模板。也就是說,文檔模板描述了相對應(yīng)每一種類型文檔的視圖和窗口的風(fēng)格類型。當(dāng)打開某種類型的文件時,應(yīng)用程序必須確定那一種文檔模板用于解釋這種文件。在初始化程序時,必須首先注冊文檔模板,以便程序利用這個模板來完成主框架窗口、視圖、文檔對象的創(chuàng)建和資源的裝入。,文檔模板的概念:,標(biāo)準(zhǔn)Windows應(yīng)用程序界面窗口組成:客戶區(qū)非客戶區(qū):,6.2菜單設(shè)計,窗口的邊框標(biāo)題欄菜單欄工具欄狀態(tài)欄滾動條菜單、工具欄、狀態(tài)欄是用戶與應(yīng)用程序進(jìn)行交互的重要工具。菜單和工具欄為應(yīng)用程序提供了傳遞用戶命令的選擇區(qū)域,而狀態(tài)欄是提示信息的輸出區(qū)域。,6.2.1建立菜單資源,使用MFCAppWizard向?qū)?chuàng)建文檔/視圖結(jié)構(gòu)應(yīng)用程序時,向?qū)⒆詣由蒞indows標(biāo)準(zhǔn)的菜單資源和命令處理函數(shù)。但這個默認(rèn)生成的主框架菜單資源往往不能滿足實際的需要,因此我們需要利用菜單資源編輯器對其進(jìn)行修改和添加。,例編寫一個單文檔應(yīng)用程序DrawCoin,為程序添加一個“畫硬幣”主菜單,并在其中添加“增加硬幣”和“減少硬幣”兩個菜單項。,1利用MFCAppWizardexe向?qū)?chuàng)建SDI應(yīng)用程序。在項目工作區(qū)的ResourceView頁面中選擇Menu并展開它,雙擊下面的IDR_MAINFRAME項彈出菜單資源編輯器,顯示應(yīng)用程序向?qū)鶆?chuàng)建的菜單資源。2為程序添加主菜單。雙擊菜單欄右邊虛空白框,彈出屬性對話框,在Caption框輸入主菜單的標(biāo)題“畫硬幣(/硬幣數(shù)量加一UpdateAllViews(NULL);/刷新視圖voidCDrawCoinDoc:OnCoinSub()if(m_nCoins0)m_nCoins-;/硬幣數(shù)量減一UpdateAllViews(NULL);,定義成員變量m_nCoins并初始化:,2.為文檔派生類CDrawCoinDoc添加一個類型為int、屬性為public的成員變量m_nCoins。按下Ctrl+W啟動ClassWizard類向?qū)?,在ClassName欄和ObjectIDs欄選擇類CDrawCoinDoc,在Messages欄選擇DeleteContents,單擊AddFuntion按鈕和EditCode按鈕,在生成的虛函數(shù)中添加初始化成員變量m_nCoins的代碼,該函數(shù)在用戶重新使用(打開或創(chuàng)建)一個文檔時調(diào)用。,voidCDrawCoinDoc:DeleteContents()/TODO:Addyour.m_nCoins=1;/初始化成員變量CDocument:DeleteContents();,在客戶區(qū)畫出硬幣:,3.在OnDraw()函數(shù)中根據(jù)m_nCoins畫出指定個數(shù)的硬幣。voidCDrawCoinView:OnDraw(CDC*pDC)CDrawCoinDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);/TODO:adddrawcodefornativedataherefor(inti=0;im_nCoins;i+)inty=200-10*i;pDC-Ellipse(200,y,300,y-30);/用兩個偏移的橢圓表示一枚硬幣pDC-Ellipse(200,y-10,300,y-35);,利用ClassWizard類向?qū)椴藛雾椞砑用钐幚砗瘮?shù)時,在Messages欄除了WM_COMMAND消息,還有一個UPDATE_COMMAND_UI消息,它稱為更新命令用戶界面消息。有時一個菜單項可以有可用和不可用兩種狀態(tài),即允許或禁止菜單項的使用(處于灰色狀態(tài))。例如,初始狀態(tài)下,菜單項“減少硬幣”不可用,因為開始時客戶區(qū)一個硬幣也沒有畫出。UPDATE_COMMAND_UI消息為程序員根據(jù)程序當(dāng)前運(yùn)行情況對菜單項的狀態(tài)進(jìn)行動態(tài)設(shè)置而提供了一個簡便的方法。參閱例6-4。,更新命令用戶界面消息,菜單分為兩類:依附于框架窗口的固定菜單浮動的彈出式菜單,快捷菜單,上下文菜單當(dāng)用戶單擊鼠標(biāo)右鍵,彈出式菜單出現(xiàn)在光標(biāo)所在位置。彈出式菜單是通過利用CMenu類和其成員函數(shù),在程序運(yùn)行過程中動態(tài)建立的。一般彈出式菜單是利用現(xiàn)有的菜單項來進(jìn)行創(chuàng)建,也可以為彈出式菜單專門建立一個菜單資源,然后通過調(diào)用函數(shù)CMenu:LoadMenu()裝入所創(chuàng)建的菜單資源。,6.2.3彈出式菜單,當(dāng)右擊鼠標(biāo)并釋放后,WM_CONTEXTMENU消息將發(fā)給應(yīng)用程序。因此,在程序中可通過為WM_CONTEXTMENU添加消息處理函數(shù)來實現(xiàn)彈出式菜單。WM_CONTEXTMENU消息是在收到WM_RBUTTONUP消息后,由Windows產(chǎn)生的。但如果在WM_RBUTTONUP的消息處理函數(shù)中沒有調(diào)用基類的處理函數(shù),那么應(yīng)用程序?qū)⒉粫盏絎M_CONTEXTMENU消息。例:,有關(guān)彈出式菜單的消息處理,利用ClassWizard為視圖類添加WM_CONTEXTMENU的消息處理函數(shù),添加如下代碼:voidCDrawCoinView:OnContextMenu(CWnd*pWnd,CPointpoint)CMenumenuPopup;/聲明菜單對象if(menuPopup.CreatePopupMenu()/創(chuàng)建彈出式菜單menuPopup.AppendMenu(MF_STRING,ID_COIN_ADD,增加硬幣tCtrl+A);menuPopup.AppendMenu(MF_STRING,ID_COIN_SUB,減少硬幣tCtrl+B);menuPopup.TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,this);,例為程序DrawCoin添加彈出式菜單。,函數(shù)TrackPopupMenu()用于在指定位置顯示彈出式菜單,并響應(yīng)用戶的菜單項選擇。函數(shù)第1個參數(shù)是位置標(biāo)記,TPM_LEFTALIGN表示以x坐標(biāo)為標(biāo)準(zhǔn)左對齊顯示菜單;第2、3個參數(shù)指定彈出式菜單的屏幕坐標(biāo);第4個參數(shù)指定擁有此彈出式菜單的窗口。,函數(shù)AppendMenu()用于向菜單menuPopup添加菜單項,函數(shù)第1個參數(shù)指定加入菜單項的風(fēng)格,值MF_STRING表示菜單項是一個字符串;第2個參數(shù)指定要加入菜單項的ID,如ID_COIN_ADD;第3個參數(shù)指定菜單項的顯示文本。,Windows是基于事件驅(qū)動、消息傳遞的操作系統(tǒng)。用戶所有的輸入都是以事件或消息的形式傳遞給應(yīng)用程序的,鼠標(biāo)也不例外。鼠標(biāo)驅(qū)動程序?qū)⑹髽?biāo)硬件信號轉(zhuǎn)換成Windows可以識別的信息,Windows根據(jù)這些信息構(gòu)造鼠標(biāo)消息,并將它們發(fā)送到應(yīng)用程序的消息隊列中。,6.3鼠標(biāo)消息處理,鼠標(biāo)構(gòu)成:左鍵、右鍵(中鍵和滾動滑輪)鼠標(biāo)操作:單擊、雙擊、釋放和移動主要鼠標(biāo)消息:WM_MOUSEMOVE:移動WM_LBUTTONDOWN:按下左鍵WM_LBUTTONUP:釋放左鍵WM_RBUTTONDOWN:按下右鍵WM_RBUTTONUP:釋放右鍵WM_LBUTTONDBLCLK:雙擊左鍵,6.3.1鼠標(biāo)消息,鼠標(biāo)消息分為兩類:,客戶區(qū)鼠標(biāo)消息非客戶區(qū)鼠標(biāo)消息:,WM_NCLBUTTONDOWN:按下鼠標(biāo)左鍵消WM_NCRBUTTONDOWN:按下鼠標(biāo)右鍵.,非客戶區(qū)鼠標(biāo)消息由Windows操作系統(tǒng)處理,應(yīng)用程序一般不需要處理??蛻魠^(qū)鼠標(biāo)消息發(fā)送到應(yīng)用程序后,可以由應(yīng)用程序自己處理。通過消息結(jié)構(gòu)中的消息參數(shù)wParam來區(qū)分客戶區(qū)鼠標(biāo)消息和非客戶區(qū)鼠標(biāo)消息。,利用MFCClassWizard類向?qū)傻氖髽?biāo)消息處理函數(shù)一般都有兩個參數(shù):nFlags:類型為UINT,表示鼠標(biāo)按鍵和鍵盤上控制鍵的狀態(tài)。point:類型為CPoint,表示鼠標(biāo)當(dāng)前所在位置坐標(biāo)。,鼠標(biāo)消息處理函數(shù)參數(shù),使用鼠標(biāo)的一個典型例子就是繪圖程序,鼠標(biāo)被用作畫筆,繪圖過程中要進(jìn)行不同鼠標(biāo)消息的處理,如按下鼠標(biāo)、釋放鼠標(biāo)和移動鼠標(biāo)等。當(dāng)用戶按下鼠標(biāo)左鍵時必須記錄下當(dāng)前鼠標(biāo)的位置,當(dāng)用戶移動鼠標(biāo)時,如果鼠標(biāo)左鍵被按住,則從上一個鼠標(biāo)位置到當(dāng)前位置畫一段直線,并保存當(dāng)前鼠標(biāo)的位置,供下一次畫線用。當(dāng)用戶彈起鼠標(biāo)左鍵時釋放鼠標(biāo)。,6.3.2鼠標(biāo)消息處理舉例:一個簡單的繪圖程序,例編寫一個繪圖程序,程序運(yùn)行后,當(dāng)用戶在客戶區(qū)窗口按下鼠標(biāo)左鍵并移動時,根據(jù)鼠標(biāo)移動的軌跡繪制出指定的線段。,1利用MFCAppWizardexe向?qū)?chuàng)建一個SDI應(yīng)用程序MyDraw,為視圖類CMyDrawView添加成員變量:protected:/定義有關(guān)鼠標(biāo)作圖的成員變量CPointm_ptOrigin;/起始點坐標(biāo)boolm_bDragging;/拖拽標(biāo)記HCURSORm_hCross;/光標(biāo)句柄,2在視圖類CMyDrawView構(gòu)造函數(shù)中設(shè)置拖拽標(biāo)記和十字光標(biāo)。CMyDrawView:CMyDrawView()/TODO:addconstructioncodeherem_bDragging=false;/初始化拖拽標(biāo)記/獲得十字光標(biāo)句柄m_hCross=AfxGetApp()-LoadStandardCursor(IDC_CROSS);,3利用ClassWizard類向?qū)橐晥D類添加按下鼠標(biāo)左鍵WM_LBUTTONDOWN的消息處理函數(shù)。,voidCMyDrawView:OnLButtonDown(UINTnFlags,CPointpoint)/TODO:Addyourmessage.SetCapture();/捕捉鼠標(biāo):SetCursor(m_hCross);/設(shè)置十字光標(biāo)m_ptOrigin=point;m_bDragging=TRUE;/設(shè)置拖拽標(biāo)記/CView:OnLButtonDown(nFlags,point);,利用ClassWizard類向?qū)橐晥D類添加鼠標(biāo)移動WM_MOUSEMOVE的消息處理函數(shù)。,voidCMyDrawView:OnMouseMove(UINTnFlags,CPointpoint)/TODO:Addyourmessage.if(m_bDragging)CClientDCdc(this);dc.MoveTo(m_ptOrigin);dc.LineTo(point);/繪制線段m_ptOrigin=point;/新的起始點,voidCMyDrawView:OnLButtonUp(UINTnFlags,CPointpoint)if(m_bDragging)m_bDragging=false;/清拖拽標(biāo)記ReleaseCapture();/釋放鼠標(biāo),還原鼠標(biāo)形狀,系統(tǒng)中任一時刻只有當(dāng)前窗口才能捕獲鼠標(biāo)。在程序中需要時通過調(diào)用函數(shù)CWnd:SetCapture()捕獲鼠標(biāo),使用鼠標(biāo)畫圖結(jié)束后應(yīng)該調(diào)用函數(shù)ReleaseCapture()釋放鼠標(biāo)。,利用ClassWizard類向?qū)橐晥D類添加左鍵釋放WM_LBUTTONUP的消息處理函數(shù)。,MyDraw程序有一個缺陷,當(dāng)改變窗口大小或?qū)⒋翱谧钚』笤僦匦麓蜷_,原來的線段沒有顯示出來。其原因是此時調(diào)用的是視圖類的刷新函數(shù)OnDraw(),而在該函數(shù)中并沒有實現(xiàn)繪制線段的功能。,MyDraw程序存在的問題,完善繪圖程序MyDraw,1為線段定義新類CLine。選擇“Insert|NewClass”菜單命令,彈出NewClass對話框中,在Classtype欄選擇GenericClass,在類名Name欄輸入CLine,在類名Baseclasses欄輸入CObject,單擊OK按鈕,自動生成了類CLine的頭文件Line.h和實現(xiàn)文件Line.cpp的框架。,例完善繪圖程序MyDraw,在重繪窗口時能夠顯示已繪制的線段。,2為類CLine定義成員變量和成員函數(shù)。classCline:CObjectprivate:/定義成員變量,表示一條直線起點和終點的坐標(biāo)CPointm_pt1;CPointm_pt2;public:CLine();virtualCLine();CLine(CPointpt1,CPointpt2);/構(gòu)造函數(shù)voidDrawLine(CDC*pDC);/繪制線段;,CLine:CLine(CPointpt1,CPointpt2)m_pt1=pt1;m_pt2=pt2;voidCLine:DrawLine(CDC*pDC)pDC-MoveTo(m_pt1);pDC-LineTo(m_pt2);,在Line.cpp中編寫成員函數(shù)的實現(xiàn)代碼:,3一般都使用數(shù)組來保存多條線段的數(shù)據(jù),而且MFC提供了實現(xiàn)動態(tài)數(shù)組的類模板。類CObArray支持CObject指針數(shù)組,用它定義的對象可以動態(tài)生成。這樣,可將存放每條線段數(shù)據(jù)的變量的指針存到CObArray類的對象中。為此在文檔類CMyDrawDoc中定義有關(guān)的成員變量和成員函數(shù),需要包含CLine類定義的頭文件。,存儲線段采用什么數(shù)據(jù)結(jié)構(gòu)?,#includeLine.h#include/使用MFC類模板classCMyDrawDoc:publicCDtected:CTypedPtrArraym_LineArray;/存放線段對象指針的動態(tài)數(shù)組public:CLine*GetLine(intnIndex);/獲取指定序號線段對象的指針voidAddLine(CPointpt1,CPointpt2);/向動態(tài)數(shù)組中添加新的線段對象的指針intGetNumLines();/獲取線段的數(shù)量.;,成員變量m_LineArray是類模板CTypedPtrArray的對象。使用數(shù)組類模板CTypedPtrArray需要指定兩個模板參數(shù):CTypedPtrArray參數(shù)BASE_CLASS指定基類,可以是CObArray或CPtrArray;參數(shù)TYPE指定存儲在基類數(shù)組中元素的類型。本例中,這兩個參數(shù)分別為CObArray和CLine*,表示m_LineArray是CObArray的派生類對象,用來存放CLine對象的指針。為了使用MFC類模板,須包含頭文件afxtempl.h。,使用MFC數(shù)組類模板CTypedPtrArray,其他主要成員函數(shù):voidCMyDrawDoc:AddLine(CPointpt1,CPointpt2)CLine*pLine=newCLine(pt1,pt2);/新建一條線段對象m_LineArray.Add(pLine);/將該線段加到動態(tài)數(shù)組CLine*CMyDrawDoc:GetLine(intnIndex)if(nIndexm_LineArray.GetUpperBound()/判斷是否越界returnNULL;returnm_LineArray.GetAt(nIndex);/返回給定序號線段對象的指針,intCMyDrawDoc:GetNumLines()returnm_LineArray.GetSize();/返回線段的數(shù)量,4鼠標(biāo)移動時,除了繪制線段,還要保存當(dāng)前線段的起點和終點坐標(biāo)。需要在視圖類CMyDrawView的鼠標(biāo)移動消息處理函數(shù)OnMouseMove()中添加有關(guān)代碼。,voidCMyDrawView:OnMouseMove(UINTnFlags,CPointpoint)/TODO:Addyourmessagehandlercodehereand/orcalldefaultif(m_bDragging)CMyDrawDoc*pDoc=GetDocument();/獲得文檔對象指針ASSERT_VALID(pDoc);/測試文檔對象是否運(yùn)行有效pDoc-AddLine(m_ptOrigin,point);/加入線段到指針數(shù)組CClientDCdc(this);dc.MoveTo(m_ptOrigin);dc.LineTo(point);/繪制線段m_ptOrigin=point;/新的起始點/CView:OnMouseMove(nFlags,point);,為了在改變程序窗口大小或最小化窗口后重新打開窗口時保留窗口中原有的圖形,必須在OnDraw()函數(shù)中重新繪制前面利用鼠標(biāo)所繪制的線段。這些線段的坐標(biāo)作為類CLine對象的成員變量,所有CLine對象的指針已保存在動態(tài)數(shù)組m_LineArray中。,5.修改OnDraw()函數(shù),voidCMyDrawView:OnDraw(CDC*pDC)CMyDrawDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);/TODO:adddrawcodefornativedatahereintnIndex=pDoc-GetNumLines();/取得線段的數(shù)量/循環(huán)畫出每一段線段while(nIndex-)/數(shù)組下標(biāo)從0到nIndex-1pDoc-GetLine(nIndex)-DrawLine(pDC);/類CLine的成員函數(shù),6.4工具欄和狀態(tài)欄設(shè)計6.4.1添加工具欄按鈕我們知道單擊工具欄按鈕也產(chǎn)生命令消息。而且,事實上工具欄按鈕和菜單項的功能往往是一致的。為了使工具欄上某個按鈕的功能與某個菜單命令的功能相同,只需讓該按鈕的ID值與對應(yīng)菜單命令的ID值相同即可。參看例6-10。,狀態(tài)欄用于顯示當(dāng)前操作的提示信息和程序的運(yùn)行狀態(tài)。MFC應(yīng)用程序默認(rèn)的狀態(tài)欄分為四個部分:第1部分:顯示菜單或工具欄的提示信息第2部分:CapsLock,顯示鍵盤的大小寫狀態(tài)第3部分:NumLock,顯示鍵盤的數(shù)字狀態(tài)第4部分:ScrollLock,顯示鍵盤的滾動狀態(tài)狀態(tài)欄上的每個部分稱為一個面板(pane)。,6.4.2定制狀態(tài)欄,staticUINTindicators=ID_SEPARATOR,/定義分隔符,作為提示信息行的面板標(biāo)識ID_INDICATOR_CAPS,/大寫指示器面板標(biāo)識ID_INDICATOR_NUM,/數(shù)字指示器面板標(biāo)識ID_INDICATOR_SCRL,/滾動指示器面板標(biāo)識;,利用MFCAppWizard向?qū)?chuàng)建應(yīng)用程序時,在CMainFrame類中定義了一個成員變量m_wndStatusBar,它是狀態(tài)欄CStatusBar類的對象。在MFC應(yīng)用程序框架的實現(xiàn)文件MainFrm.cpp中,為狀態(tài)欄定義了一個靜態(tài)數(shù)組indicators。,為了顯示硬幣數(shù)量,添加一個ID為ID_INDICATOR_COIN的指示器面板,將數(shù)組indicators作如下修改:staticUINTindicators=ID_SEPARATOR,/statuslineindicatorID_INDICATOR_COIN,/顯示硬幣數(shù)量指示器ID_INDICATOR_CAPS,ID_INDICATOR_NUM,ID_INDICATOR_SCRL,;,例修改程序DrawCoin,在狀態(tài)欄顯示硬幣的數(shù)量。,修改OnDraw()函數(shù),添加顯示硬幣數(shù)量的代碼:.CStringstrCoins;/先獲得主窗口,再獲得狀態(tài)欄的指針CStatusBar*pStatus=(CStatusBar*)AfxGetApp()-m_pMainWnd-GetDescendantWindow(ID_VIEW_STATUS_BAR);if(pStatus)strCoins.Format(硬幣:%d,pDoc-m_nCoins);/設(shè)置要顯示的信息pStatus-SetPaneText(1,strCoins);/顯示硬幣數(shù)量,面板編號從0開始.,涉及到數(shù)據(jù)處理的應(yīng)用程序一般都要考慮文檔數(shù)據(jù)的永久保存。雖然可以直接利用類CFile來實現(xiàn)文件的讀寫操功能,但在MFC應(yīng)用程序中,序列化(Serialize)使得程序員可以不直接面對一個物理文件而進(jìn)行文檔的讀寫。序列化實現(xiàn)了文檔數(shù)據(jù)的保存和裝入的幕后工作,MFC通過序列化實現(xiàn)應(yīng)用程序的文檔讀寫功能。,6.5文檔的讀寫,1.序列化的基本思想:一個類應(yīng)該能夠?qū)ψ约旱某蓡T變量的數(shù)據(jù)進(jìn)行讀寫操作,對象可以通過讀操作而重新創(chuàng)建。即對象可以將其當(dāng)前狀態(tài)(由其成員變量的值表示)寫入永久性存儲體(通常是指磁盤)中,以后可以從永久性存儲體中讀?。ㄝd入)對象的狀態(tài),從而重建對象。類的對象自己應(yīng)該具備將狀態(tài)值寫入磁盤或從磁盤中讀出的方法(即成員函數(shù)),這種對象的保存和恢復(fù)的過程稱為序列化。,6.5.1序列化工作原理,一個可序列化的類必須有一個稱作為序列化的成員函數(shù)Serialize(),文檔的序列化在文檔類的成員函數(shù)Serialize()中進(jìn)行。MFCAppWizard應(yīng)用程序向?qū)г谏蓱?yīng)用程序時只創(chuàng)建了文檔派生類序列化Serialize()函數(shù)的框架,由于不同程序的數(shù)據(jù)結(jié)構(gòu)各不相同,可序列化的類應(yīng)該重載Serialize()函數(shù),使其支持對特定數(shù)據(jù)的序列化。并且,任何需要保存的變量(數(shù)據(jù))都應(yīng)該在文檔派生類中聲明。,2.序列化函數(shù)Serialize(),voidCMyDoc:Serialize(CArchive&ar)if(ar.IsStoring()/TODO:addstoringcodehere.else/TODO:addloadingcodehere.,3.MFCAppWizard向?qū)傻腟eralize()函數(shù),函數(shù)參數(shù)ar是一個CArchive類的對象,序列化操作通過CArchive類對象作為中介來完成。CArchive類對象由應(yīng)用程序框架創(chuàng)建,并與用戶正在使用的文件關(guān)聯(lián)在一起。CArchive類包含一個類CFile指針的成員變量,當(dāng)創(chuàng)建一個CArchive類對象時,該對象與一個類CFile或其派生類的對象聯(lián)系在一起,代表一個已打開的文件。C+通過文件句柄來實現(xiàn)磁盤輸入和輸出,一個文件句柄與一個磁盤文件相關(guān)聯(lián)。而MFC中物理文件的讀寫操作是由CFile類及其派生類來完成的,它們對文件句柄進(jìn)行了封裝。CArchive類對象為讀寫CFile類對象中的可序列化數(shù)據(jù)提供了一種安全的緩沖機(jī)制,形成了如下關(guān)系:Serialize()函數(shù)CArchive類對象CFile類對象磁盤文件,1.CDocument:OnFileSave()完成的工作:文檔對象獲取一個當(dāng)前文件CFile指針,創(chuàng)建一個CArchive對象;文檔對象調(diào)用成員函數(shù)Serialize(),并把創(chuàng)建的CArchive對象作為參數(shù)傳遞給函數(shù)Serialize();Serialize()函數(shù)根據(jù)函數(shù)IsStoring()的返回值(true)執(zhí)行if語句的第一個分支,調(diào)用要讀寫對象的序列化函數(shù)Serialize(),而讀寫對象使用CFile來寫入數(shù)據(jù)。,6.5.2MFC應(yīng)用程序的序列化,類必須直接或間接地從CObject類派生而來,因為是利用CArchive類把CObject類的派生類對象序列化;必須定義一個不帶參數(shù)的構(gòu)造函數(shù),當(dāng)從磁盤文件載入文檔時調(diào)用該構(gòu)造函數(shù)創(chuàng)建一個可序列化的對象,使用從文件讀出來的數(shù)據(jù)填充對象的成員變量;在類的頭文件中使用DECLARE_SERIAL宏,在類的實現(xiàn)文件中使用IMPLEMENT_SERIAL宏;在自定義類中重載序列化成員函數(shù)Serialize()。,2.MFC類的序列化必須滿足的四個條件:,1.前面已定義了用來保存線段數(shù)據(jù)的CLine類,它已是CObject的派生類,現(xiàn)在添加函數(shù)Serialize()的聲明和DECLARE_SERIAL宏。2.在實現(xiàn)源文件Line.cpp中成員函數(shù)定義前添加IMPLEMENT_SERIAL宏:IMPLEMENT_SERIAL(CLine,CObject,1)/實現(xiàn)序列化類Cline3.編寫類CLine的序列化函數(shù)Serialize()。,例完善繪圖程序MyDraw,以便能將

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論