深入編程內(nèi)幕-VisualC++_第1頁
深入編程內(nèi)幕-VisualC++_第2頁
深入編程內(nèi)幕-VisualC++_第3頁
深入編程內(nèi)幕-VisualC++_第4頁
已閱讀5頁,還剩120頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

深入編程內(nèi)幕--VisualC++一走進(jìn)VisualC++*1理解VC工程*MFC編程特點(diǎn)*二MFC程序結(jié)構(gòu)分析*二MFC程序結(jié)構(gòu)分析*1WINDOWS程序工作原理*2建立應(yīng)用程序*3程序結(jié)構(gòu)剖析*3.1類CMYAPP*3.2類CMAINFRAME*三深入MFC類庫*3.3類三深入MFC類庫*1處理用戶輸入*1定義對話框資源*2定義對話框類*2有關(guān)屏幕輸出*1設(shè)備上下文工作原理*2實(shí)例繪圖原理剖析*3繪圖操作實(shí)現(xiàn)*4有關(guān)屏幕映射方式*3文件處理*1對象持續(xù)化簡述*2實(shí)例分析*3與文件處理關(guān)系密切的類CFVe*4DAO技術(shù)*1DAO與ODBC*2使用MFC實(shí)現(xiàn)DAO技術(shù)*5打印*打印和顯示*打印分頁*打印工作的開始和結(jié)束*打印程序?qū)嵗?四、VC程序調(diào)試*1.1調(diào)試環(huán)境的建立*1.2調(diào)試的一般過程*1.3如何設(shè)置斷點(diǎn)”1.4控制程序的運(yùn)行*1.5查看工具的使用*2高級調(diào)試技術(shù)*TRACE宏的利用*ASSERT宏的利用*ASSERT_yAUD宏的利用以及類的AssertValid()成員函的重載*對象的DUMP函數(shù)的利用*五VisualC++五VisualC++與多媒體*音的處理*1.1媒體控制接口*1.2波形混音器*2多媒體文件I/O*3多媒體圖形圖像技術(shù)*4圖像合成*5FLC動畫*6熱點(diǎn)*走進(jìn)VisualC++VisualC++作為一個功能非常強(qiáng)大的可視化應(yīng)用程序開發(fā)工具,是計(jì)算機(jī)界公認(rèn)的最優(yōu)秀的應(yīng)用開發(fā)工具之一。Microsoft的基本類庫MFC使得開發(fā)Windows應(yīng)用程序比以往任何時候都要容易。本光盤教學(xué)軟件的目的就是為了讓你學(xué)會在VisualC++環(huán)境下,利用微軟的基本類庫MFC開發(fā)出功能強(qiáng)大的Windows應(yīng)用程序。在本章節(jié)的內(nèi)容當(dāng)中,我們將向您介紹使用VC開發(fā)軟件需要用到的一些基本概念,使用MFC進(jìn)行編程的基本特點(diǎn),以及VISUALC++集成開發(fā)環(huán)境提供的一系列編程輔助工具——WIZARD的使用方法。1理解VC工程VisualC++作為一種程序設(shè)計(jì)語言,它同時也是一個集成開發(fā)工具,提供了軟件代碼自動生成和可視化的資源編輯功能。在使用VisualC++開發(fā)應(yīng)用程序的過程中,系統(tǒng)為我們生成了大量的各種類型的文件,在本節(jié)中將要詳細(xì)介紹VisualC++中這些不同類型的文件分別起到什么樣的作用,在此基礎(chǔ)上對VisualC++如何管理應(yīng)用程序所用到的各種文件有一個全面的認(rèn)識。首先要介紹的是擴(kuò)展名為dsw的文件類型,這種類型的文件在VC中是級別最高的,稱為Workspace文件。在VC中,應(yīng)用程序是以Project的形式存在的,Project文件以.dsp擴(kuò)展名,在Workspace文件中可以包含多個Project,由Workspace文件對它們進(jìn)行統(tǒng)一的協(xié)調(diào)和管理。與dsw類型的Workspace文件相配合的一個重要的文件類型是以opt為擴(kuò)展名的文件,這個文件中包含的是在Workspace文件中要用到的本地計(jì)算機(jī)的有關(guān)配置信息,所以這個文件不能在不同的計(jì)算機(jī)上共享,當(dāng)我們打開一個Workspace文件時,如果系統(tǒng)找不到需要的。pt類型文件,就會自動地創(chuàng)建一個與之配合的包含本地計(jì)算機(jī)信息的opt文件。上面提到Project文件的擴(kuò)展名是dsp,這個文件中存放的是一個特定的工程,也就是特定的應(yīng)用程序的有關(guān)信息,每個工程都對應(yīng)有一個dsp類型的文件。以clw為擴(kuò)展名的文件是用來存放應(yīng)用程序中用到的類和資源的信息的,這些信息是VC中的Classwizard工具管理和使用類的信息來源。對應(yīng)每個應(yīng)用程序有一個readme.txt文件,這個文件中列出了應(yīng)用程序中用到的所有的文件的信息,打開并查看其中的內(nèi)容就可以對應(yīng)用程序的文件結(jié)構(gòu)有一個基本的認(rèn)識。在應(yīng)用程序中大量應(yīng)用的是以h和cpp為擴(kuò)展名的文件,以h為擴(kuò)展名的文件稱為頭文件。以cpp為擴(kuò)展名的文件稱為實(shí)現(xiàn)文件,一般說來h為擴(kuò)展名的文件與cpp為擴(kuò)展名的文件是一一對應(yīng)配合使用的,在h為擴(kuò)展名的文件中包含的主要是類的定義,而在cpp為擴(kuò)展名的文件中包含的主要是類成員函數(shù)的實(shí)現(xiàn)代碼。在應(yīng)用程序中經(jīng)常要使用一些位圖、菜單之類的資源,VC中以rc為擴(kuò)展名的文件稱為資源文件,其中包含了應(yīng)用程序中用到的所有的windows資源,要指出的?點(diǎn)是rc文件可以直接在VC集成環(huán)境中以可視化的方法進(jìn)行編輯和修改。最后要介紹的是以rc2為擴(kuò)展名的文件,它也是資源文件,但這個文件中的資源不能在VC的集成環(huán)境下直接進(jìn)行編輯和修改,而是由我們自己根據(jù)需要手工地編輯這個文件。對于以ico.bmp等為擴(kuò)展名的文件是具體的資源,產(chǎn)生這種資源的途徑很多。使用rc資源文件的目的就是為了對程序中用到的大量的資源進(jìn)行統(tǒng)的管理。2MFC編程特點(diǎn)如果你曾經(jīng)使用過傳統(tǒng)的windows編程方法開發(fā)應(yīng)用程序,你會深刻地體會到,即使是開發(fā)一個簡單的windows應(yīng)用程序也需要對windows的編程原理有很深刻的認(rèn)識,同時也要手工編寫很多的代碼。因?yàn)槌绦虻某鲥e率幾乎是隨著代碼長度的增加呈幾何級數(shù)增長的,這就使得調(diào)試程序變得非常困難。所以傳統(tǒng)的windows編程是需要極大的耐心和豐富的編程經(jīng)驗(yàn)的。近幾年來,面向?qū)ο蠹夹g(shù)無論是在理論還是實(shí)踐上都在飛速地發(fā)展。面向?qū)ο蠹夹g(shù)中最重要的就是“對象”的概念,它把現(xiàn)實(shí)世界中的氣球、自行車等客觀實(shí)體抽象成程序中的“對象”。這種“對象”具有一定的屬性和方法,這里的屬性指對象本身的各種特性參數(shù)。如氣球的體積,自行車的長度等,而方法是指對象本身所能執(zhí)行的功能,如氣球能飛,自行車能滾動等。一個具體的對?象可以有許多的屬性和方法,面向?qū)ο蠹夹g(shù)的重要特點(diǎn)就是對象的封裝性,對于外界而言,并不需要知道對象有哪些屬性,也不需要知道對象本身的方法是如何實(shí)現(xiàn)的,而只需要調(diào)用對象所提供的方法來完成特定的功能。從這里我們可以看出,當(dāng)把面向時象技術(shù)應(yīng)用到程序設(shè)計(jì)中時,程序員只是在編寫對象方法時才需要關(guān)心對象本身的細(xì)節(jié)問題,大部分的時間是放在對對象的方法的調(diào)用上,組織這些對象進(jìn)行協(xié)同工作。MFC的英文全稱是MicrosoftFundationClasses,即微軟的基本類庫,MFC的本質(zhì)就是一個包含了許多微軟公司已經(jīng)定義好的對象的類庫,我們知道,雖然我們要編寫的程序在功能上是千差萬別的,但從本質(zhì)上來講,都可以化歸為用戶界面的設(shè)計(jì),對文件的操作,多媒體的使用,數(shù)據(jù)庫的訪問等等一些最主要的方面。這一點(diǎn)正是微軟提供MFC類庫最重要的原因,在這個類庫中包含了一百多個程序開發(fā)過程中最常用到的對象。在進(jìn)行程序設(shè)計(jì)的時候,如果類庫中的某個對象能完成所需要的功能,這時我們只要簡單地調(diào)用已有對象的方法就可以了。我們還可以利用面向?qū)ο蠹夹g(shù)中很重要的“繼承”方法從類庫中的已有對象派生出我們自己的對象,這時派生出來的對象除了具有類庫中的對象的特性和功能之外,還可以由我們自己根據(jù)需要加上所需的特性和方法,產(chǎn)生一個更專門的,功能更為強(qiáng)大的對象。當(dāng)然,你也可以在程序中創(chuàng)建全新的對象,并根據(jù)需要不斷完善對象的功能。正是由于MFC編程方法充分利用了面向?qū)ο蠹夹g(shù)的優(yōu)點(diǎn),它使得我們編程時極少需要關(guān)心對象方法的實(shí)現(xiàn)細(xì)節(jié),同時類庫中的各種對象的強(qiáng)大功能足以完成我們程序中的絕大部分所需功能,這使得應(yīng)用程序中程序員所需要編寫的代碼大為減少,有力地保證了程序的良好的可調(diào)試性。最后要指出的是MFC類庫在提供的對象的各種屬性和方法都是經(jīng)過謹(jǐn)慎的編寫和嚴(yán)格的測試,可靠性很高,這就保證了使用MFC類庫不會影響程序的可靠性和正確性。3使用WizardVisualC++是一種功能強(qiáng)大的通用程序設(shè)計(jì)語言,它提供了各種向?qū)Ш凸ぞ邘椭覀儊韺?shí)現(xiàn)所需的功能,在一定程度上實(shí)現(xiàn)了軟件的自動生成和可視化編程。下面就為你介紹VC集成環(huán)境中幾個最主要的開發(fā)工具的使用方法。首先要介紹的是Appwizard工具,這個工具的作用是幫助我們一步步地生成一個新的應(yīng)用程序,并且自動生成應(yīng)用程序所需的基本代碼。下面我們就介紹使用Appwizard生成一個應(yīng)用程序的具體步驟。?單擊File菜單New菜單項(xiàng),系統(tǒng)彈出的對話讓我們選擇所要創(chuàng)建的文件類型,這里的文件分成了Files,Project,Workspaces,Otherdocuments四種大類型,每一個類型下面又包含許多具體的文件類型,選中Projects標(biāo)簽,標(biāo)簽下的工作區(qū)中列出的是各種不同的應(yīng)用程序類型,比如dll類型的動態(tài)鏈接庫,exe類型的可執(zhí)行程序等,這里選中MFCAppwizard(exe)選項(xiàng),表示要創(chuàng)建的是一個使用MFC基本類庫進(jìn)行編程的可執(zhí)行程序。如下圖1.1所示:圖1.1?選好后在projectname-欄中為程序起一個名字為test,在location-欄中為程序定義文件存放的目錄,對話框右下角的platforms一欄中的Win32項(xiàng)表示要創(chuàng)建的程序是建立在32位的windows平臺基礎(chǔ)上。單擊0K按鈕,就啟動了使用MFC方式開發(fā)應(yīng)用程序的Appwizard功能。圖1.2?Wizard讓我們選擇程序的類型和程序中的資源所用的語種,這里不妨選擇程序類型為單文檔界面,語種為英語,然后單擊NEXT按鈕。圖1.3圖1.4Wizard讓我們選擇是否需要提供數(shù)據(jù)庫方面的支持,這里選擇NONE,然后單擊NEXT按鈕。?下面選擇程序中對復(fù)合文檔的支持,這里選擇NONE。圖1.5?接者選擇程序的其它一些特性,如提供對WINSOCK的支持等。這里對系統(tǒng)的缺省值不作改變,如下圖1.6所示。單擊NEXT按鈕。圖1.6?在第五步中,對話框上部選擇是否為程序自動生成注釋,對話框的下部用來選擇使用MFC類庫的方式是動態(tài)鏈接庫方式還是靜態(tài)鏈接方式,使用動態(tài)鏈接庫方式時在以后生成的可執(zhí)行應(yīng)用程序中并不真正包含MFC類庫中的對象,而使用靜態(tài)鏈接方式時,則把MFC庫中的代碼生成為應(yīng)用程序的?部分,這時生成的應(yīng)用程序也就相對大一些。選好后單擊NEXT按鈕。圖1.7?進(jìn)入APPWIZARD的最后一個步驟,對話框中的提示信息指明了系統(tǒng)將要自動創(chuàng)建的對象和相關(guān)文件,以及派生出這些對象的MFC的基類等內(nèi)容。在這一步當(dāng)中,我們還可以對視圖類的基類進(jìn)行選擇,單擊FINISH按鈕。圖1.8?游覽一下對話框中對將要生成的程序的有關(guān)信息的描述后單擊0K按鈕。系統(tǒng)就自動為我們生成?個使用MFC基本類庫的應(yīng)用程序的基本框架,在以后將會對這個框架的內(nèi)容作詳細(xì)的介紹。 I接下來介紹VC集成環(huán)境中提供的一個很重要的工具CLASSWIZARD,它主要是用來管理程序中的對象和消息的,這個工具對于MFC編程顯得尤為重要。單擊VIEW菜單的CLASSWIZARD項(xiàng),就可以運(yùn)行MFCCLASSWIZARD,在這個對話框中就可以對程序中的對象和消息進(jìn)行管理了。圖1.10在對話框中的MESSAGEMAPS標(biāo)簽下,PROJECT欄中的內(nèi)容代表當(dāng)前程序的名字。CLASSWNAME下拉列表框列出的就是程序當(dāng)前用到的所有類的名字,在MESSAGE一欄中列出的就是一個選中的類所能接收到的所有的消息,在WINDOWS程序設(shè)計(jì)中,消息是個極為重要的概念,用戶通過窗口界面的各種操作最后都轉(zhuǎn)化為發(fā)送到程序中的對象的各種消息、,卜面就向您介紹在WlNDOWS程序設(shè)計(jì)中最常用的一些消息:窗口消息:WM_CREATE,WM_DESTROY,WM_CLOSE我們創(chuàng)建一個窗口對象的時候,這個窗口對象在創(chuàng)建過程中收到的就是WM_CREATE消息,對這個消息的處理過程一般用來設(shè)置一些顯示窗口前的初始化工作,如設(shè)置窗口的大小,背景顏色等,WM_DESTROY消息指示窗口即將要被撤消,在這個消息處理過程中,我們就可以做窗口撤消前的一些工作。WM_CLOSEwm_close消息發(fā)生在窗口將要被關(guān)閉之前,在收到這個消息后,一般性的操作是回收所有分配給這個窗口的各種資源。在windows系統(tǒng)中資源是很有限的,所以回收資源的工作還是非常重要的。鍵盤消息:WM_CHAR,WM_KEYDOWN,WM_KEYUP這三個消息用來處理用戶的鍵盤數(shù)據(jù),當(dāng)用戶在鍵盤上按下某個鍵的時候,會產(chǎn)生WM_KEYDOWN消息,釋放按鍵的時候又回產(chǎn)生WM_KEYUP消息,所以WM_KEYDOWN與WM_KEYUP消息一般總是成對出現(xiàn)的,至于WM_CHAR消息是在用戶的鍵盤輸入能產(chǎn)生有效的ASCII碼時才會發(fā)生。這里特別提醒要注意前兩個消息與WM_CHAR消息在使用上是有區(qū)別的。在前兩個消息中,伴隨消息傳遞的是按鍵的虛擬健碼,所以這兩個消息可以處理非打印字符,如方向鍵,功能鍵等。而伴隨WM_CHAR消息的參數(shù)是所按的鍵的ASCII碼,ASCII碼是可以區(qū)分字母的大小寫的。而虛擬鍵碼是不能區(qū)分大小寫的。鼠標(biāo)消息:WM_MOUSEMOVE,WM_LBUTTONDOWN,WM_LBUTTONUP,WM_LBUTTONDBCLICK,WM_RBUTTONDOWN,WM_RBUTTONUP,WM_RBUTTONDBCLICK這組消息是與鼠標(biāo)輸入相關(guān)的,WM_MOUSEMOVE消息發(fā)生在鼠標(biāo)移動的時候,剩余的六個消息則分別對應(yīng)于鼠標(biāo)左右鍵的按下、釋放、雙擊事件,要指出的是WINDOWS系統(tǒng)并不是在鼠標(biāo)每移動一個像素時都產(chǎn)生MOUSEMOVE消息,這一點(diǎn)要特別注意。另一組窗口消息:WM_MOVE,WM_SIZE,WM_PAINT當(dāng)窗口移動的時候產(chǎn)生WM_MOVE消息,窗口的大小改變的時候產(chǎn)生WM_SIZE消息,而當(dāng)窗口工作區(qū)中的內(nèi)容需要重畫的時候就會產(chǎn)生WM_PAINT消息。焦點(diǎn)消息WM_SETFOCUS,WM_KILLFOCUS當(dāng)一個窗口從非活動狀態(tài)變?yōu)榫哂休斎虢裹c(diǎn)的活動狀態(tài)的時候,它就會收到WM_SETFOCUS消息,而當(dāng)窗口失去輸入焦點(diǎn)的時候它就會收到WM_KILLFOCUS消息。6定時器消息:WM_TIMER當(dāng)我們?yōu)橐粋€窗口設(shè)置了定時器資源之后,系統(tǒng)就會按規(guī)定的時間間隔向窗口發(fā)送WM_TIMER消息,在這個消息中就可以處理一些需要定期處理的事情。最后要指出的一點(diǎn)是,在WINDOWS環(huán)境F,消息的來源是多方面的,最常見的是用戶的操作產(chǎn)生消息,系統(tǒng)在必要的時候也會向程序發(fā)送系統(tǒng)消息,其他在運(yùn)行中的程序也可以向程序發(fā)送消息。此外,在程序的內(nèi)部,也可以根據(jù)需要在適當(dāng)?shù)臅r候主動產(chǎn)生消息,比如主動產(chǎn)生WM_PAINT消息以實(shí)現(xiàn)需要的重畫功能。上面介紹了MESSAGE欄中主要的消息,在MEMBERFUNCTION?欄中列出的是目前被選中的類已經(jīng)有的成員函數(shù)。這些成員函數(shù)一般說來是與這個類可以接收的消息一一對應(yīng)的。也就是說,一個成員函數(shù)?般總是用來處理某個特定的消息。如果在MESSAGE欄中的某個消息在程序中需要處理,但FT前還沒有相應(yīng)的類成員函數(shù),比如這里選中WM_TIMER這個消息,它目前還沒有相應(yīng)的對應(yīng)的類的成員函數(shù),單擊ADDFUNCTION按鈕,系統(tǒng)就自動為WM_TIMER消息在類中添加了對應(yīng)的成員函數(shù)ONTIMER,單擊EDITCODE按鈕,可以發(fā)現(xiàn)系統(tǒng)已經(jīng)自動生成了完成ONTIMER函數(shù)所需的基本代碼,我們只要在這些基本代碼的基礎(chǔ)上再添加所需要的代碼就可以了。注意對話框中的ADDCLASS按鈕,它用來往當(dāng)前應(yīng)用程序中添加一個新的類。單擊后選中NEW菜單,圖1.12 I系統(tǒng)彈出了NEWCLASS對話框用于生成一個新的類。在這個對話框中需要為類起個名字,設(shè)置類文件的名字,另外還要在BASECLASS一欄的下拉列表框中選擇某個已有的類作為基類,設(shè)好需要的信息后單擊0K就生成了一個新的類。圖1.13CLASSWIZARD還有一些很強(qiáng)大的功能,這里就不再詳細(xì)介紹,你會在不斷的學(xué)習(xí)中慢慢地了解和掌握。最后介紹一下集成環(huán)境提供的一個重要工具RESOUCREDITOR,也就是資源編輯器。在VC開發(fā)的應(yīng)用程序中要用到大量的位圖,菜單,工具條,對話框等各種資源。這些資源對于程序而言是相對獨(dú)立的,所以可以對它們進(jìn)行單獨(dú)的編輯,然后使用在程序中。而RESOUCEEDITOR正是為編輯資源提供了一種可視化的開發(fā)方法。極大地減輕了程序員的負(fù)擔(dān)。單擊FlLE菜單的OPEN菜單項(xiàng),然后在對話框中選擇打開TEST.RC文件,就可以開始使用資源編輯器了。在左邊的工作區(qū)中按類型列出了程序中用到的所有的資源,雙擊其中的某個類型,比如雙擊MENU資源,MENU目錄的下面列出的就是系統(tǒng)已經(jīng)有的MENU類型的資源,選中其中一個并雙擊,在右邊的工作區(qū)中列出了這個資源當(dāng)前的樣子,我們就可以在工作區(qū)中對資源進(jìn)行可視化的編輯和修改了。

