Visual C++面向?qū)ο缶幊探坛痰?章 文檔與視圖.ppt_第1頁(yè)
Visual C++面向?qū)ο缶幊探坛痰?章 文檔與視圖.ppt_第2頁(yè)
Visual C++面向?qū)ο缶幊探坛痰?章 文檔與視圖.ppt_第3頁(yè)
Visual C++面向?qū)ο缶幊探坛痰?章 文檔與視圖.ppt_第4頁(yè)
Visual C++面向?qū)ο缶幊探坛痰?章 文檔與視圖.ppt_第5頁(yè)
已閱讀5頁(yè),還剩77頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、第 5 章 文檔與視圖,版權(quán)所有 復(fù)制必究,文檔與視圖結(jié)構(gòu)的工作原理 文檔的讀寫(xiě)操作機(jī)制 菜單編程 工具欄編程 狀態(tài)欄編程,文檔與視圖結(jié)構(gòu)是MFC應(yīng)用程序最基本的程序結(jié)構(gòu),適用于大多數(shù)Windows應(yīng)用程序。文檔和視圖完成了程序的大部分功能,它們是MFC應(yīng)用程序的核心。文檔與視圖結(jié)構(gòu)是MFC的基石,掌握文檔與視圖結(jié)構(gòu)對(duì)于利用MFC編程有著至關(guān)重要的意義。本章對(duì)文檔與視圖結(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)一和簡(jiǎn)化

2、數(shù)據(jù)處理方法,Microsoft公司在MFC中提出了文檔/視圖結(jié)構(gòu)的概念,其產(chǎn)品Word就是典型的文檔/視圖結(jié)構(gòu)應(yīng)用程序。,5.1 文檔與視圖結(jié)構(gòu),標(biāo)題欄 主菜單 工具欄 客戶區(qū) 狀態(tài)欄 不同程序的相同菜單項(xiàng)和工具欄按鈕表示相同的操作。,5.1.1 文檔與視圖結(jié)構(gòu)概述,Windows應(yīng)用程序界面特點(diǎn):,分為數(shù)據(jù)的管理和顯示 文檔用于管理和維護(hù)數(shù)據(jù) 視圖用來(lái)顯示和編輯數(shù)據(jù) MFC通過(guò)其文檔類(lèi)和視圖類(lèi)提供了大量有關(guān)數(shù)據(jù)處理的方法。,MFC文檔/視圖結(jié)構(gòu)數(shù)據(jù)處理工作分工:,文檔的概念在MFC應(yīng)用程序中的適用范圍很廣,一般說(shuō)來(lái),文檔是能夠被邏輯地組合的一系列數(shù)據(jù),包括文本、圖形、圖象和表格數(shù)據(jù)。 一個(gè)

3、文檔代表了用戶存儲(chǔ)或打開(kāi)的一個(gè)文件單位。文檔的主要作用是把對(duì)數(shù)據(jù)的處理從對(duì)用戶界面的處理中分離出來(lái),集中處理數(shù)據(jù),同時(shí)提供了一個(gè)與其它類(lèi)交互的接口。,什么是文檔?,視圖是文檔在屏幕上的一個(gè)映像,它就像一個(gè)觀景器,用戶通過(guò)視圖看到文檔,也是通過(guò)視圖來(lái)改變文檔,視圖充當(dāng)了文檔與用戶之間的媒介物。 應(yīng)用程序通過(guò)視圖向用戶顯示文檔中的數(shù)據(jù),并把用戶的輸入解釋為對(duì)文檔的操作。 一個(gè)視圖總是與一個(gè)文檔對(duì)象相關(guān)聯(lián),用戶通過(guò)與文檔相關(guān)聯(lián)的視圖與文檔進(jìn)行交互。當(dāng)用戶打開(kāi)一個(gè)文檔時(shí),應(yīng)用程序就會(huì)創(chuàng)建一個(gè)與之相關(guān)聯(lián)的視圖。,什么是視圖?,視圖負(fù)責(zé)顯示和編輯文檔數(shù)據(jù),但不負(fù)責(zé)存儲(chǔ)。用戶對(duì)數(shù)據(jù)的編輯需要依靠窗口上的鼠標(biāo)

4、與鍵盤(pán)操作才得以完成,這些消息都是由視圖類(lèi)接收后進(jìn)行處理或通知文檔類(lèi),如收到窗口刷新消息時(shí)調(diào)用視圖類(lèi)的成員函數(shù)OnDraw()顯示文檔內(nèi)容。 視圖還可在打印機(jī)上輸出。 文檔負(fù)責(zé)數(shù)據(jù)的讀寫(xiě)操作,數(shù)據(jù)通常被保存在文檔類(lèi)的成員變量中,文檔類(lèi)通過(guò)一個(gè)稱為序列化的成員函數(shù)將成員變量的數(shù)據(jù)保存到磁盤(pán)文件中。MFC應(yīng)用程序?yàn)閿?shù)據(jù)的序列化提供了默認(rèn)支持。,視圖和文檔的功能:,文檔、視圖、框架窗口之間的關(guān)系,一個(gè)視圖是一個(gè)沒(méi)有邊框的窗口,它位于主框架窗口中的客戶區(qū)。視圖是文檔對(duì)外顯示的窗口,但它并不能完全獨(dú)立,它必須依存在一個(gè)框架窗口內(nèi)。 一個(gè)視圖只能擁有一個(gè)文檔,但一個(gè)文檔可以同時(shí)擁有多個(gè)視圖。,視圖是文檔在

