




已閱讀5頁,還剩80頁未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(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)建一個(gè)完整的文檔/視圖結(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ì)算機(jī)的一個(gè)主要應(yīng)用,而信息是用數(shù)據(jù)表示的,因此數(shù)據(jù)的處理是一般軟件都要完成的一項(xiàng)主要工作。采用傳統(tǒng)的編程方法,數(shù)據(jù)處理是一項(xiàng)復(fù)雜的任務(wù),并且每一個(gè)程序員都可能有不同的處理方法。為了統(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)欄不同程序的相同菜單項(xiàng)和工具欄按鈕表示相同的操作,6.1.1文檔與視圖結(jié)構(gòu)概述,Windows應(yīng)用程序界面特點(diǎn):,分為數(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ù)。一個(gè)文檔代表了用戶存儲或打開的一個(gè)文件單位。文檔的主要作用是把對數(shù)據(jù)的處理從對用戶界面的處理中分離出來,集中處理數(shù)據(jù),同時(shí)提供了一個(gè)與其它類交互的接口。,什么是文檔?,視圖是文檔在屏幕上的一個(gè)映像,它就像一個(gè)觀景器,用戶通過視圖看到文檔,也是通過視圖來改變文檔,視圖充當(dāng)了文檔與用戶之間的媒介物。應(yīng)用程序通過視圖向用戶顯示文檔中的數(shù)據(jù),并把用戶的輸入解釋為對文檔的操作。一個(gè)視圖總是與一個(gè)文檔對象相關(guān)聯(lián),用戶通過與文檔相關(guān)聯(lián)的視圖與文檔進(jìn)行交互。當(dāng)用戶打開一個(gè)文檔時(shí),應(yīng)用程序就會創(chuàng)建一個(gè)與之相關(guān)聯(lián)的視圖。,什么是視圖?,視圖負(fù)責(zé)顯示和編輯文檔數(shù)據(jù),但不負(fù)責(zé)存儲。用戶對數(shù)據(jù)的編輯需要依靠窗口上的鼠標(biāo)與鍵盤操作才得以完成,這些消息都是由視圖類接收后進(jìn)行處理或通知文檔類,如收到窗口刷新消息時(shí)調(diào)用視圖類的成員函數(shù)OnDraw()顯示文檔內(nèi)容。視圖還可在打印機(jī)上輸出。文檔負(fù)責(zé)數(shù)據(jù)的讀寫操作,數(shù)據(jù)通常被保存在文檔類的成員變量中,文檔類通過一個(gè)稱為序列化的成員函數(shù)將成員變量的數(shù)據(jù)保存到磁盤文件中。MFC應(yīng)用程序?yàn)閿?shù)據(jù)的序列化提供了默認(rèn)支持。,視圖和文檔的功能:,文檔、視圖、框架窗口之間的關(guān)系,一個(gè)視圖是一個(gè)沒有邊框的窗口,它位于主框架窗口中的客戶區(qū)。視圖是文檔對外顯示的窗口,但它并不能完全獨(dú)立,它必須依存在一個(gè)框架窗口內(nèi)。一個(gè)視圖只能擁有一個(gè)文檔,但一個(gè)文檔可以同時(shí)擁有多個(gè)視圖。,視圖是文檔在屏幕上的一個(gè)映像,它就像一個(gè)觀景器,文檔/視圖結(jié)構(gòu)的優(yōu)點(diǎn):,把數(shù)據(jù)處理類從用戶界面處理類中分離出來,使得每一個(gè)類都能集中地執(zhí)行一項(xiàng)工作。把Windows程序通常要做的工作分成若干定義好的類,這樣有助于應(yīng)用程序的模塊化,程序也易于擴(kuò)展,編程時(shí)只需修改所涉及的類。雖然文檔/視圖結(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ù),在需要時(shí)都從文檔類中獲取,這樣做會影響程序的效率。例如,在文本編輯程序中,往往在視圖中緩存部分?jǐn)?shù)據(jù),這樣可以避免對文檔的頻繁訪問,提高運(yùn)行效率。,在視圖類中定義數(shù)據(jù),包含多個(gè)類的MFC文檔/視圖結(jié)構(gòu)應(yīng)用程序要管理這些類中的數(shù)據(jù),除了考慮在程序的哪一部分擁有數(shù)據(jù)和在哪一部分顯示數(shù)據(jù),一個(gè)主要的問題是文檔數(shù)據(jù)更改后如何保持視圖顯示的同步,即文檔與視圖如何進(jìn)行交互。在文檔、視圖和應(yīng)用程序框架之間包含了一系列復(fù)雜的相互作用過程,文檔與視圖的交互是通過類的公有成員變量和成員函數(shù)實(shí)現(xiàn)的。,6.1.2文檔與視圖之間的相互作用,1視圖類的成員函數(shù)GetDocument()一個(gè)視圖對象只有一個(gè)與之相關(guān)聯(lián)的文檔對象。在MFC應(yīng)用程序中,視圖對象通過調(diào)用成員函數(shù)函數(shù)GetDocument()得到當(dāng)前文檔。GetDocument()是視圖類的成員函數(shù),調(diào)用它可以返回與視圖相關(guān)聯(lián)的文檔對象的指針,利用這個(gè)指針可以訪問文檔類及其派生類的公有成員。當(dāng)利用MFCAppWizard向?qū)?chuàng)建一個(gè)SDI單文檔應(yīng)用程序Mysdi時(shí),生成了視圖類的一個(gè)派生類,并在派生類中定義了函數(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ù)代碼:,一個(gè)文檔對象可以有多個(gè)與之相關(guān)聯(lián)的視圖對象,當(dāng)一個(gè)文檔的數(shù)據(jù)通過某個(gè)視圖被修改后,與它關(guān)聯(lián)的每一個(gè)視圖都必須反映出這些修改。因此,視圖在需要時(shí)必須進(jìn)行重繪,即當(dāng)文檔數(shù)據(jù)發(fā)生改變時(shí),必須通知到所有相關(guān)聯(lián)的視圖對象,以便更新所顯示的數(shù)據(jù)。更新與該文檔有關(guān)的所有視圖的方法是調(diào)用成員函數(shù)CDocument:UpdateAllViews()。,2CDocument類的成員函數(shù)UpdateAllViews(),如果在文檔派生類的成員函數(shù)中調(diào)用UpdateAllViews()函數(shù),其第一個(gè)參數(shù)pSender設(shè)為NULL,表示所有與當(dāng)前文檔相關(guān)的視圖都要重繪(參見例6-3)。如果在視圖派生類的成員函數(shù)中通過當(dāng)前文檔指針調(diào)用UpdateAllViews()函數(shù),其第一個(gè)參數(shù)pSender設(shè)為當(dāng)前視圖,如下形式:GetDocument()-UpdateAllViews(this),函數(shù)聲明:voidUpdateAllViews(CView*pSender,LPARAMlHint=0L,CObject*pHint=NULL);,當(dāng)程序調(diào)用CDocument:UpdateAllViews()函數(shù)時(shí),實(shí)際上是調(diào)用了所有相關(guān)視圖的OnUpdate()函數(shù),以更新相關(guān)的視圖。需要時(shí),可以直接在視圖派生類的成員函數(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);/使整個(gè)窗口矩形無效,通過調(diào)/用OnDraw()更新整個(gè)視圖窗口,基類CView的成員函數(shù),在OnUpdate()中通過調(diào)用函數(shù)CWnd:Invalidate()刷新整個(gè)客戶區(qū),我們也可以在自己的CWnd派生類中直接調(diào)用函數(shù)Invalidate()。,總結(jié):刷新視圖時(shí)默認(rèn)的函數(shù)調(diào)用過程:CDocument:UpdateAllViews()CView:OnUpdate()CWnd:Invalidate()OnPaint()OnDraw(),MFC基于文檔/視圖結(jié)構(gòu)的應(yīng)用程序分為單文檔和多文檔兩種類型,一個(gè)多文檔應(yīng)用程序有一個(gè)主窗口,但在主窗口中可以同時(shí)打開多個(gè)子窗口,每一個(gè)子窗口對應(yīng)一個(gè)不同的文檔。利用MFCAppWizardexe向?qū)Э梢院芊奖愕亟⒁粋€(gè)多文檔應(yīng)用程序,只需在MFCAppWizard向?qū)У?步選擇Multipledocuments程序類型。SDI和MDI使用不同框架窗口。SDI的框架窗口是唯一的主框架窗口,窗口類是CMainFrame,由CFrameWnd派生而來。,6.1.3多文檔,MDI的框架窗口分為主框架窗口和子框架窗口,區(qū)別于SDI,MDI的主框架窗口不包含視圖,分別由每個(gè)子框架窗口包含一個(gè)視圖。MDI的主框架窗口類不與某個(gè)打開的文檔相關(guān)聯(lián),而只與子框架窗口相關(guān)聯(lián)。MDI主框架窗口類CMainFrame由CMDIFrameWnd派生而來,而MDI子框架窗口類CChildFrame由CMDIChildWnd派生而來。,在文檔/視圖結(jié)構(gòu)中,數(shù)據(jù)以文檔類對象的形式存在。文檔對象通過視圖對象顯示,而視圖對象又是主框架窗口的一個(gè)子窗口,并且涉及文檔操作的菜單和工具欄等資源也是建立在主框架窗口上。這樣,文檔、視圖、框架類和所涉及的資源形成了一種固定的聯(lián)系,這種固定的聯(lián)系就稱為文檔模板。也就是說,文檔模板描述了相對應(yīng)每一種類型文檔的視圖和窗口的風(fēng)格類型。當(dāng)打開某種類型的文件時(shí),應(yīng)用程序必須確定那一種文檔模板用于解釋這種文件。在初始化程序時(shí),必須首先注冊文檔模板,以便程序利用這個(gè)模板來完成主框架窗口、視圖、文檔對象的創(chuàng)建和資源的裝入。,文檔模板的概念:,標(biāo)準(zhǔn)Windows應(yīng)用程序界面窗口組成:客戶區(qū)非客戶區(qū):,6.2菜單設(shè)計(jì),窗口的邊框標(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)用程序時(shí),向?qū)⒆詣由蒞indows標(biāo)準(zhǔn)的菜單資源和命令處理函數(shù)。但這個(gè)默認(rèn)生成的主框架菜單資源往往不能滿足實(shí)際的需要,因此我們需要利用菜單資源編輯器對其進(jìn)行修改和添加。,例編寫一個(gè)單文檔應(yīng)用程序DrawCoin,為程序添加一個(gè)“畫硬幣”主菜單,并在其中添加“增加硬幣”和“減少硬幣”兩個(gè)菜單項(xiàng)。,1利用MFCAppWizardexe向?qū)?chuàng)建SDI應(yīng)用程序。在項(xiàng)目工作區(qū)的ResourceView頁面中選擇Menu并展開它,雙擊下面的IDR_MAINFRAME項(xiàng)彈出菜單資源編輯器,顯示應(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添加一個(gè)類型為int、屬性為public的成員變量m_nCoins。按下Ctrl+W啟動ClassWizard類向?qū)?,在ClassName欄和ObjectIDs欄選擇類CDrawCoinDoc,在Messages欄選擇DeleteContents,單擊AddFuntion按鈕和EditCode按鈕,在生成的虛函數(shù)中添加初始化成員變量m_nCoins的代碼,該函數(shù)在用戶重新使用(打開或創(chuàng)建)一個(gè)文檔時(shí)調(diào)用。,voidCDrawCoinDoc:DeleteContents()/TODO:Addyour.m_nCoins=1;/初始化成員變量CDocument:DeleteContents();,在客戶區(qū)畫出硬幣:,3.在OnDraw()函數(shù)中根據(jù)m_nCoins畫出指定個(gè)數(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);/用兩個(gè)偏移的橢圓表示一枚硬幣pDC-Ellipse(200,y-10,300,y-35);,利用ClassWizard類向?qū)椴藛雾?xiàng)添加命令處理函數(shù)時(shí),在Messages欄除了WM_COMMAND消息,還有一個(gè)UPDATE_COMMAND_UI消息,它稱為更新命令用戶界面消息。有時(shí)一個(gè)菜單項(xiàng)可以有可用和不可用兩種狀態(tài),即允許或禁止菜單項(xiàng)的使用(處于灰色狀態(tài))。例如,初始狀態(tài)下,菜單項(xiàng)“減少硬幣”不可用,因?yàn)殚_始時(shí)客戶區(qū)一個(gè)硬幣也沒有畫出。UPDATE_COMMAND_UI消息為程序員根據(jù)程序當(dāng)前運(yùn)行情況對菜單項(xiàng)的狀態(tài)進(jìn)行動態(tài)設(shè)置而提供了一個(gè)簡便的方法。參閱例6-4。,更新命令用戶界面消息,菜單分為兩類:依附于框架窗口的固定菜單浮動的彈出式菜單,快捷菜單,上下文菜單當(dāng)用戶單擊鼠標(biāo)右鍵,彈出式菜單出現(xiàn)在光標(biāo)所在位置。彈出式菜單是通過利用CMenu類和其成員函數(shù),在程序運(yùn)行過程中動態(tài)建立的。一般彈出式菜單是利用現(xiàn)有的菜單項(xiàng)來進(jìn)行創(chuàng)建,也可以為彈出式菜單專門建立一個(gè)菜單資源,然后通過調(diào)用函數(shù)CMenu:LoadMenu()裝入所創(chuàng)建的菜單資源。,6.2.3彈出式菜單,當(dāng)右擊鼠標(biāo)并釋放后,WM_CONTEXTMENU消息將發(fā)給應(yīng)用程序。因此,在程序中可通過為WM_CONTEXTMENU添加消息處理函數(shù)來實(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)用戶的菜單項(xiàng)選擇。函數(shù)第1個(gè)參數(shù)是位置標(biāo)記,TPM_LEFTALIGN表示以x坐標(biāo)為標(biāo)準(zhǔn)左對齊顯示菜單;第2、3個(gè)參數(shù)指定彈出式菜單的屏幕坐標(biāo);第4個(gè)參數(shù)指定擁有此彈出式菜單的窗口。,函數(shù)AppendMenu()用于向菜單menuPopup添加菜單項(xiàng),函數(shù)第1個(gè)參數(shù)指定加入菜單項(xiàng)的風(fēng)格,值MF_STRING表示菜單項(xiàng)是一個(gè)字符串;第2個(gè)參數(shù)指定要加入菜單項(xiàng)的ID,如ID_COIN_ADD;第3個(gè)參數(shù)指定菜單項(xiàng)的顯示文本。,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)用程序的消息隊(duì)列中。,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ù)一般都有兩個(gè)參數(shù):nFlags:類型為UINT,表示鼠標(biāo)按鍵和鍵盤上控制鍵的狀態(tài)。point:類型為CPoint,表示鼠標(biāo)當(dāng)前所在位置坐標(biāo)。,鼠標(biāo)消息處理函數(shù)參數(shù),使用鼠標(biāo)的一個(gè)典型例子就是繪圖程序,鼠標(biāo)被用作畫筆,繪圖過程中要進(jìn)行不同鼠標(biāo)消息的處理,如按下鼠標(biāo)、釋放鼠標(biāo)和移動鼠標(biāo)等。當(dāng)用戶按下鼠標(biāo)左鍵時(shí)必須記錄下當(dāng)前鼠標(biāo)的位置,當(dāng)用戶移動鼠標(biāo)時(shí),如果鼠標(biāo)左鍵被按住,則從上一個(gè)鼠標(biāo)位置到當(dāng)前位置畫一段直線,并保存當(dāng)前鼠標(biāo)的位置,供下一次畫線用。當(dāng)用戶彈起鼠標(biāo)左鍵時(shí)釋放鼠標(biāo)。,6.3.2鼠標(biāo)消息處理舉例:一個(gè)簡單的繪圖程序,例編寫一個(gè)繪圖程序,程序運(yùn)行后,當(dāng)用戶在客戶區(qū)窗口按下鼠標(biāo)左鍵并移動時(shí),根據(jù)鼠標(biāo)移動的軌跡繪制出指定的線段。,1利用MFCAppWizardexe向?qū)?chuàng)建一個(gè)SDI應(yīng)用程序MyDraw,為視圖類CMyDrawView添加成員變量:protected:/定義有關(guān)鼠標(biāo)作圖的成員變量CPointm_ptOrigin;/起始點(diǎn)坐標(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;/新的起始點(diǎn),voidCMyDrawView:OnLButtonUp(UINTnFlags,CPointpoint)if(m_bDragging)m_bDragging=false;/清拖拽標(biāo)記ReleaseCapture();/釋放鼠標(biāo),還原鼠標(biāo)形狀,系統(tǒng)中任一時(shí)刻只有當(dāng)前窗口才能捕獲鼠標(biāo)。在程序中需要時(shí)通過調(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程序有一個(gè)缺陷,當(dāng)改變窗口大小或?qū)⒋翱谧钚』笤僦匦麓蜷_,原來的線段沒有顯示出來。其原因是此時(shí)調(diào)用的是視圖類的刷新函數(shù)OnDraw(),而在該函數(shù)中并沒有實(shí)現(xiàn)繪制線段的功能。,MyDraw程序存在的問題,完善繪圖程序MyDraw,1為線段定義新類CLine。選擇“Insert|NewClass”菜單命令,彈出NewClass對話框中,在Classtype欄選擇GenericClass,在類名Name欄輸入CLine,在類名Baseclasses欄輸入CObject,單擊OK按鈕,自動生成了類CLine的頭文件Line.h和實(shí)現(xiàn)文件Line.cpp的框架。,例完善繪圖程序MyDraw,在重繪窗口時(shí)能夠顯示已繪制的線段。,2為類CLine定義成員變量和成員函數(shù)。classCline:CObjectprivate:/定義成員變量,表示一條直線起點(diǎn)和終點(diǎn)的坐標(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ù)的實(shí)現(xiàn)代碼:,3一般都使用數(shù)組來保存多條線段的數(shù)據(jù),而且MFC提供了實(shí)現(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需要指定兩個(gè)模板參數(shù):CTypedPtrArray參數(shù)BASE_CLASS指定基類,可以是CObArray或CPtrArray;參數(shù)TYPE指定存儲在基類數(shù)組中元素的類型。本例中,這兩個(gè)參數(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)移動時(shí),除了繪制線段,還要保存當(dāng)前線段的起點(diǎn)和終點(diǎn)坐標(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;/新的起始點(diǎn)/CView:OnMouseMove(nFlags,point);,為了在改變程序窗口大小或最小化窗口后重新打開窗口時(shí)保留窗口中原有的圖形,必須在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è)計(jì)6.4.1添加工具欄按鈕我們知道單擊工具欄按鈕也產(chǎn)生命令消息。而且,事實(shí)上工具欄按鈕和菜單項(xiàng)的功能往往是一致的。為了使工具欄上某個(gè)按鈕的功能與某個(gè)菜單命令的功能相同,只需讓該按鈕的ID值與對應(yīng)菜單命令的ID值相同即可。參看例6-10。,狀態(tài)欄用于顯示當(dāng)前操作的提示信息和程序的運(yùn)行狀態(tài)。MFC應(yīng)用程序默認(rèn)的狀態(tài)欄分為四個(gè)部分:第1部分:顯示菜單或工具欄的提示信息第2部分:CapsLock,顯示鍵盤的大小寫狀態(tài)第3部分:NumLock,顯示鍵盤的數(shù)字狀態(tài)第4部分:ScrollLock,顯示鍵盤的滾動狀態(tài)狀態(tài)欄上的每個(gè)部分稱為一個(gè)面板(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)用程序時(shí),在CMainFrame類中定義了一個(gè)成員變量m_wndStatusBar,它是狀態(tài)欄CStatusBar類的對象。在MFC應(yīng)用程序框架的實(shí)現(xiàn)文件MainFrm.cpp中,為狀態(tài)欄定義了一個(gè)靜態(tài)數(shù)組indicators。,為了顯示硬幣數(shù)量,添加一個(gè)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來實(shí)現(xiàn)文件的讀寫操功能,但在MFC應(yīng)用程序中,序列化(Serialize)使得程序員可以不直接面對一個(gè)物理文件而進(jìn)行文檔的讀寫。序列化實(shí)現(xiàn)了文檔數(shù)據(jù)的保存和裝入的幕后工作,MFC通過序列化實(shí)現(xiàn)應(yīng)用程序的文檔讀寫功能。,6.5文檔的讀寫,1.序列化的基本思想:一個(gè)類應(yīng)該能夠?qū)ψ约旱某蓡T變量的數(shù)據(jù)進(jìn)行讀寫操作,對象可以通過讀操作而重新創(chuàng)建。即對象可以將其當(dāng)前狀態(tài)(由其成員變量的值表示)寫入永久性存儲體(通常是指磁盤)中,以后可以從永久性存儲體中讀取(載入)對象的狀態(tài),從而重建對象。類的對象自己應(yīng)該具備將狀態(tài)值寫入磁盤或從磁盤中讀出的方法(即成員函數(shù)),這種對象的保存和恢復(fù)的過程稱為序列化。,6.5.1序列化工作原理,一個(gè)可序列化的類必須有一個(gè)稱作為序列化的成員函數(shù)Serialize(),文檔的序列化在文檔類的成員函數(shù)Serialize()中進(jìn)行。MFCAppWizard應(yīng)用程序向?qū)г谏蓱?yīng)用程序時(shí)只創(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是一個(gè)CArchive類的對象,序列化操作通過CArchive類對象作為中介來完成。CArchive類對象由應(yīng)用程序框架創(chuàng)建,并與用戶正在使用的文件關(guān)聯(lián)在一起。CArchive類包含一個(gè)類CFile指針的成員變量,當(dāng)創(chuàng)建一個(gè)CArchive類對象時(shí),該對象與一個(gè)類CFile或其派生類的對象聯(lián)系在一起,代表一個(gè)已打開的文件。C+通過文件句柄來實(shí)現(xiàn)磁盤輸入和輸出,一個(gè)文件句柄與一個(gè)磁盤文件相關(guān)聯(lián)。而MFC中物理文件的讀寫操作是由CFile類及其派生類來完成的,它們對文件句柄進(jìn)行了封裝。CArchive類對象為讀寫CFile類對象中的可序列化數(shù)據(jù)提供了一種安全的緩沖機(jī)制,形成了如下關(guān)系:Serialize()函數(shù)CArchive類對象CFile類對象磁盤文件,1.CDocument:OnFileSave()完成的工作:文檔對象獲取一個(gè)當(dāng)前文件CFile指針,創(chuàng)建一個(gè)CArchive對象;文檔對象調(diào)用成員函數(shù)Serialize(),并把創(chuàng)建的CArchive對象作為參數(shù)傳遞給函數(shù)Serialize();Serialize()函數(shù)根據(jù)函數(shù)IsStoring()的返回值(true)執(zhí)行if語句的第一個(gè)分支,調(diào)用要讀寫對象的序列化函數(shù)Serialize(),而讀寫對象使用CFile來寫入數(shù)據(jù)。,6.5.2MFC應(yīng)用程序的序列化,類必須直接或間接地從CObject類派生而來,因?yàn)槭抢肅Archive類把CObject類的派生類對象序列化;必須定義一個(gè)不帶參數(shù)的構(gòu)造函數(shù),當(dāng)從磁盤文件載入文檔時(shí)調(diào)用該構(gòu)造函數(shù)創(chuàng)建一個(gè)可序列化的對象,使用從文件讀出來的數(shù)據(jù)填充對象的成員變量;在類的頭文件中使用DECLARE_SERIAL宏,在類的實(shí)現(xiàn)文件中使用IMPLEMENT_SERIAL宏;在自定義類中重載序列化成員函數(shù)Serialize()。,2.MFC類的序列化必須滿足的四個(gè)條件:,1.前面已定義了用來保存線段數(shù)據(jù)的CLine類,它已是CObject的派生類,現(xiàn)在添加函數(shù)Serialize()的聲明和DECLARE_SERIAL宏。2.在實(shí)現(xiàn)源文件Line.cpp中成員函數(shù)定義前添加IMPLEMENT_SERIAL宏:IMPLEMENT_SERIAL(CLine,CObject,1)/實(shí)現(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)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 江蘇南通2024~2025學(xué)年高一下冊6月期末考試數(shù)學(xué)試題含解析
- 福建漳州第一中學(xué)2024~2025學(xué)年高一下冊數(shù)冊末試題
- 樂器行業(yè)口碑營銷中的用戶參與度研究考核試卷
- 化學(xué)教育中的多元智能理論應(yīng)用研究考核試卷
- 保險(xiǎn)代理人在團(tuán)隊(duì)協(xié)作中的作用考核試卷
- 綠色產(chǎn)業(yè)政策與區(qū)域發(fā)展協(xié)同研究考核試卷
- 光學(xué)儀器在海洋科普中的應(yīng)用案例光學(xué)儀器考核試卷
- 2025年中國LED蜂窩像素屏數(shù)據(jù)監(jiān)測研究報(bào)告
- 2025年中國AⅤ端子數(shù)據(jù)監(jiān)測報(bào)告
- 2025至2030年中國陶泥市場分析及競爭策略研究報(bào)告
- 2023年春季國開《學(xué)前教育科研方法》期末大作業(yè)(參考答案)
- 2023四川安全員《B證》考試題庫
- EXCELVBA函數(shù)參考手冊
- 雨污分流工程安全文明施工方案優(yōu)質(zhì)資料
- SYB第一步:把自己作為創(chuàng)業(yè)者來評價(jià)課件
- 建筑工程中級職稱論文范文精選6篇
- 變電站值班員技師實(shí)操試卷(答案)
- 青少年性教育課件
- 2022年桂林市衛(wèi)生學(xué)校教師招聘筆試題庫及答案解析
- 生活中的化學(xué)-課件
- 欄桿安裝單元工程施工質(zhì)量驗(yàn)收評定表完整
評論
0/150
提交評論