圖1.14圖115如何添加一個資源呢?單擊INSERT菜單,選中RESOURCE菜單項(xiàng),系統(tǒng)彈出INSERTRESOURCE圖115在圖1.15這個對話框,在這個對話框中選中一種資源類型,比如選擇CURSOR類型,然后單擊NEW按鈕。在左邊的工作區(qū)中就出現(xiàn)了我們新生成的資源的標(biāo)識符,雙擊這個標(biāo)識符,在右邊的工作區(qū)中就可以對這個新的指針形狀資源進(jìn)行可視化編輯了。如圖1.16。通過這部分內(nèi)容的介紹,相信您已經(jīng)對使用VISUALC++開發(fā)MFC應(yīng)用程序的圖1.16基本步驟有了認(rèn)識。在下一章的內(nèi)容當(dāng)中,我們將結(jié)合WINDOWS的工作原理,詳細(xì)地向您解釋MFC類庫的基本結(jié)構(gòu),以及MFC應(yīng)用程序的基本框架——文檔/視圖結(jié)構(gòu).MFC程序結(jié)構(gòu)分析1WlNDOWS程序工作原理WINDOWS程序設(shè)計(jì)是一種完全不同于傳統(tǒng)的DOS方式的程序設(shè)計(jì)方法,它是一種事件驅(qū)動方式的程序設(shè)計(jì)模式。在程序提供給用戶的界面中有許多可操作的可視對象。用戶從所有可能的操作中任意選擇,被選擇的操作會產(chǎn)生某些特定的事件,這些事件發(fā)生后的結(jié)果是向程序中的某的對象發(fā)出消息,然后這四對象調(diào)用相應(yīng)的消息處理函數(shù)來完成特定的操作。WINDOWS應(yīng)用程序最大的特點(diǎn)就是程序沒有固定的流程,而只是針對某個事件的處理有特定的子流程,WlNDOWS應(yīng)用程序就是由許多這樣的子流程構(gòu)成的。從上面的討論中可以看出,WINDOWS應(yīng)用程序在本質(zhì)上是面向?qū)ο蟮摹3绦蛱峁┙o用戶界面的可視對象在程序的內(nèi)部?般也是一個對象,用戶對可視對象的操作通過事件驅(qū)動模式觸發(fā)相應(yīng)對象的可用方法。程序的運(yùn)行過程就是用戶的外部操作不斷產(chǎn)生事件,這些事件又被相應(yīng)的對象處理的過程。下面是WINDOWS程序工作原理的示意圖。2建立應(yīng)用程序在介紹AppWizard的時候,我們已經(jīng)建立了一個名字為TEST的工程,事實(shí)上這個框架程序已經(jīng)可以編譯運(yùn)行了。在BUILD菜單中選擇REBUILDALL菜單項(xiàng),系統(tǒng)開始編譯由APPWIZARD自動生成的程序框架中所有文件中的源代碼,并且鏈接生成可執(zhí)行的應(yīng)用程序。在BUILD菜單中選擇EXECUTE菜單項(xiàng),應(yīng)用程序就開始開始運(yùn)行了,雖然我們沒有編寫一行代碼,但是可以看出由系統(tǒng)自動生成的應(yīng)用程序的界面已經(jīng)有了一個標(biāo)準(zhǔn)WINDOWS應(yīng)用程序所需的幾個組成部分,我們要做的事情是往這個應(yīng)用程序添加必要的代碼以完成我們所需要的功能。接下來將要對WINDOWS自動生成的這個應(yīng)用程序框架作詳細(xì)的介紹,讓你時MFC方式的WINDOWS應(yīng)用程序的工作原理有全面的認(rèn)識,只有這樣你才會知道應(yīng)該如何往程序框架當(dāng)中添加需要的代碼。 I圖2.13程序結(jié)構(gòu)剖析為了讓您對MFC方式的程序的框架有一個總體的認(rèn)識,這里設(shè)計(jì)了一個表示程序中的主要類之間的關(guān)系的圖表:這個圖表表示了使用MFC方式的應(yīng)用程序的四個主要類之間的關(guān)系,從中可以看出,CMYAPP類主要的作用是用來處理消息的,它統(tǒng)一管理程序收到的所有的消息,然后把消息分配到相應(yīng)的對象。CMAINFRAME是CMYVIEW的父類,也就是說視窗VIEW顯示在主框窗MAINFRAME的客戶區(qū)中。類CMYVIEW的作用是顯示數(shù)據(jù),而數(shù)據(jù)的來源是類CMYDOC,在MFC程序中,程序的數(shù)據(jù)是放在文檔當(dāng)中的,而顯示數(shù)據(jù)則是利用視窗方式,文檔與視窗分離帶來的好處就是一個文檔可以同時具有多個視窗,每個視窗只顯示文檔中的一部分?jǐn)?shù)據(jù),或者以特定的風(fēng)格顯示文檔中的數(shù)據(jù)。文檔與視窗分離的另一個好處就是在程序中可以處理多個文檔,通過對不同的視窗的處理達(dá)到對不同的文檔分別處理的目的。使用過傳統(tǒng)的WINDOWS編程方法的人都知道,在應(yīng)用程序中有一個重要的函數(shù)WINMAIN(),這個函數(shù)是應(yīng)用程序的基礎(chǔ),用戶的操作所產(chǎn)生的消息正是經(jīng)過這個函數(shù)的處理派送到對應(yīng)的對象中進(jìn)行處理。在MFC方式的WINDOWS應(yīng)用程序中,用來處理消息的是系統(tǒng)自動生成的MFC中的類CWINAPP的派生類CMYAPP,下面就從這個類開始介紹應(yīng)用程序的框架。3.1類CMYAPP類CMYAPP是應(yīng)用程序運(yùn)行的基礎(chǔ),注意這一行代碼,可以看出這個類是由MFC中的類CWINAPP派生來的。在這個類中除了有般類都有的構(gòu)造函數(shù),一個重要的成員函數(shù)就是INITINSTANCE,我們知道,在WlNDOWS環(huán)境卜.面可以運(yùn)行同一程序的多個實(shí)例,函數(shù)INITINSTANCE的作用就是在生成的一個新的實(shí)例的時候,完成一些初始化的工作。注意這一行代碼,它的作用就是生成一個CMYAPP類型的時象,生成的時候系統(tǒng)會主動調(diào)用INITINSTANCE函數(shù)完成一些必要的初始化工作。下面研究INITINSTANCE函數(shù)所做的事情,注意這一行代碼,它定義了一個文檔模板對象指針PDOCTEMPLATE,通過NEW操作符,系統(tǒng)動態(tài)生成了這個文檔模板對象,然后使用ADDDOCTEMPLATE函數(shù)把這個文檔模板對象加入到應(yīng)用程序所維護(hù)的文檔模板鏈表當(dāng)中,這個文檔模板PDOCTEMPLATE的作用就是把程序用到的框架窗口,CMAINFRAME,文檔CMYDOC,視窗CMYVIEW與應(yīng)用對象CMYAPP聯(lián)系起來。CMYAPP類提供了用戶與WINDOWS應(yīng)用程序之間進(jìn)行交流的界面。在生成這個類的對象后,這個對象白動地把自身與WINDOWS系統(tǒng)建立聯(lián)系,接收WINDOWS傳送的消息,并交給程序中相應(yīng)的對象去處理,這就免去了程序員許多的工作,使得開發(fā)C++的WINDOWS程序變得簡單方便。3.2類CMAINFRAME類CMAINFRAME是由MFC中的CFRAMEWND派生來的,所以它也是一個框架窗口。前面已經(jīng)指出,CMAINFRAME是類CMYVIEW的父類,也就是說CMYVIEW類的對象顯示在主框架窗口的客戶區(qū)中。在類CMAINFRAME中,系統(tǒng)已經(jīng)從類CFRAMEWND那里繼承了處理窗口的一般事件的WINDOWS消息,比如改變窗口的大小,窗口最小化等等的成員函數(shù),因此編程的時候程序員不需要再關(guān)心此類消息的處理,從而減輕了程序員的負(fù)擔(dān)。當(dāng)然,如果確實(shí)需要重新編寫處理此類消息的成員函數(shù),則需要對原有的成員函數(shù)進(jìn)行重載。在MFC程序中,我們并不需要經(jīng)常對CMAINFRAME類進(jìn)行操作,更多的是對視窗類進(jìn)行操作,達(dá)到對程序中的數(shù)據(jù)進(jìn)行編輯和修改的目的。最后要指出的是,在MFC方式的程序中,當(dāng)程序的一個實(shí)例被運(yùn)行的時候,系統(tǒng)根據(jù)前面在CMYAPP類中介紹的文檔模板對象自動生成類CMAINFRAME,CMYVIEW,CMYDOC的對象,而不需要程序員主動地去創(chuàng)建這些類的對象。3.3類CMyView與CMyDoc之所以把CMyView類和CMyDoc類一起介紹是因?yàn)檫@兩個類是密切相關(guān)的,下面的框圖可以說明文檔與視窗的關(guān)系。在這個框圖當(dāng)中,文檔是由文檔模板對象生成的,并由應(yīng)用程序?qū)ο蠊芾?,而用戶則是通過與文檔相聯(lián)系的視窗對象來存儲、管理應(yīng)用程序的數(shù)據(jù),用戶與文檔之間的交互則是通過與文檔相關(guān)聯(lián)的視窗對象來進(jìn)行的。生成一個新的文檔的時候,MFC程序同時生成?個框架窗口,并且在框架窗口的客戶區(qū)中生成一個視窗對象作為框架窗口的子窗口,這個子窗口以可視化的方式表現(xiàn)文檔中的內(nèi)容。視窗的重要功能就是負(fù)責(zé)處理用戶的鼠標(biāo)、鍵盤等操作,通過對視窗對象的處理達(dá)到處理文檔對象的目的。要指出的一點(diǎn)是,WINDOWS應(yīng)用程序分單文檔界面SDI和多文檔界面MDI兩種,在單文檔界面中,文檔窗口與主框架窗口是同一概念。而這時的視窗對象則是顯示在文檔窗口的客戶區(qū)當(dāng)中。我們先前生成的TEST程序使用的就是單文檔界面方式,此時文檔窗口是主框架窗口,即類CMAINFRAME的對象。下面將以一個例子來說明這兩個類之間的關(guān)系。前面已經(jīng)提到,文檔類是用來存放程序中的數(shù)據(jù)的,所以我們首先在文檔類CMyDoc中加入一個成員變量用來存放數(shù)據(jù)。在左邊的工作區(qū)用右鍵單擊CMyDoc選項(xiàng),在彈出的菜單中選中Addmembervariable菜單項(xiàng)。圖2.2系統(tǒng)彈出AddMemberVariable對話框。VariableType一欄用來輸入成員變量的類型。這里設(shè)置為CString,即字符串類型,VariableDeclaration--欄用來輸入變量的名字,這里不妨輸入為mystring,Access組合框用來設(shè)置成員變量的訪問權(quán)限,缺省為Public,設(shè)好后單擊OK按鈕關(guān)閉對話框。如下圖2.3所示:圖2.3這時,如果打開類CMyDoc的頭文件、可以發(fā)現(xiàn)其中已經(jīng)自動加入了我們定義的公有變量mystring。這個變量就可以作為我們的文檔類的數(shù)據(jù)存儲空間,因?yàn)閙ystring是公有成員,它就可以被文檔對應(yīng)的視窗所處理了。在VIEW菜單中選擇ClassWizard菜單項(xiàng),系統(tǒng)打開MFCClassWizard對話框,接下來我們要為視窗類添加處理鍵盤事件的成員函數(shù)。在Classname一欄中選中類CMyView,然后在messages一欄中選中消息wm_char,單擊addfunction按鈕,系統(tǒng)就自動往CMyView類中添加了處理wm_char消息的成員函數(shù)的框架。單擊editcode按鈕,接下來對OnChar這個成員函數(shù)進(jìn)行編輯和修改??梢钥闯鱿到y(tǒng)已經(jīng)自動在這個成員函數(shù)中添加了CMyView的基類CView的WM_CHAR消息的處理函數(shù)。注意這一行代碼:BEGIN_MESSAGE_MAP(CMyView,CView)//{{AFX_MSG_MAP(CMyView)ON_WM_CHAR()ON_WM_LBUTTONDOWN()ON_WM_CANCELMODE()//\}AFX_MSG_MAP//StandardprintingcomiuandsON_COMMAND(ID_FILE_PRINTZCView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT,CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEWZCView::OnFilePrintPreview)END_MESSAGE_MAP()它被放在mfc的消息映射宏BEGIN_MESSAGE_MAP中,它的作用就是把windows系統(tǒng)發(fā)來的WM_CHAR消息連接到CMyView類的成員函數(shù)OnChar上,即把這個成員函數(shù)作為處理WM_CHAR消息的過程。接下來我們就往這個成員函數(shù)中添加處理WM_CHAR消息的具體代碼。首先在OnChar函數(shù)中添加如下的代碼:voidCMyView::OnChar(UINTnChar,UINTnRepCnt,UINTnFlags)//TODO:Addyourmessagehandlercodehereand/orcalldefaultCMyDoc*pdoc;pdoc=GetDocument();這段代碼的作用是首先定義個指向文檔類對象的指針pdoc,然后利用CMyView類的成員函數(shù)getdocument()獲取指向當(dāng)前視窗類所對應(yīng)的文檔類對象的指針,并把這個指針賦給定義的文檔類型指針pdoc,這樣我們在后面就可以用“pdoc_>mystring”的方式訪問文檔類中定義的公有數(shù)據(jù)成員mystring了。接著往函數(shù)OnChar中添加如卜的代碼:pdoc_>mystring=nChar;CClientDCmydc(this);mydc.TextOut(0,0,pdoc_>mystring,pdoc_>mystring.GetLength());這段代碼中的第一行代碼的作用是根據(jù)從消息WM_CHAR中傳來的參數(shù)nchar,也就是鍵盤中輸入的字符的ASCII碼,把輸入的字符添加到文檔中的字符串對象mystring中。在介紹第二行代碼前要先介紹設(shè)備描述表的概念。設(shè)備描述表也稱為設(shè)備上下文,在windows環(huán)境中,當(dāng)需要對一個對象,如打印機(jī),屏幕,窗口等進(jìn)行輸出時,就必須先獲取這個對象的設(shè)備描述表,然后通過這個設(shè)備描述表來進(jìn)行輸出。使用設(shè)備描述表帶來的最大的好處就是輸出格式的一致性,因?yàn)檩敵霾辉偈侵苯俞槍唧w的設(shè)備,而是通過統(tǒng)一格式的設(shè)備描述表間接地實(shí)現(xiàn)。第二行代碼的作用就是定義并生成了一個當(dāng)前視窗的客戶區(qū)的設(shè)備描述表對象MYDC,其中的參數(shù)THIS是面向?qū)ο笳Z言中的一個重要的關(guān)鍵字。指代成員函數(shù)所在類的對象的指針。在生成了視窗的客戶區(qū)的設(shè)備描述表MYDC之后,我們可以利用它在視窗的客戶區(qū)中輸出數(shù)據(jù)了。這段代碼的第三行就是調(diào)用設(shè)備描述表MYDC的方法TEXTOUT,在視窗的客戶區(qū)中輸出文檔中的字符串MYSTRINGT.我們在前面曾經(jīng)指出,一個文檔可以對應(yīng)多個視窗。如果用戶通過某個視窗更改了文檔中的數(shù)據(jù),就比如上面的代碼當(dāng)中,我們通過視窗CMYWIVE更改了文檔中的字符串對象MYSTRING,那么系統(tǒng)又如何維護(hù)同一文檔的不同的視窗顯示的數(shù)據(jù)的一致性呢?我們接著在。nChar函數(shù)中輸入如下的代碼:pdoc_>UpdateAlIViews(this,0L,0);這行代碼的作用就是通知本視窗所在的文檔的所有其他的視窗,文檔中的數(shù)據(jù)已經(jīng)更新,這些視窗應(yīng)該重新從文檔中取回?cái)?shù)據(jù)用來顯示,這樣就維持了同一文檔的所有視窗的數(shù)據(jù)的一致性。這一行是視窗類中對文檔的數(shù)據(jù)作了修改以后需要加的一條典型語句。接下來運(yùn)行這個程序,在BUILD菜單中選擇REBUILDALL菜單項(xiàng)來編譯連接應(yīng)用程序,然后單擊BUILD菜單的EXECUTE菜單項(xiàng)運(yùn)行程序,從鍵盤I.輸入一些字符,可以發(fā)現(xiàn)這些字符顯示在視窗也就是主窗口的客戶區(qū)當(dāng)中。而這些字符的實(shí)際位置是存放在文檔對象的成員變量MYSTRING這個字符串中。改變一下窗口的大小,可以發(fā)現(xiàn)顯示的數(shù)據(jù)都沒有了,這是因?yàn)槲覀冊诖翱诔叽绺淖兊臅r候沒有把數(shù)據(jù)重新輸出到窗口的客戶區(qū)中。關(guān)閉應(yīng)用程序,找到CMyView類的成員函數(shù)ONDRAW,在其中添加如下的代碼:voidCMyView::OnDraw(CDC*pDC)CMyDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);//TODO:adddrawcodefornativedataherepDC_>TextOut(0,0,pDoc_>mystring);當(dāng)窗口的大小改變的時候,應(yīng)用程序會調(diào)用ONDRAW這個函數(shù),我們添加的這行代碼的作用就是把字符串對象MYSTRING重新顯示在窗口的客戶區(qū)當(dāng)中,這樣在窗口大小改變的時候,數(shù)據(jù)依然顯示在窗口客戶區(qū)中。再次編譯運(yùn)行這個程序,可以發(fā)現(xiàn)窗口大小的改變不再影響數(shù)據(jù)的顯示了。在前面的內(nèi)容當(dāng)中,我們已經(jīng)介紹了使用MFC編制程序的基本結(jié)構(gòu)。MFC的內(nèi)容非常豐富,下面我們將針對軟件的基本任務(wù):接受用戶輸入、處理程序輸出、進(jìn)行文件處理以及數(shù)據(jù)庫訪問技術(shù),向您介紹如何使用MFC編寫程序,實(shí)現(xiàn)這些基本的功能。三深入MFC類庫1處理用戶輸入程序從用戶那里得到數(shù)據(jù),經(jīng)過自己的處理,再把計(jì)算的結(jié)果輸出到屏暮、打印機(jī)或者其他的輸出設(shè)備上,這是軟件工作的基本模型。消息和鍵盤消息是最基本的輸入信息,除此之外,MFC封裝了一系列的使用戶可以進(jìn)行可視化的輸入的界面對象,比方說對話框以及可以布置在上面的編輯框、按鈕、列表控件、樹形控件等等。使程序支持用戶輸入的手段更加豐富。圖3.11定義對話框資源卜面我們通過一個例子來介紹如何設(shè)計(jì)一個基于對話框的界面,接受用戶輸入的數(shù)據(jù),并且將它們以圖形化的方式顯示出來。我們將制作這樣的一個有用的程序。它訪問一個保存歌曲曲目的數(shù)據(jù)庫,用戶可以通過對話框讓用戶定義一個曲目表,并選定一張背景圖,然后在一個沒有系統(tǒng)菜單的窗口客戶區(qū)上滾動顯示曲目的名字。在許多的娛樂場所的大屏幕上我們都可以看到類似的東西。在這部分的內(nèi)容當(dāng)中,我們著重介紹如何獲得和處理用戶輸入數(shù)據(jù)的工作,在后面的處理用戶輸出的內(nèi)容當(dāng)中,我們還將使用這個例子來說明如何在屏幕上進(jìn)行輸出工作。下面我們來介紹如何定義一個對話框資源。在WORKSPACE窗口當(dāng)中RESOURCE一頁,在DIALOG小圖標(biāo)上面單擊鼠標(biāo)右鍵,彈出菜單,選擇INSERT命令,如圖3.2所示:圖3.2接下來在彈出的資源類型對話框中選擇DIALOG,表示添加一個對話框資源。單擊NEW按鈕。圖3.3接下來我們就開始布置這個對話框。對話框上面已經(jīng)有了兩個按鈕:0K和CANCEL。如下圖3.4所示。它們的作用分別是確認(rèn)用戶通過對話框進(jìn)行的輸入和取消前面的輸入工作。把它們的標(biāo)題分別改為確定和取消。布置其它的控件。每一個對話框以及對話框上面的每一個控件都有一個ID號碼,它們的定義包括在RESOURCE用這個頭文件當(dāng)中。比方說,這個對話框的ID號是IDD_DIALOG2,確認(rèn)按鈕的ID號是IDOK,取消按鈕的ID號是IDCANCEL,MFC將通過ID號來訪問這些資源。單擊DIALOG工具條上面的TEST按鈕可以測試對話框運(yùn)行的效果。需要注意的是我們這里我們定義的對話框只是一個資源,如果要使這個對話框真正實(shí)現(xiàn)它的功能,必須在程序當(dāng)中定義一個使用這個資源的對話框類。圖3.41.2定義對話框類下面我們就定義一個對話框類。在VIEW菜單當(dāng)中選擇CLASSWIZARD命令,單擊ADDCLASS按鈕,在彈出的菜單當(dāng)中選擇NEW命令,在NAME一欄當(dāng)中輸入新類的名字,在BASECLASS列表框當(dāng)中選擇需要繼承MFC當(dāng)中的哪一個類。在DIALOGID列表框當(dāng)中選擇對話框資源的ID號碼,在這個實(shí)例當(dāng)中,我們不使用OLEAUTOMATION,所以在這個組框當(dāng)中選擇NONE。在FILENAME一欄顯示的是這個類的定義寫在哪一個文件當(dāng)中。圖3.5單擊圖3.5中所示CHANGE按鈕,在HEADERFILE和IMPLEMENTATIONFILE當(dāng)中分別敲入新類的聲明和定義分別寫在哪個文件當(dāng)中,單擊0K按鈕確認(rèn),這樣我們就完成了對新的對話框類的定義。單擊0K按鈕,CLASSWIZARD將按照我們剛才的要求進(jìn)行對話框類定義的工作。U'ffWORKSPACE,選擇FILEVIEW一頁,在SOURCEFlLES和HEADERFlLES組當(dāng)中到CLASSWIZARD已經(jīng)新建了兩個文件,并將它們加入了工程當(dāng)中。SongDIg.h當(dāng)中內(nèi)容是CSongDIg這個類的聲明,SongDIg.cpp這個文件當(dāng)中的內(nèi)容是這個類的實(shí)現(xiàn)。但是目前的程序只是包含了實(shí)現(xiàn)一個對話框的最基本功能的代碼,調(diào)用這個對話框類的DoModal函數(shù)之后可以運(yùn)行它。但是用戶通過對話框進(jìn)行的所有的輸入工作都不會被接受。下面,我們就著手完成實(shí)現(xiàn)對話框接受用戶輸入功能的工作。這里核心的工作就是實(shí)現(xiàn)對布置在對話框當(dāng)中的控件的控制??刂朴挚梢苑謨煞N類型:第一種是與界面上的控件交換數(shù)據(jù),在對話框中的某些響應(yīng)函數(shù)當(dāng)中編寫取出用戶在對話框當(dāng)中輸入的數(shù)據(jù)。比方說在用戶單擊了確認(rèn)輸入的按鈕,觸發(fā)了該按鈕的單擊事件的時候,我們就要從輸入新歌的編輯框當(dāng)中取出曲目字符串保存到數(shù)據(jù)庫當(dāng)中,并將其顯示在曲目列表當(dāng)中。我們可以使用MFC提供的一種叫做對話框數(shù)據(jù)交換(DDX)的機(jī)制來從編輯控件當(dāng)中取出數(shù)據(jù)。在MFC的對話框類CDialog中已經(jīng)封裝了這種機(jī)制。它的工作原理就是在對話框資源中的編輯框和對話框類的一個成員變量之間建立連接。然后由MFC自動地完成在成員變量和控件之間的數(shù)據(jù)交換工作。首先打開CLASSWIZARD,選中MEMBERVARIABLE這一頁,在CLASSNAME列表框當(dāng)中選擇CSongDIg,選擇曲目編輯框的ID號IDC_EDIT1,單擊ADDVARIABLE按鈕。圖3.6MEMBERVARIABLENAME一欄當(dāng)中敲入變量的名字,在CATEGORY列表框當(dāng)中可以選擇變量的類型,VALUE表示生成一個數(shù)據(jù)變量,CONTROL類型的變量可以被用來對控件資源進(jìn)行另一種類型的控制。它的類型依賴于前面選中的控件費(fèi)源,比方說如果為一個編輯框控件成一個CONTROL類型的成員變量,那么它只能是CEdit類型的。我們將在后面的內(nèi)容當(dāng)中具體地介紹如何使用CONTROL類型的成員變量。圖3.7生成一個VALUE變量,它的數(shù)據(jù)類型是字符串。單擊0K按鈕。這時WIZARD就自動地添加了進(jìn)行對話框數(shù)據(jù)交換所有的代碼。打開對話框類的頭文件和實(shí)現(xiàn)文件,我們發(fā)現(xiàn)當(dāng)中增加了一jCString類型的成員變量://DialogData//{{AFX_DATA(CSongDlg)enum{IDD=IDD_DIALOG2);CStringm_songname;11}}AFX_DATA并且在建構(gòu)函數(shù)當(dāng)中對這個變量進(jìn)行了初始化:CSongDlg::CSongDlg(CWnd*pParent/*=NULL*/):CDialog(CSongDlg::IDDZpParent)(//{{AFX_DATA_INIT(CSongDlg)m_songname=_T(nH;//}}AFX_DATA_INIT}在新生成的對話框類CSongDlg中有如下一個虛函數(shù):virtualvoidDoDataExchange(CDataExchange*pDX);DoDataExchange函數(shù)就是對話框類和對話框資源進(jìn)行DDX數(shù)據(jù)交換的函數(shù)。在對話框初始化的時候或者在程序中調(diào)用UpdateData()函數(shù)的時候,這個函數(shù)將會被調(diào)用。DDX_TEXT這個函數(shù)可以處理多種類型的數(shù)據(jù)成員變量與控件資源之間的數(shù)據(jù)交換。這中間包括int,uint,long,DWORD,CString,float,double等。PDX這個參數(shù)是一個指向一個CDataExchange對象的指針通過它我們可以設(shè)置進(jìn)行數(shù)據(jù)交換的方法。比方說:數(shù)據(jù)交換的方向。這段代碼就可以通過PDX的這個標(biāo)志志判斷數(shù)據(jù)交換的方向是從變量到控件還是從控件到變量,然后進(jìn)行不同的處理。進(jìn)行數(shù)據(jù)交換之后,程序當(dāng)中就可以通過成員變量來使用用戶輸入的數(shù)據(jù)了。對控件資源的另外一種類型的控制就是要操縱界面控件的外觀。比方說,我們可以通過生成一個CONTROL類型的成員變量來控制對話框當(dāng)中的列表控件。和VALUE類型變量的添加方法一樣,我們可以使用CLASSWIZARD生成一個CListControl類型的對象,在DoDataExchange當(dāng)中增加了這樣的代碼:DDX_Control(pDX,IDC_LIST1,m_listCtrll);DDX_CONTROL也是對話框數(shù)據(jù)交換機(jī)制提供的個函數(shù),它的作用和DDX_TEXT大致一樣。使用剛才定義的控件時象m」istCtrl1,就可以對列表框資源進(jìn)行操縱了。當(dāng)對話框開始運(yùn)行的時候,我們需要從數(shù)據(jù)庫當(dāng)中取出已經(jīng)入庫的曲目的名字將其顯示在曲目列表框當(dāng)中。這個工作應(yīng)該在對話框響應(yīng)WM_INITDIALOG消息的時候來做。使用CLASSWIZARD來添加這個消息響應(yīng)函數(shù)。在左邊的列表框當(dāng)中選定CSongDIg這個類,在消息列表框當(dāng)中選定對話框初始化消息,單擊ADDFUNCTION按鈕,WIZARD就自動地在這個類的聲明當(dāng)中重載了基類的這個成員函數(shù)并且在實(shí)現(xiàn)文件當(dāng)中加入了函數(shù)體。單擊EDITCODE按鈕,就可以在函數(shù)體當(dāng)中加入我們自己的代碼了。 I圖3.8在響應(yīng)WM_INITDIALOG消息的處理函數(shù)CSongDlg::OnlnitDialog中添加如下一段代碼:COleVariantvar;LV_ITEM Ivitem;CString Name(nsong_namen);char str[50];Ivitem.iltem=0;if(globalRS_>IsOpen())globalRS_>Close();CStringstrQuery=_T("Select*fromH;strQuery+="SONGS”;globalRS_>Open(dbOpenDynaset,strQuery);globalRS_>m_bCheckCacheForDirtyFields=FALSE;if(globalRS_>IsOpen())(if(!globalRS_>GetRecordCount())return0;globalRS_>MoveFirst();while(!globalRS_>IsEOF())var=globalRS_>GetFieldvalue(_T("[”)+Name+_T("]"));lvitem.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_DI_SETITEM;Ivitem.iltem++;Ivitem.iSubltem=0;strcpy(str,(LPCTSTR)CString(V_BSTRT(&var)));Ivitem.pszText=str;Ivitem.ilmage=0;m_originsonglist.InsertItem(&lvitem);globalRS_>MoveNext();}}if(globalRS_>IsOpen())globalRS_>Close();這里使用了DAO技術(shù)來訪問數(shù)據(jù)庫并使用讀出的字符串向列表控件當(dāng)中添加條目。關(guān)于DAO技術(shù)的使用方法,我們在其他的章節(jié)當(dāng)中會有詳細(xì)地介紹。我們關(guān)心的是下面這段代碼:lvitem.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_DI_SETITEM;Ivitem.iltem++;Ivitem.iSubltem=0;strcpy(str,(LPCTSTR)CString(V_BSTRT(&var)));Ivitem.pszText=str;Ivitem.ilmage=0;m_originsonglist.InsertItem(&Ivitem);它執(zhí)行了對列表控件添加條目的操作。這里需要用到WIN32提供的一個結(jié)構(gòu):LV_ITEMo我們可以從VC的HELP中找到其定義:typedefstruct_LV_ITEM{UINTmask;intiltem;intiSubltem;UINTstate;UINTstateMask;LPTSTRpszText;intcchTextMax;intilmage;//indexofthelistviewitem-JfliconLPARAMIParam;//32_bitvaluetoassociatewithitem}LV_ITEM;為了添加一個條目,我們首先在在這個結(jié)構(gòu)當(dāng)中填寫條目的信息,然后把它傳給列表對象的添加條H函數(shù)Insertitem就可以了。接下來的這段代碼位于響應(yīng)中曲目列表框當(dāng)中刪去選定曲H的按鈕單擊事件當(dāng)中。要實(shí)現(xiàn)從列表控件當(dāng)中刪去的條目的操作,只要把需要刪去的條目的索引號傳遞給列表對象的刪去條目函數(shù)Deleteltem就可以了。inttotalNum;totalNum=m_selsonglist.GetItemCount();intstep=0;LV_ITEMIvitem;Ivitem.mask=LVIF_TEXT|LVIF_IMAGE|LVIF_DI_SETITEM;Ivitem.iSubltem=0;Ivitem.ilmage=0;while(step<=totalNum){if(m_selsonglist.GetItemState(step,LVIS_SELECTED))(m_selsonglist.Deleteltem(step);}step++;)我們在這總結(jié)一下對對話框上面的控件進(jìn)行控制所需的工作:首先在對話框類當(dāng)中定義成員變量,然后調(diào)用對話框的成員變量的函數(shù)來操縱界面控件。2有關(guān)屏幕輸出1設(shè)備上下文工作原理在絕大多數(shù)的WINDOWS應(yīng)用都需要在屏幕上顯示自己的數(shù)據(jù)。由于WINDOWS是一個設(shè)備無關(guān)的操作系統(tǒng),所以任何向屏幕上進(jìn)行輸出的功能都要間接地通一個叫做設(shè)備上下文(devicecontext)的對象來完成。我們向設(shè)備上下文提出屏幕輸出的要求,然后由WINDOWS自己來調(diào)用具體的輸出設(shè)備的驅(qū)動程序來完成實(shí)際的輸出工作。圍繞設(shè)備上下文,MFC提供了一系列與其配合使用的繪圖對象,這其中包括畫筆對象、刷子對象以及字體對象等等。它們的工作模型是這樣的:首先對設(shè)備上下文對象——我們簡稱為DC對象——進(jìn)行設(shè)置,然后選擇進(jìn)行扉幕輸出所需要的工具,最后用DC對象的輸出函數(shù)繪制圖形。屏幕輸出的目標(biāo)一般都是窗口的客戶區(qū),它是一個萬能的輸出區(qū)域,可以接受無論是文本、位圖、還是其他類型的數(shù)據(jù)(比方說OLE對象)。2實(shí)例繪圖原理剖析在有關(guān)用戶輸入部分的內(nèi)容當(dāng)中,我們曾經(jīng)介紹過?個實(shí)例,它訪問一個保存歌曲曲目的數(shù)據(jù)庫,用戶可以通過對話框讓用戶定義一個曲目表,并選定一張背景圖,然后在一個沒有系統(tǒng)菜單的窗口客戶區(qū)上滾動顯示曲目的名字。我們已經(jīng)介紹了通過對話框介紹用戶輸入的方法,接下來就看重介紹如何把用戶輸入的信息在屏幕上顯示出來。我們將用戶選定的字符串在一張背景圖上面滾動輸出。前面已經(jīng)介紹了使用設(shè)備上卜.文進(jìn)行工作的基本模型。即:首先選擇繪圖的工具,然后調(diào)用DC的繪圖函數(shù)來進(jìn)行繪制。在WINDOWS當(dāng)中,每次窗口的外觀發(fā)生改變的時候都會發(fā)出一個WM_PAINT消息,窗口的重繪工作都是在響應(yīng)這個消息的處理函數(shù)當(dāng)中進(jìn)行的??梢允褂肅LASSWIZARD來添加這個消息響應(yīng)函數(shù)。之后,就可以在這個函數(shù)當(dāng)中進(jìn)行屏幕輸出了。還有什么時候會觸發(fā)重繪事件呢?在程序中調(diào)用CWND的UpdateWindow和RedrawWindow數(shù)的時候都會觸發(fā)重繪事件。我們還可以直接使用SendMessage函數(shù)向一個指定的窗口送出重繪消息。另外調(diào)用CWND的Invalidate函數(shù)可以指示重繪的時候是否需要擦去背景,如果使用InvalidateRect函數(shù)還可以設(shè)置客戶區(qū)的無效區(qū)域,系統(tǒng)重繪的時候?qū)⒅话言搮^(qū)域的內(nèi)容重新繪制,我們首先在窗口的客戶區(qū)上帖一張位圖,然后滾動輸出文本。如何實(shí)現(xiàn)滾動輸出呢我們的方法是在程序中設(shè)置一個定時器,在定時器計(jì)時已滿事件WM_TIMER觸發(fā)的時候來,調(diào)用REDRAWWINDOW函數(shù),觸發(fā)重繪事件,我們只要在它的消息響應(yīng)函數(shù)ONPAINT當(dāng)中重新繪制背景,擦去原來的文本,然后不斷的改變文本輸出的位置就可以達(dá)到目的了。您可能會重繪整個背景的做法會很耗費(fèi)了過多的系統(tǒng)時間并且可能產(chǎn)背景的閃爍。這種擔(dān)心是必要的。在WINDOWS95當(dāng)中,系統(tǒng)對重繪的機(jī)制進(jìn)行了優(yōu)化,在我們沒有指定無效區(qū)域的情況之下,系統(tǒng)自己會選擇一個最小的無效區(qū)域,只對這一區(qū)域進(jìn)行重繪。3繪圖操作實(shí)現(xiàn)下面介紹繪圖操作的源程序使您對設(shè)備上下文的使用有一個大致的了解。首先生成一個設(shè)備上下文。CPaintDC是MFC提供的一個從CDC繼承出來的類.使用它有什么好處呢?如果直接使用CDC的話,我們需要首先調(diào)用CWnd的BeginPaint函數(shù)為重繪工作做一些準(zhǔn)備工作,在完成繪制之還要用EndPaint函數(shù)表示結(jié)束繪制工作。所有的繪圖操作都必須在這兩個函數(shù)之間完成。CPaintDC封裝了這兩個函數(shù),自動地對它們進(jìn)行調(diào)用,使用者無須再去進(jìn)行這些調(diào)用。CPaintDCde(this);BITMAPbm;m_bitmap_>GetBitmap(&bm);CDCdclmage;if(!dclmage.CreateCompatibleDC(&dc))return;CBitmap*pOldBitmap=dclmage.Selectobject(m_bitmap);de.BitBlt(0,0,bm.bmWidth,bm.bmHeight,&dclmage,0,0,SRCCOPY);以上這段代碼完成向屏幕上面輸出位圖的工作。首先根據(jù)資源生成一個位圖對象,然后生成成一個和CPaintDC-致的內(nèi)存DC對象,在內(nèi)存DC當(dāng)中選擇這個位圖。BITMAP是一個WlN32提供的位圖結(jié)構(gòu),我們將這幅位圖的信息保存在這個結(jié)構(gòu)當(dāng)中。這樣做的原因是由于在使用到位圖的位置及大小信息。BITMAP結(jié)構(gòu)的定義如下:typedefstructtagBITMAP{/*bm*/intbmType;intbmWidth;intbmHeight;intbmWidthBytes;BYTEbmPlanes;BYTEbmBitsPixel;LPVOIDbmBits;}BITMAP;作好這些準(zhǔn)備工作之后。調(diào)用DC對象的BitBlt函數(shù)把位圖從內(nèi)存DC當(dāng)中貼到繪圖DC當(dāng)中來。前四個參數(shù)指示了位圖在目的DC上的位置和大小。第五個參數(shù)是原來保存位圖的內(nèi)存DC的地址。接下來的兩個參數(shù)是從位圖的哪一點(diǎn)開始進(jìn)行拷。最后這個參數(shù)設(shè)置該位圖和屏幕上當(dāng)前內(nèi)容的相互關(guān)系,SRCCOPY的意思是拷貝過來覆蓋原來的內(nèi)容。這個參數(shù)還有其他的許多選擇比方說取反操作或者異或操作,設(shè)置不同的參數(shù)可以獲得豐富的效果。下面介紹如何輸出文本。首先對DC對象進(jìn)行設(shè)置:de.SetBkMode(TRANSPARENT);de.SetTextColor(RGB(0,155,nowX*nowX));這里把文本輸出的背景置為透明,然后設(shè)置輸出文本的前景顏色。卜面這段程序的意思是為將要輸出的文本選擇字體。LOGFONTlogfont;memset(&logfontz0,sizeof(logfont));logfont.IfWeight=50;logfont.IfHeight=50;Istrcpy(logfont.1fFaceName,"黑體");nowFont.CreateFontIndirect(&logfont);de?Selectobject(&nowFont);首先聲一個WIN32提供的字體信息結(jié)構(gòu)。為其分配內(nèi)存空間。再按照我們的要求填寫這個字體結(jié)構(gòu),設(shè)置字體的寬度,設(shè)置字體的高度,選擇字體種類,根據(jù)這個結(jié)構(gòu)生成一個CFONT字體對象,讓DC對象選中這個字體對象,最后使用DC的文本輸出函數(shù)來輸出一個字符串??偠灾M(jìn)行屏幕輸出的規(guī)則如K:第一必須通過CDC對象進(jìn)行屏幕輸出;第二設(shè)置DC對象的輸出屬性;第三選擇繪圖工具第四用CDC對象的繪圖函數(shù)。有關(guān)屏幕輸出的內(nèi)容就介紹到這里。4有關(guān)屏幕映射方式在般的情況之下,我們都以像素作為繪圖的單位,我們稱之為設(shè)備坐標(biāo)。我們在進(jìn)行繪圖操作的時候,不可避免的要用到設(shè)備坐標(biāo)系。WINDOWS提供了幾種映射方式,或稱坐標(biāo)系??梢酝ㄟ^它們來和設(shè)備上下文相聯(lián)系。比方說不管是什么樣的顯示設(shè)備,如果我們需要在上面顯示一個2英寸高,2英寸寬的矩形,該怎樣處理呢?這就要依賴于我們所設(shè)定的坐標(biāo)系。如果我們指定了MM_TEXT方式,這時坐標(biāo)原點(diǎn)就位于屏幕的左上角,X軸和Y軸的方向分別指向我們面對屏幕的右方和下方,它的繪圖單位是像素,如果一英寸對應(yīng)72個像素的話,我們就需要這樣繪制這個矩形:DC.Rectangle(CRect(0,0,72*2,72*2));所以我們?nèi)绻覀冎付薓M_LOENGLISH方式,那么一個繪圖單位就是百分之一英寸,坐標(biāo)原點(diǎn)仍然位于屏幕的左上角,但是X軸和丫軸的方向恰好和MM_TEXT方式下的軸方向相反,同樣完成繪制上面提到的矩形的工作,我們就需要寫出這樣的代碼:DC.Rectangle(CRect(0,0,200,_200));可見,坐標(biāo)系的選擇對我們編寫程序有很大的影響。此外,在有些時候,我們需要在幾個不同的坐標(biāo)系下面工作,那么還需要在進(jìn)行在這些坐標(biāo)系之間的轉(zhuǎn)換工作。所以,我們有必要在這里詳細(xì)介紹以下WINDOWS的坐標(biāo)映射方法。一般來說,最常用的就是WM_TEXT方式。在WM_TEXT坐標(biāo)方式下面,坐標(biāo)被映射到了像素,X的值向右方遞增,丫的值向下遞增,并且可以通過調(diào)用CDC的SetViewpotOrg函數(shù)來改變坐標(biāo)原點(diǎn)。下面的代碼把屏幕映射方式設(shè)為MM_TEXT方式,并且把坐標(biāo)原點(diǎn)設(shè)在(300,300)處:DC.SetMapMode(MM_TEXT);DC.SetViewportOrg(CPoint(300,300));另外,WINDOWS提供了一組非常重要的比例固定的映射方式,在這些映射方式下面,我們可以改變它的坐標(biāo)原點(diǎn),卻無法改變它的比例因子。對于MMJJDENGLISH映射方式,我們已經(jīng)知道它的X值是向右遞減的,丫的值是向下遞減的,所有的固定比例的映射方式都遵循這一原則。它們的比例因子也各不相同。我們列表如下:映射方式邏輯單位MM_LOENGLISH0.01英寸MM_HIENGLISH0.001英寸MM_LOMETRIC0.1毫米MM_HIMETRIC0.01毫米MM_TWIPS1/1440英寸最后一種映射方式MM_TWIPS常常用語打印機(jī),一個‘twip'單位相當(dāng)于1/20個點(diǎn)(一點(diǎn)近似與1/72)英寸。例如,如果指定的MM_TWIPS一個社單位,那么對于12點(diǎn)大小的字模來說,字符的高度為12x20,即240個twip。除了固定比例的映射方式,WINDOWS還提供了比例可變的映射方式,在這種映射方式下面,我們除了可以改變它們比例因子之外還可以改變比例因子。借助于這樣的映射方式,當(dāng)用戶改變窗口的尺寸的時候,繪制的圖形的大小也可以根據(jù)比例發(fā)生相應(yīng)的變化;同樣,當(dāng)我們翻轉(zhuǎn)某個軸的時候,他們所繪制的圖像,也以另外的一個軸為軸心進(jìn)行翻轉(zhuǎn)。這樣的映射方式有兩種:MMJSOTROPIC和MM_ANIOTROPICo在MM」SOTROPIC方式下,縱橫的比例為1:1,換句話說,無論比例因子如何變化,我們畫出的圖形不會改變自己的形狀。但是在MM_ANIOSTROPIC方式下面,X和丫的比例因子可以獨(dú)立地變化,圖形的形狀可以發(fā)生變化。我們分析下面這段程序:voidCAView::OnDraw(CDC*pDC)CRectclientDC;GetClientRect(clientRect);pDC_>SetMapMode(MM_ANISOTROPIC);pDC_>SetWindowExt(1000,1000);pDC_>SetViewportExt(clientRect.right,_clientRect.bottom);pDC_>SetViewportOrg(clientRect.right/2,clientRect.bottom/2);pDC_>Ellipse(CRect(_500z_500z500,500));這段代碼的功能是這樣的,首先取得窗口客戶區(qū)矩形的大小,然后用SetWindowExt和SetViewportExt函數(shù)設(shè)定比例,結(jié)果窗口尺寸的大小被設(shè)為1000個邏輯單位高和1000個邏輯單位寬,坐標(biāo)原點(diǎn)被設(shè)為窗口的中心,在這樣的設(shè)置之下,繪制出一個半徑為500個邏輯單位的橢圓。在這里如果將映射方式改變?yōu)镸MJSOTROPIC那么就將畫出一個圓。圓的直徑是窗口舉行寬和高的最小值。下面我們給出邏輯單位到設(shè)備單位的公式:X比例因子=X視口范圍/X窗口范圍丫比例因子=丫視口范圍/丫窗口范圍設(shè)備X=邏輯X*X比例因子+X坐標(biāo)原點(diǎn)偏移設(shè)備Y=邏輯丫*Y比例因子+Y坐標(biāo)原點(diǎn)偏移當(dāng)我們設(shè)定了設(shè)備上下文的映射方式之后,就可以直接使用邏輯坐標(biāo)作為其參數(shù)了,但是從WM_MOUSEMOVE消息所獲得的鼠標(biāo)的坐標(biāo)值是設(shè)備坐標(biāo)。許多其他的MFC庫函數(shù),尤其是類CRect的成員函數(shù),只接受設(shè)備坐標(biāo)。所以我們有時要利用CDC的LPtoDP和DPtoLP在邏輯坐標(biāo)和設(shè)備坐標(biāo)之間進(jìn)行轉(zhuǎn)換的工作。卜面我們列出進(jìn)行坐標(biāo)映射工作的時候所要遵循的一些規(guī)則:?可以認(rèn)為CDC的所有成員函數(shù)都以邏輯坐標(biāo)作為參數(shù),但和CRect有關(guān)的函數(shù)例外。?可以認(rèn)為CWnd的成員函數(shù)都以設(shè)備坐標(biāo)作為參數(shù)。?所有的HIT_TEST操作都應(yīng)該考慮設(shè)備坐標(biāo)。?以邏輯坐標(biāo)的形式來保存數(shù)據(jù),否則用戶對窗口進(jìn)行滾動操作的時候,這個數(shù)據(jù)就不再有效了。3文件處理幾乎所有的軟件都需要將程序當(dāng)中的信息保存在磁盤存儲器上面。這些信息可能是程序運(yùn)行的初始化數(shù)據(jù),或者是程序中計(jì)算得到的結(jié)果,還可能是程序經(jīng)常用到的資料。從磁盤存儲器上存取數(shù)據(jù)的工作往往是通過文件操作或者數(shù)據(jù)庫操作來完成的。關(guān)于數(shù)據(jù)庫操作的內(nèi)容,我們將在后面的章節(jié)當(dāng)中進(jìn)行詳細(xì)的介紹,在下面的內(nèi)容中,我們主要討論VC如何實(shí)現(xiàn)一般意義上的數(shù)據(jù)存取工作。VC是面向?qū)ο蟮拈_發(fā)平臺,在使用MFC編寫的程序中,我們定義和生成了各種各樣的對象,通過它們之間的協(xié)同工作完成程序的功能。所以在MFC中,程序的存取工作的核心內(nèi)容就是如何實(shí)現(xiàn)這些對象的持續(xù)化。一個可以實(shí)現(xiàn)持續(xù)化的對象知道如何保存和載入它們自己的數(shù)據(jù)。比方說,在程序使用MFC文檔/視圖結(jié)構(gòu)的時候,如果為文檔對象提供正確的持續(xù)化功能,它將在您需要的時候自動地保存和恢復(fù)自己的數(shù)據(jù),并且保持用戶最新的修改結(jié)果。需要注意的是對象的持續(xù)化同樣是將數(shù)據(jù)保存到磁盤文件中去,它的好處在于MFC對二進(jìn)制文件的存取過程進(jìn)行了封裝,使用來實(shí)現(xiàn)對象存取的程序代碼得到了簡化。當(dāng)然,如果您更喜歡直接操作文件進(jìn)行數(shù)據(jù)的存取工作,MFC也提供了更為直接的渠道。CFile這個類封裝了所有對文件的常用操作,使用CFile對象處理文件會比使用API函數(shù)簡單得多。1對象持續(xù)化簡述在MFC當(dāng)中,對象的持續(xù)化功能主要是通過文檔/視圖結(jié)構(gòu)當(dāng)中文檔對象的序列化機(jī)制來實(shí)現(xiàn)的。下面,我們將詳細(xì)介紹如何使用序列化機(jī)制來實(shí)現(xiàn)對象的持續(xù)化。序列化,簡單地說就是向一個持久性的存儲媒體——如磁盤文件保存對象或讀取對象的過程??梢詫?shí)現(xiàn)序列化的類——即從CObject繼承而來的類,有一個叫做Serialize的成員函數(shù),序列化工作主要是在這個函數(shù)當(dāng)中進(jìn)行的。我們使用一張示意圖來說明序列化的原理。MFC使用一個類型為CArchive的歸檔對象充當(dāng)磁盤文件與程序中的對象的中介。歸檔對象總是與一個CFile對象相關(guān)聯(lián),從中獲得一些進(jìn)行序列化所需要的信息,比如說文件名,以及存取標(biāo)志等。對象的持續(xù)化的主要工作就是將自己的成員變量或者當(dāng)前狀態(tài)保存起來。我們可以使用經(jīng)過重載的流入和流出操作符直接向歸檔對象中保存或者取出變量成員的值,而將這些數(shù)據(jù)保存到磁盤文件中的工作由CArchive對象指示CFile對象來完成。當(dāng)用戶在打開或保存擁有文檔對象數(shù)據(jù)的文件或者使用文檔對象的Open、Save、SaveAs菜單命令時,MFC便會自動調(diào)用Serialize函數(shù)。使類實(shí)現(xiàn)序列化,需要五個步驟:1、從Cobject類或其派生類派生用戶類;2、在類聲明中使用DECLARE_SERIAL宏;3、重載Serialize函數(shù);4、定義不用變量的構(gòu)造函數(shù);5、在類實(shí)現(xiàn)文件中使用宏IMPLEMENT_SERIAL。在下?節(jié)中,我們將以?個具體的實(shí)例來詳細(xì)說明如何實(shí)現(xiàn)類的序列化。3.2實(shí)例分析 I在描述了類序列化的基本原理之后,讓我們來看一個II體的序列化實(shí)例DrawLine。啟動這個實(shí)例。圖3.9在這個實(shí)例中,我們將完成對直線的簡單繪制。在視圖按下鼠標(biāo)左鍵,然后拖動鼠標(biāo)到一個新位置松開鼠標(biāo),程序就畫出一條直線。再來看看這個程序的基本構(gòu)成。除了基本的文檔類和視類之外,我們還有一個直線類CLine,它有四個int成員變量m_x1,m_y1,m_x2,m_y2,用來記錄直線兩個端點(diǎn)的X軸和Y軸方向坐標(biāo),此外有一個Draw成員函數(shù),Draw是根據(jù)直線的以上四個成員變量,在視圖客戶區(qū)中繪出直線。在Workspace的ClassView中雙擊類CLine的Draw函數(shù),則可以看到Draw的實(shí)現(xiàn)。voidCLine::Draw(CDC*PDC)PDC_>MoveTo(m_xlzm_y1);PDC_>LineTo(m_x2,m_y2);我們對視類CDrawLineView的OnLButtonDown,OnMouseMove,OnLButtonUp三條消息進(jìn)行了處理,在Workspace的ClassView中同樣可看到它們的實(shí)現(xiàn)。此外我們在文檔類CDrawLineDoc中有一個成員變量m_LineArray,它是用來記錄我們在視圖客戶區(qū)所畫的直線。函數(shù)GetLine是根據(jù)索引取得m_LineArray中的一條直線,GetNumLines則是取得直線的總數(shù)的。在了解了基本的程序結(jié)構(gòu)之后,下面對宜線對象進(jìn)行序列化處理。1從Object類中派生并使用宏DECLARE_SERIAL打開定義CLine這個類的頭文件line.h,可以看到這個類是從CObject類派生出來的。要對CLine類實(shí)現(xiàn)序列化,需要在類的聲明中加入宏DECLARE_SERIAL的調(diào)用,并在類的實(shí)現(xiàn)文件中,力口入宏IMPLEMENT_SERIAL的調(diào)用。CObject類擁有基本的序列化功能,通過對此類的繼承實(shí)現(xiàn)可以獲得這些功能,此外一個無參數(shù)的構(gòu)造函數(shù)是不可缺少的。我們打開Line.h后,在CLine類定義中第一句就可以是DECLARE_SERIAL(CLine),這個宏不需要加分號。2重載Serialize成員函數(shù)我們要實(shí)現(xiàn)序列化,先對其進(jìn)行改造,在Workspace的ClassView中選擇CLine類,單擊鼠標(biāo)右鍵,選擇AddMemberFunction增加?個成員函數(shù):圖3.10VC將會跳出如3.11所示下添加函數(shù)的對話框:圖3.11在FunctionType輸入void,在FunctionDeclaretion輸入Serialize(CArchive&ar),然后選擇Virtual,按OK即可。然后在ClassView中可以看到這個函數(shù)。下面我們編輯這個函數(shù),雙擊Workspace顯示的CLine類的Serialize函數(shù),則轉(zhuǎn)到Line.cpp中其實(shí)現(xiàn)處。這個函數(shù)的實(shí)現(xiàn)如下:voidCLine::Serialize(CArchive&ar)(CObject::Serialize(ar);if(ar.IsStoring())ar<<m_x2<<m_y2;elsear>>m_xl>>m_y1;ar>>m_x2>>m_y2;首先調(diào)用基類的Serialize函數(shù),CObject::Serialize(ar);然后判斷是保存數(shù)據(jù)還是載入數(shù)據(jù),然后再根據(jù)判斷的結(jié)果進(jìn)行實(shí)際的存取工作。這里ar就是框架程序傳遞給序列化函數(shù)的歸檔對象指針。當(dāng)調(diào)用完基類的序列化函數(shù)后,判斷ar的狀態(tài),當(dāng)ar.lsStoring()返回真時,這時進(jìn)行數(shù)據(jù)保存;當(dāng)ar.lsStoring。返回非真時,這時CArchive對象要求讀取數(shù)據(jù)。3使用操作符存取數(shù)據(jù)在上面的代碼中我們用到了>>和<<,在這里對它們作一個介紹,>>和<<是一種操作符,用來指示向CArchive對象讀取還是保存數(shù)據(jù),必要時我們可以重載重定向符。如ar>>m_x1>>m_y1;這一句,其中>>表示從ar中讀出數(shù)據(jù)m_x1,m_y2,這個符號及>>可以連用,亦可以分開來用,如ar>>m_x1;ar>>m_y1;同樣ar<<m_x1<<m_y1;中的〈〈是把數(shù)據(jù)存入ar中。4文檔對象序列化在對直線對象進(jìn)行序列化函數(shù)處理之后,接下來,我們對文檔類進(jìn)行改寫,首先實(shí)現(xiàn)文檔類的序列化函數(shù)。雙擊Workspace中CDrawLineDoc類Serialize函數(shù)打開它,文檔類的Serialize函數(shù)是個虛擬成員函數(shù)的,其缺省實(shí)現(xiàn)是不做任何工作的。我們再來看文檔類的序列化函數(shù),CDrawLineDoc類的序列化函數(shù)上要是對CLine類對象的序列化函數(shù)的調(diào)用,其

溫馨提示

  • 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

提交評論