5、屏幕上的一個(gè)映像,它就像一個(gè)觀景器,文檔/視圖結(jié)構(gòu)的優(yōu)點(diǎn):,把數(shù)據(jù)處理類(lèi)從用戶界面處理類(lèi)中分離出來(lái),使得每一個(gè)類(lèi)都能集中地執(zhí)行一項(xiàng)工作。 把Windows程序通常要做的工作分成若干定義好的類(lèi),這樣有助于應(yīng)用程序的模塊化,程序也易于擴(kuò)展,編程時(shí)只需修改所涉及的類(lèi)。 雖然文檔/視圖結(jié)構(gòu)牽涉到許多類(lèi),其中的也關(guān)系比較復(fù)雜,但MFC AppWizard向?qū)Ы⒌腗FC應(yīng)用程序框架已經(jīng)把程序的主要結(jié)構(gòu)完成了,模塊間的消息傳遞以及各函數(shù)的功能都已確定。 MFC應(yīng)用程序框架起到了穿針引線的作用,按照消息處理函數(shù)功能的不同,將不同消息的響應(yīng)分別分布在文檔類(lèi)和視圖類(lèi)中。,文檔/視圖結(jié)構(gòu)并沒(méi)有完全要求所有數(shù)據(jù)都屬

6、于文檔類(lèi),視圖類(lèi)也可以有自己的數(shù)據(jù)。如果在視圖類(lèi)中不定義任何數(shù)據(jù),在需要時(shí)都從文檔類(lèi)中獲取,這樣做會(huì)影響程序的效率。 例如,在文本編輯程序中,往往在視圖中緩存部分?jǐn)?shù)據(jù),這樣可以避免對(duì)文檔的頻繁訪問(wèn),提高運(yùn)行效率。,在視圖類(lèi)中定義數(shù)據(jù),包含多個(gè)類(lèi)的MFC文檔/視圖結(jié)構(gòu)應(yīng)用程序要管理這些類(lèi)中的數(shù)據(jù),除了考慮在程序的哪一部分擁有數(shù)據(jù)和在哪一部分顯示數(shù)據(jù),一個(gè)主要的問(wèn)題是文檔數(shù)據(jù)更改后如何保持視圖顯示的同步,即文檔與視圖如何進(jìn)行交互。 在文檔、視圖和應(yīng)用程序框架之間包含了一系列復(fù)雜的相互作用過(guò)程,文檔與視圖的交互是通過(guò)類(lèi)的公有成員變量和成員函數(shù)實(shí)現(xiàn)的。,5.1.2 文檔與視圖之間的相互作用,1視圖類(lèi)的

7、成員函數(shù)GetDocument() 一個(gè)視圖對(duì)象只有一個(gè)與之相關(guān)聯(lián)的文檔對(duì)象。在MFC應(yīng)用程序中,視圖對(duì)象通過(guò)調(diào)用成員函數(shù)函數(shù)GetDocument()得到當(dāng)前文檔。GetDocument()是視圖類(lèi)的成員函數(shù),調(diào)用它可以返回與視圖相關(guān)聯(lián)的文檔對(duì)象的指針,利用這個(gè)指針可以訪問(wèn)文檔類(lèi)及其派生類(lèi)的公有成員。 當(dāng)利用MFC AppWizard向?qū)?chuàng)建一個(gè)SDI單文檔應(yīng)用程序Mysdi時(shí),生成了視圖類(lèi)的一個(gè)派生類(lèi),并在派生類(lèi)中定義了函數(shù)GetDocument()。,文檔和視圖類(lèi)常用的成員函數(shù),CMysdiDoc* CMysdiView:GetDocument() ASSERT(m_pDocument-

8、 IsKindOf(RUNTIME_CLASS(CMysdiDoc); return (CMysdiDoc*)m_pDocument; / m_pDocument是CArchive類(lèi)的數(shù)據(jù)成員, / 指向當(dāng)前文檔對(duì)象 ,GetDocument()的Debug版函數(shù)代碼:,一個(gè)文檔對(duì)象可以有多個(gè)與之相關(guān)聯(lián)的視圖對(duì)象,當(dāng)一個(gè)文檔的數(shù)據(jù)通過(guò)某個(gè)視圖被修改后,與它關(guān)聯(lián)的每一個(gè)視圖都必須反映出這些修改。因此,視圖在需要時(shí)必須進(jìn)行重繪,即當(dāng)文檔數(shù)據(jù)發(fā)生改變時(shí),必須通知到所有相關(guān)聯(lián)的視圖對(duì)象,以便更新所顯示的數(shù)據(jù)。 更新與該文檔有關(guān)的所有視圖的方法是調(diào)用成員函數(shù)CDocument:UpdateAllView

9、s()。,2CDocument類(lèi)的成員函數(shù)UpdateAllViews(),如果在文檔派生類(lèi)的成員函數(shù)中調(diào)用UpdateAllViews()函數(shù),其第一個(gè)參數(shù)pSender設(shè)為NULL,表示所有與當(dāng)前文檔相關(guān)的視圖都要重繪(參見(jiàn)例5-3)。 如果在視圖派生類(lèi)的成員函數(shù)中通過(guò)當(dāng)前文檔指針調(diào)用UpdateAllViews()函數(shù),其第一個(gè)參數(shù)pSender設(shè)為當(dāng)前視圖,如下形式: GetDocument()-UpdateAllViews(this),函數(shù)聲明: void UpdateAllViews(CView* pSender, LPARAM lHint = 0L, CObject* pHint

10、=NULL );,當(dāng)程序調(diào)用CDocument:UpdateAllViews()函數(shù)時(shí),實(shí)際上是調(diào)用了所有相關(guān)視圖的OnUpdate()函數(shù),以更新相關(guān)的視圖。需要時(shí),可以直接在視圖派生類(lèi)的成員函數(shù)中調(diào)用該函數(shù)刷新當(dāng)前視圖。,3視圖類(lèi)的成員函數(shù)OnUpdate(),void CView:OnUpdate(CView* pSender, LPARAM /*lHint*/, CObject* /*pHint*/) ASSERT(pSender != this); UNUSED(pSender); / unused in release builds / invalidate the entire

11、pane, erase background too Invalidate(TRUE); / 使整個(gè)窗口矩形無(wú)效,通過(guò)調(diào) / 用OnDraw()更新整個(gè)視圖窗口 ,基類(lèi)CView的成員函數(shù),在OnUpdate()中通過(guò)調(diào)用函數(shù)CWnd:Invalidate()刷新整個(gè)客戶區(qū),我們也可以在自己的CWnd派生類(lèi)中直接調(diào)用函數(shù)Invalidate()。,總結(jié):刷新視圖時(shí)默認(rèn)的函數(shù)調(diào)用過(guò)程: CDocument:UpdateAllViews() CView:OnUpdate() CWnd:Invalidate() OnPaint() OnDraw(),MFC基于文檔/視圖結(jié)構(gòu)的應(yīng)用程序分為單文檔和多文

12、檔兩種類(lèi)型,一個(gè)多文檔應(yīng)用程序有一個(gè)主窗口,但在主窗口中可以同時(shí)打開(kāi)多個(gè)子窗口,每一個(gè)子窗口對(duì)應(yīng)一個(gè)不同的文檔。 利用MFC AppWizardexe向?qū)Э梢院芊奖愕亟⒁粋€(gè)多文檔應(yīng)用程序,只需在MFC AppWizard向?qū)У?步選擇Multiple documents程序類(lèi)型。 SDI和MDI使用不同框架窗口。SDI的框架窗口是唯一的主框架窗口,窗口類(lèi)是CMainFrame,由CFrameWnd派生而來(lái)。,5.1.3 多文檔,MDI的框架窗口分為主框架窗口和子框架窗口,區(qū)別于SDI,MDI的主框架窗口不包含視圖,分別由每個(gè)子框架窗口包含一個(gè)視圖。MDI的主框架窗口類(lèi)不與某個(gè)打開(kāi)的文檔相關(guān)聯(lián)

13、,而只與子框架窗口相關(guān)聯(lián)。 MDI主框架窗口類(lèi)CMainFrame由CMDIFrameWnd派生而來(lái),而MDI子框架窗口類(lèi)CChildFrame由CMDIChildWnd派生而來(lái)。,在文檔/視圖結(jié)構(gòu)中,數(shù)據(jù)以文檔類(lèi)對(duì)象的形式存在。文檔對(duì)象通過(guò)視圖對(duì)象顯示,而視圖對(duì)象又是主框架窗口的一個(gè)子窗口,并且涉及文檔操作的菜單和工具欄等資源也是建立在主框架窗口上。這樣,文檔、視圖、框架類(lèi)和所涉及的資源形成了一種固定的聯(lián)系,這種固定的聯(lián)系就稱為文檔模板。也就是說(shuō),文檔模板描述了相對(duì)應(yīng)每一種類(lèi)型文檔的視圖和窗口的風(fēng)格類(lèi)型。 當(dāng)打開(kāi)某種類(lèi)型的文件時(shí),應(yīng)用程序必須確定那一種文檔模板用于解釋這種文件。在初始化程序時(shí)

14、,必須首先注冊(cè)文檔模板,以便程序利用這個(gè)模板來(lái)完成主框架窗口、視圖、文檔對(duì)象的創(chuàng)建和資源的裝入。,文檔模板的概念:,標(biāo)準(zhǔn)Windows應(yīng)用程序界面窗口組成: 客戶區(qū) 非客戶區(qū):,5.2 菜單設(shè)計(jì),窗口的邊框 標(biāo)題欄 菜單欄 工具欄 狀態(tài)欄 滾動(dòng)條 菜單、工具欄、狀態(tài)欄是用戶與應(yīng)用程序進(jìn)行交互的重要工具。菜單和工具欄為應(yīng)用程序提供了傳遞用戶命令的選擇區(qū)域,而狀態(tài)欄提供了提示信息的輸出區(qū)域。,5.2.1 建立菜單資源,使用MFC AppWizard向?qū)?chuàng)建文檔/視圖結(jié)構(gòu)應(yīng)用程序時(shí),向?qū)⒆詣?dòng)生成Windows標(biāo)準(zhǔn)的菜單資源和命令處理函數(shù)。但這個(gè)默認(rèn)生成的主框架菜單資源往往不能滿足實(shí)際的需要,因此我

15、們需要利用菜單資源編輯器對(duì)其進(jìn)行修改和添加。,例 編寫(xiě)一個(gè)單文檔應(yīng)用程序DrawCoin,為程序添加一個(gè)“畫(huà)硬幣”主菜單,并在其中添加“增加硬幣”和“減少硬幣”兩個(gè)菜單項(xiàng)。,1利用MFC AppWizardexe向?qū)?chuàng)建SDI應(yīng)用程序。在項(xiàng)目工作區(qū)的ResourceView頁(yè)面中選擇Menu并展開(kāi)它,雙擊下面的IDR_MAINFRAME項(xiàng)彈出菜單資源編輯器,顯示應(yīng)用程序向?qū)鶆?chuàng)建的菜單資源。 2為程序添加主菜單。雙擊菜單欄右邊虛空白框,彈出屬性對(duì)話框,在Caption框輸入主菜單的標(biāo)題“畫(huà)硬幣( / 硬幣數(shù)量加一 UpdateAllViews(NULL); / 刷新視圖 void CDrawC

16、oinDoc:OnCoinSub() if(m_nCoins0) m_nCoins-; / 硬幣數(shù)量減一 UpdateAllViews(NULL); ,定義成員變量m_nCoins并初始化:,2. 為文檔派生類(lèi)CDrawCoinDoc添加一個(gè)類(lèi)型為int、屬性為public的成員變量m_nCoins。 按下Ctrl+W啟動(dòng)ClassWizard類(lèi)向?qū)В贑lass Name欄和Object IDs欄選擇類(lèi)CDrawCoinDoc,在Messages欄選擇DeleteContents,單擊Add Funtion按鈕和Edit Code按鈕,在生成的虛函數(shù)中添加如下初始化成員變量m_nCoins的

17、代碼,該函數(shù)在用戶重新使用(打開(kāi)或創(chuàng)建)一個(gè)文檔時(shí)調(diào)用。,void CDrawCoinDoc:DeleteContents() / TODO: Add your . . . m_nCoins=1; / 初始化成員變量 CDocument:DeleteContents(); ,在客戶區(qū)畫(huà)出硬幣:,3. 在OnDraw()函數(shù)中根據(jù)m_nCoins畫(huà)出指定個(gè)數(shù)的硬幣。 void CDrawCoinView:OnDraw(CDC* pDC) CDrawCoinDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); / TODO: add draw code fo

18、r native data here for(int i=0; im_nCoins; i+) int y=200-10*i; pDC-Ellipse(200,y,300,y-30); / 用兩個(gè)偏移的橢圓表示一枚硬幣 pDC-Ellipse(200,y-10,300,y-35); ,利用ClassWizard類(lèi)向?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)“減少硬幣”不可用,

19、因?yàn)殚_(kāi)始時(shí)客戶區(qū)一個(gè)硬幣也沒(méi)有畫(huà)出。 UPDATE_COMMAND_UI消息為程序員根據(jù)程序當(dāng)前運(yùn)行情況對(duì)菜單項(xiàng)的狀態(tài)進(jìn)行動(dòng)態(tài)設(shè)置而提供了一個(gè)簡(jiǎn)便的方法。參閱例5-4。,何謂更新命令用戶界面消息?,菜單分為兩類(lèi): 依附于框架窗口的固定菜單 浮動(dòng)的彈出式菜單,快捷菜單,上下文菜單 當(dāng)用戶單擊鼠標(biāo)右鍵,彈出式菜單出現(xiàn)在光標(biāo)所在位置。彈出式菜單是通過(guò)利用CMenu類(lèi)和其成員函數(shù),在程序運(yùn)行過(guò)程中動(dòng)態(tài)建立的。 一般而言,彈出式菜單是利用現(xiàn)有的菜單項(xiàng)來(lái)進(jìn)行創(chuàng)建,但也可以為彈出式菜單專(zhuān)門(mén)建立一個(gè)菜單資源,然后通過(guò)調(diào)用函數(shù)CMenu:LoadMenu()裝入所創(chuàng)建的菜單資源。,5.2.3 彈出式菜單,當(dāng)右擊

20、鼠標(biāo)并釋放后,WM_CONTEXTMENU消息將發(fā)給應(yīng)用程序。因此,在程序中可通過(guò)為WM_CONTEXTMENU添加消息處理函數(shù)來(lái)實(shí)現(xiàn)彈出式菜單。 WM_CONTEXTMENU消息是在收到WM_ RBUTTONUP消息后,由Windows產(chǎn)生的。但如果在WM_RBUTTONUP的消息處理函數(shù)中沒(méi)有調(diào)用基類(lèi)的處理函數(shù),那么應(yīng)用程序?qū)⒉粫?huì)收到WM_CONTEXTMENU消息。 例:,有關(guān)彈出式菜單的消息處理,利用ClassWizard為視圖類(lèi)添加WM_CONTEXTMENU的消息處理函數(shù),添加如下代碼: void CDrawCoinView:OnContextMenu(CWnd* pWnd, CP

21、oint point) CMenu menuPopup; / 聲明菜單對(duì)象 if (menuPopup.CreatePopupMenu() / 創(chuàng)建彈出式菜單 / 向菜單menuPopup中添加菜單項(xiàng) menuPopup.AppendMenu(MF_STRING, ID_COIN_ADD, 增加硬幣tCtrl+A); menuPopup.AppendMenu(MF_STRING, ID_COIN_SUB, 減少硬幣tCtrl+B); / 顯示彈出式菜單,并跟蹤用戶的菜單項(xiàng)的選擇 menuPopup.TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y,

22、this); ,例 為程序DrawCoin添加彈出式菜單。,函數(shù)TrackPopupMenu()用于在指定位置顯示彈出式菜單,并響應(yīng)用戶的菜單項(xiàng)選擇。函數(shù)第1個(gè)參數(shù)是位置標(biāo)記,TPM_LEFTALIGN表示以x坐標(biāo)為標(biāo)準(zhǔn)左對(duì)齊顯示菜單;第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ū)動(dòng)、消息傳遞的操

23、作系統(tǒng)。用戶所有的輸入都是以事件或消息的形式傳遞給應(yīng)用程序的,鼠標(biāo)也不例外。 鼠標(biāo)驅(qū)動(dòng)程序?qū)⑹髽?biāo)硬件信號(hào)轉(zhuǎn)換成Windows可以識(shí)別的信息,Windows根據(jù)這些信息構(gòu)造鼠標(biāo)消息,并將它們發(fā)送到應(yīng)用程序的消息隊(duì)列中。,5.3 鼠標(biāo)消息處理,鼠標(biāo)構(gòu)成:左鍵、右鍵(中鍵和滾動(dòng)滑輪) 鼠標(biāo)操作:?jiǎn)螕?、雙擊、釋放和移動(dòng) 主要鼠標(biāo)消息: WM_MOUSEMOVE:移動(dòng) WM_LBUTTONDOWN:按下左鍵 WM_LBUTTONUP:釋放左鍵 WM_RBUTTONDOWN:按下右鍵 WM_RBUTTONUP:釋放右鍵 WM_LBUTTONDBLCLK:雙擊左鍵,5.3.1 鼠標(biāo)消息,鼠標(biāo)消息分為兩類(lèi):,

24、客戶區(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)用程序自己處理。 通過(guò)消息結(jié)構(gòu)中的消息參數(shù)wParam來(lái)區(qū)分客戶區(qū)鼠標(biāo)消息和非客戶區(qū)鼠標(biāo)消息。,利用MFC ClassWizard類(lèi)向?qū)傻氖髽?biāo)消息處理函數(shù)一般都有兩個(gè)參數(shù): nFlags:類(lèi)型為UINT,表示鼠標(biāo)按鍵和 鍵盤(pán)上控制鍵的狀態(tài)。 point:類(lèi)型為CPoint,表示鼠標(biāo)當(dāng)前所 在位置坐標(biāo)。,鼠標(biāo)消息處理函數(shù)參數(shù),使

25、用鼠標(biāo)的一個(gè)典型例子就是繪圖程序,鼠標(biāo)被用作畫(huà)筆,繪圖過(guò)程中要進(jìn)行不同鼠標(biāo)消息的處理,如按下鼠標(biāo)、釋放鼠標(biāo)和移動(dòng)鼠標(biāo)等。當(dāng)用戶按下鼠標(biāo)左鍵時(shí)必須記錄下當(dāng)前鼠標(biāo)的位置,當(dāng)用戶移動(dòng)鼠標(biāo)時(shí),如果鼠標(biāo)左鍵被按住,則從上一個(gè)鼠標(biāo)位置到當(dāng)前位置畫(huà)一段直線,并保存當(dāng)前鼠標(biāo)的位置,供下一次畫(huà)線用。當(dāng)用戶彈起鼠標(biāo)左鍵時(shí)釋放鼠標(biāo)。,5.3.1 鼠標(biāo)消息處理舉例:繪圖程序,例 編寫(xiě)一個(gè)繪圖程序,程序運(yùn)行后,當(dāng)用戶在客戶區(qū)窗口按下鼠標(biāo)左鍵并移動(dòng)時(shí),根據(jù)鼠標(biāo)移動(dòng)的軌跡繪制出指定的線段。,1利用MFC AppWizardexe向?qū)?chuàng)建一個(gè)SDI應(yīng)用程序MyDraw,為視圖類(lèi)CMyDrawView添加成員變量: prote

26、cted: / 定義有關(guān)鼠標(biāo)作圖的成員變量 CPoint m_ptOrigin; / 起始點(diǎn)坐標(biāo) bool m_bDragging; / 拖拽標(biāo)記 HCURSOR m_hCross; / 光標(biāo)句柄,2在視圖類(lèi)CMyDrawView構(gòu)造函數(shù)中設(shè)置拖拽標(biāo)記和十字光標(biāo)。 CMyDrawView:CMyDrawView() / TODO: add construction code here m_bDragging=false; / 初始化拖拽標(biāo)記 / 獲得十字光標(biāo)句柄 m_hCross=AfxGetApp()- LoadStandardCursor(IDC_CROSS); ,3利用ClassWiza

27、rd類(lèi)向?qū)橐晥D類(lèi)添加按下鼠標(biāo)左鍵WM_LBUTTONDOWN的消息處理函數(shù)。,void CMyDrawView:OnLButtonDown( UINT nFlags, CPoint point) / TODO: Add your message . . . . . . SetCapture(); / 捕捉鼠標(biāo) :SetCursor(m_hCross); / 設(shè)置十字光標(biāo) m_ptOrigin=point; m_bDragging=TRUE; / 設(shè)置拖拽標(biāo)記 / CView:OnLButtonDown(nFlags, point); ,利用ClassWizard類(lèi)向?qū)橐晥D類(lèi)添加鼠標(biāo)移動(dòng)WM

28、_MOUSEMOVE的消息處理函數(shù)。,void CMyDrawView:OnMouseMove( UINT nFlags, CPoint point) / TODO: Add your message . . . . . . if(m_bDragging) CClientDC dc(this); dc.MoveTo(m_ptOrigin); dc.LineTo(point); / 繪制線段 m_ptOrigin=point; / 新的起始點(diǎn) / CView:OnMouseMove(nFlags, point); ,void CMyDrawView:OnLButtonUp( UINT nFlag

29、s, CPoint point) / TODO: Add your message . . . . . . if(m_bDragging) m_bDragging=false; / 清拖拽標(biāo)記 ReleaseCapture(); / 釋放鼠標(biāo),還原鼠標(biāo)形狀 / CView:OnLButtonUp(nFlags, point); ,系統(tǒng)中任一時(shí)刻只有當(dāng)前窗口才能捕獲鼠標(biāo)。在程序中需要時(shí)通過(guò)調(diào)用函數(shù)CWnd:SetCapture()捕獲鼠標(biāo),使用鼠標(biāo)畫(huà)圖結(jié)束后應(yīng)該調(diào)用函數(shù)ReleaseCapture()釋放鼠標(biāo)。,利用ClassWizard類(lèi)向?qū)橐晥D類(lèi)添加左鍵釋放WM_LBUTTONUP的消息處

30、理函數(shù)。,MyDraw程序有一個(gè)缺陷,當(dāng)改變窗口大小或?qū)⒋翱谧钚』笤僦匦麓蜷_(kāi),原來(lái)的線段沒(méi)有顯示出來(lái)。其原因是此時(shí)調(diào)用的是視圖類(lèi)的刷新函數(shù)OnDraw(),而在該函數(shù)中并沒(méi)有實(shí)現(xiàn)繪制線段的功能。,MyDraw程序存在的問(wèn)題,完善繪圖程序MyDraw,1為線段定義新類(lèi)CLine。選擇“Insert|New Class”菜單命令,彈出New Class對(duì)話框中,在Class type欄選擇Generic Class,在類(lèi)名Name欄輸入CLine,在類(lèi)名Base classes欄輸入CObject,單擊OK按鈕,自動(dòng)生成了類(lèi)CLine的頭文件Line.h和實(shí)現(xiàn)文件Line.cpp的框架。,例 完

31、善繪圖程序MyDraw,在重繪窗口時(shí)能夠顯示已繪制的線段。,2為類(lèi)CLine定義成員變量和成員函數(shù)。 class Cline : CObject private: / 定義成員變量,表示一條直線起點(diǎn)和終點(diǎn)的坐標(biāo) CPoint m_pt1; CPoint m_pt2; public: CLine(); virtual CLine(); CLine(CPoint pt1, CPoint pt2); / 構(gòu)造函數(shù) void DrawLine(CDC *pDC); / 繪制線段 ;,CLine:CLine(CPoint pt1, CPoint pt2) m_pt1=pt1; m_pt2=pt2; vo

32、id CLine:DrawLine(CDC* pDC) pDC-MoveTo(m_pt1); pDC-LineTo(m_pt2); ,在Line.cpp中編寫(xiě)成員函數(shù)的實(shí)現(xiàn)代碼:,3一般都使用數(shù)組來(lái)保存多條線段的數(shù)據(jù),而且MFC提供了實(shí)現(xiàn)動(dòng)態(tài)數(shù)組的類(lèi)模板。類(lèi)CObArray支持CObject指針數(shù)組,用它定義的對(duì)象可以動(dòng)態(tài)生成。這樣,可將存放每條線段數(shù)據(jù)的變量的指針存到CObArray類(lèi)的對(duì)象中。為此在文檔類(lèi)CMyDrawDoc中定義有關(guān)的成員變量和成員函數(shù),需要包含CLine類(lèi)定義的頭文件。,存儲(chǔ)線段采用什么數(shù)據(jù)結(jié)構(gòu)?,#include Line.h #include / 使用MFC類(lèi)模板

33、class CMyDrawDoc : public CDocument . . . . . . protected: CTypedPtrArray m_LineArray; / 存放線段對(duì)象指針的動(dòng)態(tài)數(shù)組 public: CLine* GetLine(int nIndex); / 獲取指定序號(hào)線段對(duì)象的指針 void AddLine(CPoint pt1, CPoint pt2); / 向動(dòng)態(tài)數(shù)組中添加新的線段對(duì)象的指針 int GetNumLines(); / 獲取線段的數(shù)量 . . . . . . ;,成員變量m_LineArray是類(lèi)模板CTypedPtrArray的對(duì)象。使用數(shù)組類(lèi)模板

34、CTypedPtrArray需要指定兩個(gè)模板參數(shù): CTypedPtrArray 參數(shù)BASE_CLASS指定基類(lèi),可以是CObArray或CPtrArray;參數(shù)TYPE指定存儲(chǔ)在基類(lèi)數(shù)組中元素的類(lèi)型。本例中,這兩個(gè)參數(shù)分別為CObArray和CLine*,表示m_LineArray是CObArray的派生類(lèi)對(duì)象,用來(lái)存放CLine對(duì)象的指針。 為了使用MFC類(lèi)模板,須包含頭文件afxtempl.h。,使用MFC數(shù)組類(lèi)模板CTypedPtrArray,其他主要成員函數(shù): void CMyDrawDoc:AddLine(CPoint pt1, CPoint pt2) CLine* pLine=

35、new CLine(pt1, pt2); / 新建一條線段對(duì)象 m_LineArray.Add(pLine); / 將該線段加到動(dòng)態(tài)數(shù)組 CLine* CMyDrawDoc:GetLine(int nIndex) if(nIndexm_LineArray.GetUpperBound() / 判斷是否越界 return NULL; return m_LineArray.GetAt(nIndex); / 返回給定序號(hào)線段對(duì)象的指針 ,int CMyDrawDoc:GetNumLines() return m_LineArray.GetSize(); / 返回線段的數(shù)量 ,4當(dāng)鼠標(biāo)移動(dòng)時(shí),除了繪制線

36、段,還要保存當(dāng)前線段的起點(diǎn)坐標(biāo)和終點(diǎn)坐標(biāo)。需要在視圖類(lèi)CMyDrawView的OnMouseMove()鼠標(biāo)移動(dòng)消息處理函數(shù)中添加有關(guān)代碼。,void CMyDrawView:OnMouseMove(UINT nFlags, CPoint point) / TODO: Add your message handler code here and/or call default if(m_bDragging) CMyDrawDoc *pDoc=GetDocument(); /獲得文檔對(duì)象指針 ASSERT_VALID(pDoc); /測(cè)試文檔對(duì)象是否運(yùn)行有效 pDoc-AddLine(m_ptO

37、rigin, point); /加入線段到指針數(shù)組 CClientDC dc(this); dc.MoveTo(m_ptOrigin); dc.LineTo(point); / 繪制線段 m_ptOrigin=point; / 新的起始點(diǎn) / CView:OnMouseMove(nFlags, point); ,為了在改變程序窗口大小或最小化窗口后重新打開(kāi)窗口時(shí)保留窗口中原有的圖形,必須在OnDraw()函數(shù)中重新繪制前面利用鼠標(biāo)所繪制的線段。這些線段的坐標(biāo)作為類(lèi)CLine對(duì)象的成員變量,所有CLine對(duì)象的指針已保存在動(dòng)態(tài)數(shù)組m_LineArray中。,5. 修改OnDraw()函數(shù),voi

38、d CMyDrawView:OnDraw(CDC* pDC) CMyDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); / TODO: add draw code for native data here int nIndex=pDoc-GetNumLines(); / 取得線段的數(shù)量 / 循環(huán)畫(huà)出每一段線段 while(nIndex-) / 數(shù)組下標(biāo)從0到nIndex-1 pDoc-GetLine(nIndex)-DrawLine(pDC); / 類(lèi)CLine的成員函數(shù) ,5.4 工具欄和狀態(tài)欄設(shè)計(jì) 5.4.1 添加工具欄按鈕 我們知道單擊工

39、具欄按鈕也產(chǎn)生命令消息。而且,事實(shí)上工具欄按鈕和菜單項(xiàng)的功能往往是一致的。為了使工具欄上某個(gè)按鈕的功能與某個(gè)菜單命令的功能相同,只需讓該按鈕的ID值與對(duì)應(yīng)菜單命令的ID值相同即可。參看例5-10。,狀態(tài)欄用于顯示當(dāng)前操作的提示信息和程序的運(yùn)行狀態(tài)。 MFC應(yīng)用程序默認(rèn)的狀態(tài)欄分為四個(gè)部分: 第1部分:顯示菜單或工具欄的提示信息 第2部分: Caps Lock,顯示鍵盤(pán)的大小寫(xiě)狀態(tài) 第3部分: Num Lock,顯示鍵盤(pán)的數(shù)字狀態(tài) 第4部分: Scroll Lock,顯示鍵盤(pán)的滾動(dòng)狀態(tài) 狀態(tài)欄上的每個(gè)部分稱為一個(gè)面板(pane)。,5.4.2 定制狀態(tài)欄,static UINT indicato

40、rs = ID_SEPARATOR, / 定義分隔符,作為提示信息行的面板標(biāo)識(shí) ID_INDICATOR_CAPS, / 大寫(xiě)指示器面板標(biāo)識(shí) ID_INDICATOR_NUM, / 數(shù)字指示器面板標(biāo)識(shí) ID_INDICATOR_SCRL, / 滾動(dòng)指示器面板標(biāo)識(shí) ;,利用MFC AppWizard向?qū)?chuàng)建應(yīng)用程序時(shí),在CMainFrame類(lèi)中定義了一個(gè)成員變量m_wndStatusBar,它是狀態(tài)欄CStatusBar類(lèi)的對(duì)象。 在MFC應(yīng)用程序框架的實(shí)現(xiàn)文件MainFrm.cpp中,為狀態(tài)欄定義了一個(gè)靜態(tài)數(shù)組indicators。,為了顯示硬幣數(shù)量,添加一個(gè)ID為ID_INDICATOR_C

41、OIN的指示器面板,將數(shù)組indicators作如下修改: static UINT indicators = ID_SEPARATOR, / status line indicator ID_INDICATOR_COIN, / 顯示硬幣數(shù)量指示器 ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, ;,例 修改程序DrawCoin,在狀態(tài)欄顯示硬幣的數(shù)量。,修改OnDraw()函數(shù),添加顯示硬幣數(shù)量的代碼: . . . . . . CString strCoins; / 先獲得主窗口, 再獲得狀態(tài)欄的指針 CStatusBar* pS

42、tatus= (CStatusBar*)AfxGetApp()-m_pMainWnd- GetDescendantWindow(ID_VIEW_STATUS_BAR); if(pStatus) strCoins.Format(硬幣:%d, pDoc-m_nCoins); / 設(shè)置要顯示的信息 pStatus-SetPaneText(1, strCoins); / 顯示硬幣數(shù)量,面板編號(hào)從0開(kāi)始 . . . . . .,涉及到數(shù)據(jù)處理的應(yīng)用程序一般都要考慮文檔數(shù)據(jù)的永久保存。雖然我們可以直接利用類(lèi)CFile來(lái)實(shí)現(xiàn)文件的讀寫(xiě)操功能,但在MFC應(yīng)用程序中,序列化(Serialize)使得程序員可以不

43、直接面對(duì)一個(gè)物理文件而進(jìn)行文檔的讀寫(xiě)。序列化實(shí)現(xiàn)了文檔數(shù)據(jù)的保存和裝入的幕后工作,MFC通過(guò)序列化實(shí)現(xiàn)應(yīng)用程序的文檔讀寫(xiě)功能。,5.5 文檔的讀寫(xiě),1. 序列化的基本思想: 一個(gè)類(lèi)應(yīng)該能夠?qū)ψ约旱某蓡T變量的數(shù)據(jù)進(jìn)行讀寫(xiě)操作,對(duì)象可以通過(guò)讀操作而重新創(chuàng)建。即對(duì)象可以將其當(dāng)前狀態(tài)(由其成員變量的值表示)寫(xiě)入永久性存儲(chǔ)體(通常是指磁盤(pán))中,以后可以從永久性存儲(chǔ)體中讀取(載入)對(duì)象的狀態(tài),從而重建對(duì)象。類(lèi)的對(duì)象自己應(yīng)該具備將狀態(tài)值寫(xiě)入磁盤(pán)或從磁盤(pán)中讀出的方法(即成員函數(shù)),這種對(duì)象的保存和恢復(fù)的過(guò)程稱為序列化。,5.5.1 序列化工作原理,一個(gè)可序列化的類(lèi)必須有一個(gè)稱作為序列化的成員函數(shù)Seriali

44、ze(),文檔的序列化在文檔類(lèi)的成員函數(shù)Serialize()中進(jìn)行。MFC AppWizard應(yīng)用程序向?qū)г谏蓱?yīng)用程序時(shí)只創(chuàng)建了文檔派生類(lèi)序列化Serialize()函數(shù)的框架,由于不同程序的數(shù)據(jù)結(jié)構(gòu)各不相同,可序列化的類(lèi)應(yīng)該重載Serialize()函數(shù),使其支持對(duì)特定數(shù)據(jù)的序列化。并且,任何需要保存的變量(數(shù)據(jù))都應(yīng)該在文檔派生類(lèi)中聲明。,2. 序列化函數(shù)Serialize(),void CMyDoc:Serialize(CArchive& ar) if(ar.IsStoring() / TODO:add storing code here. else / TODO:add loadi

45、ng code here. ,3. MFC AppWizard向?qū)傻腟eralize()函數(shù),函數(shù)參數(shù)ar是一個(gè)CArchive類(lèi)的對(duì)象,文檔數(shù)據(jù)的序列化操作通過(guò)CArchive類(lèi)對(duì)象作為中介來(lái)完成。CArchive類(lèi)對(duì)象由應(yīng)用程序框架創(chuàng)建,并與用戶正在使用的文件關(guān)聯(lián)在一起。CArchive類(lèi)包含一個(gè)類(lèi)CFile指針的成員變量,當(dāng)創(chuàng)建一個(gè)CArchive類(lèi)對(duì)象時(shí),該對(duì)象與一個(gè)類(lèi)CFile或其派生類(lèi)的對(duì)象聯(lián)系在一起,代表一個(gè)已打開(kāi)的文件。 C+主要通過(guò)文件句柄來(lái)實(shí)現(xiàn)磁盤(pán)輸入和輸出,一個(gè)文件句柄與一個(gè)磁盤(pán)文件相關(guān)聯(lián)。而MFC中物理文件的讀寫(xiě)操作是由CFile類(lèi)及其派生類(lèi)來(lái)完成的,它們對(duì)文件句柄

46、進(jìn)行了封裝。CArchive類(lèi)對(duì)象為讀寫(xiě)CFile類(lèi)對(duì)象中的可序列化數(shù)據(jù)提供了一種安全的緩沖機(jī)制,它們之間形成了如下關(guān)系: Serialize()函數(shù) CArchive類(lèi)對(duì)象CFile類(lèi)對(duì)象 磁盤(pán)文件,1. CDocument:OnFileSave()完成的工作: 文檔對(duì)象獲取一個(gè)當(dāng)前文件CFile指針,創(chuàng)建一個(gè)CArchive對(duì)象; 文檔對(duì)象調(diào)用成員函數(shù)Serialize(),并把創(chuàng)建的CArchive對(duì)象作為參數(shù)傳遞給函數(shù)Serialize(); Serialize()函數(shù)根據(jù)函數(shù)IsStoring()的返回值(true)執(zhí)行if語(yǔ)句的第一個(gè)分支,調(diào)用要讀寫(xiě)對(duì)象的序列化函數(shù)Serializ

47、e(),而讀寫(xiě)對(duì)象使用CFile來(lái)寫(xiě)入數(shù)據(jù)。,5.5.2 MFC應(yīng)用程序的序列化,類(lèi)必須直接或間接地從CObject類(lèi)派生而來(lái),因?yàn)槭抢肅Archive類(lèi)把用戶的CObject類(lèi)的派生類(lèi)對(duì)象序列化; 類(lèi)必須定義一個(gè)不帶參數(shù)的構(gòu)造函數(shù),當(dāng)從磁盤(pán)文件載入文檔時(shí)調(diào)用該構(gòu)造函數(shù)來(lái)創(chuàng)建一個(gè)可序列化的對(duì)象,使用從文件中讀出來(lái)的數(shù)據(jù)填充對(duì)象的成員變量; 在類(lèi)的頭文件中使用DECLARE_SERIAL宏,在類(lèi)的實(shí)現(xiàn)文件中使用IMPLEMENT_SERIAL宏; 在自定義類(lèi)中重載序列化成員函數(shù)Serialize()。,2 MFC類(lèi)的序列化必須滿足的四個(gè)條件:,1. 前面已定義了用來(lái)保存線段數(shù)據(jù)的CLine類(lèi),它已是CObject的派生類(lèi),現(xiàn)在添加函數(shù)Serialize()的聲明和DECLARE_SERIAL宏。 2. 在實(shí)現(xiàn)源文件Line.cpp中成員函數(shù)定義前添加IMPLEMENT_SERIAL宏: IMPLEMENT_

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論