




免費預覽已結(jié)束,剩余86頁可下載查看
下載本文檔
版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
第一章 VC+基礎知識Visual C+(以下簡稱VC)是一個強大的編程工具,它以C+為語言基礎。C+是由C語言發(fā)展而來,是面向?qū)ο蟪绦蛟O計語言之一,要用VC開發(fā)程序,要有堅實的C+語言基礎。我們在學習VC+語言之前首先必須了解兩個基本概念1 了解C+語言的編程思想:即面向?qū)ο蟮乃枷?,面向?qū)ο笕筇匦詳?shù)據(jù)封裝、繼承性、多態(tài)性。2 了解windows編程基礎。這是我們在學習VC+語言之前必須闖過的兩道基礎關。在這一章中,我們要了解面向?qū)ο缶幊痰幕舅枷?,Windows編程的基礎以及MFC的基礎知識。由于時間有限,我們只能將以后學習VC+時遇到的概念做一簡要介紹。第一節(jié) 面向?qū)ο蟪绦蛟O計的基本概念一、什么是面向?qū)ο竺嫦驅(qū)ο螅╫bject oriented,簡稱OO)是一種新的軟件設計思想。這種思想力求使在面向?qū)ο蟮某绦蛟O計中,有經(jīng)常接觸類、對象等專業(yè)名詞;到底什么是類、什么是對象呢?在程序又是怎樣運用呢?類是面向?qū)ο蟪绦蛟O計的核心,它實際是一種新的數(shù)據(jù)類型,也是實現(xiàn)抽象類型的工具,因為類是通過抽象數(shù)據(jù)類型的方法來實現(xiàn)的一種數(shù)據(jù)類型。類是對某一類對象的抽象;而對象是某一種類的實例,因此,類和對象是密切相關的。沒有脫離對象的類,也沒有不依賴于類的對象。二、封裝性封裝性是面向?qū)ο蟮幕A。面向?qū)ο笙到y(tǒng)的封裝性其實是一種信息隱藏技術,它使系統(tǒng)設計人員能清楚地標注出他們所提供的服務截面,用戶只看見對象提供的操作功能,看不到其中的數(shù)據(jù)和操作代碼細節(jié)。面向?qū)ο笙到y(tǒng)的封裝單位是對象,對對象的封裝是通過類的描述來實現(xiàn)的。1、什么是類 類是一種復雜的數(shù)據(jù)類型,它是將不同類型的數(shù)據(jù)和與這些數(shù)據(jù)相關的操作(函數(shù))封裝在一起的集合體。這有點像C語言中的結(jié)構,唯一不同的就是結(jié)構沒有定義所說的“數(shù)據(jù)相關的操作”,“數(shù)據(jù)相關的操作”就是我們平常經(jīng)??吹降摹胺椒ā保虼?,類具有更高的抽象性,類中的數(shù)據(jù)具有隱藏性,類還具有封裝性。 類的結(jié)構(也即類的組成)是用來確定一類對象的行為的,這些行為是通過一種操作接口來描述的(也即平時我們所看到的類的成員函數(shù)),使用者只關心的是接口的功能(也就是我們只關心類的各個成員函數(shù)的功能),對它是如何實現(xiàn)的并不感興趣。而操作接口又被稱為這類對象向其他對象所提供的服務。2、類的定義格式 類的定義格式一般地分為說明部分和實現(xiàn)部分。說明部分是用來說明該類中的成員,包含數(shù)據(jù)成員的說明和成員函數(shù)的說明。成員函數(shù)是用來對數(shù)據(jù)成員進行操作的,又稱為“方法”。實現(xiàn)部分是用來對成員函數(shù)的定義。概括說來,說明部分將告訴使用者“干什么”,而實現(xiàn)部分是告訴使用者“怎么干”。類的一般定義格式如下:class public: private: ; 下面簡單地對上面的格式進行說明:class是定義類的關鍵字,是種標識符。一對花括號內(nèi)是類的說明部分(包括前面的類頭)說明該類的成員。類的成員包含數(shù)據(jù)成員和成員函數(shù)兩部分。訪問權限上來分,類的成員又分為:公有的(public)、私有的(private)和保護的(protected)三類。公有的成員用public來說明,公有部分往往是一些操作(即成員函數(shù)),它是提供給用戶的接口功能。這部分成員可以在程序中引用。私有的成員用private來說明,私有部分通常是一些數(shù)據(jù)成員,這些成員是用來描述該類中的對象的屬性的,用戶是無法訪問它們的,只有成員函數(shù)或經(jīng)特殊說明的函數(shù)才可以引用它們,它們是被用來隱藏的部分。保護類(protected)將在以后介紹。 關鍵字public,private和protected被稱為訪問權限修飾符或訪問控制修飾符。它們在類體內(nèi)(即一對花括號內(nèi))出現(xiàn)的先后順序無關,并且允許多次出現(xiàn),用它們來說明類成員的訪問權限。 其中,是類定義中的實現(xiàn)部分,這部分包含所有在類體內(nèi)說明的函數(shù)的定義。如果一個成員函數(shù)的類體內(nèi)定義了,實現(xiàn)部分將不出現(xiàn)。如果所有的成員函數(shù)都在類體內(nèi)定義,則實現(xiàn)部分可以省略。下面給出一個日期類定義的例子:class CDatepublic:/公共部分以下兩個函數(shù)是該類提供給外界的接口void SetDate(int y, int m, int d);/ 該函數(shù)的功能為日期賦值int IsLeapYear();/判斷是否是閏年void Print();/打印日期private:/該類的成員變量是私有的只能在該類內(nèi)部調(diào)用int year, month, day;/類的實現(xiàn)部分,即函數(shù)體void CDate:SetDate(int y, int m, int d)year = y;month = m;day = d;int CDate:IsLeapYear()return(year%4=0 & year%100!=0) | (year%400=0);void CDate:Print();coutyear.month.dayendl;這里出現(xiàn)的作用域運算符:是用來標識某個成員函數(shù)是屬于哪個類的。3、對象和對象的定義我們已經(jīng)知道,對象是類的實例。對象是屬于某個已知的類。因此,定義對象之前,一定要先定義好該對象的類。下面簡單的介紹對象的定義。 (1)、對象的定義格式 對象在確定了它的類以后,其定義格式如下: 其中,是待定的對象所屬的類的名字,即所定義的對象是該類類型的對象。中可以有一個或多個對象名,多個對象名時用逗號分隔。中,可以是一般的對象名,還可以是指向?qū)ο蟮闹羔樏蛞妹?,也可以是對象?shù)組名。如: CDate date1, date2, *Pdate, date31;(2)、對象成員的表示方法 一個對象的成員就是該對象的類所定義的成員。對象成員有數(shù)據(jù)成員和成員函數(shù),其表示方式如下: . 或者 .() 前者用來表示數(shù)據(jù)成員的,后者用來表示成員函數(shù)的。如: date1.year, date1.month, date1.day; date1.SetDate( y, m, d); 這里,是一個運算符,該運算符的功能是表示對象的成員。指向?qū)ο蟮闹羔樀某蓡T表示如下: -如: Pdate-year, Pdate-month, Pdate-day; Pdate-SetDate( y, m, d); 由同一個類所創(chuàng)建的對象的數(shù)據(jù)結(jié)構是相同的,類中的成員函數(shù)是共享的。兩個不同的對象的名字是不同的,它們的數(shù)據(jù)結(jié)構的內(nèi)容(即數(shù)據(jù)成員的值)是不同的。因此,系統(tǒng)對已定義的對象僅給它們分配數(shù)據(jù)成員變量,而一般數(shù)據(jù)成員又都為私有成員,不同對象的數(shù)據(jù)成員的值可以是不相同的。(3)對象的初始化構造函數(shù)和析構函數(shù) 構造函數(shù)和析構函數(shù)是在類體中說明的兩種特殊的成員函數(shù)。構造函數(shù)的功能是在創(chuàng)建對象時,使用給定的值來將對象初化。析構函數(shù)的功能是用來釋放一個對象的,在對象刪除前,用它來做一些清理工作,它與構造函數(shù)的功能正好相反。下面舉一例子來說明構造函數(shù)和析構函數(shù)的特點:class CDatepublic: CDate(int y, int m, int d);CDate(); CDate(); int IsLeapYear(); void Print();private: int year, month, day;/類的實現(xiàn)部分CDate:CDate(int y, int m, int d) year = y; month = m; day = d; cout構造函數(shù)已被調(diào)用。n;CDate:CDate() cout析構函數(shù)被調(diào)用。n;int CDate:IsLeapYear() return(year%4=0 & year%100!=0) | (year%400=0);void CDate:Print()coutyear.month.dayendl;1、構造函數(shù)可以重載,即可以定義多個參數(shù)個數(shù)不同的函數(shù)。 2、程序中不能直接調(diào)用構造函數(shù),在創(chuàng)建對象時系統(tǒng)自動調(diào)用構造函數(shù)。 析構函數(shù)的特點如下: 1、析構函數(shù)也是一個特殊的函數(shù),它的名字同類名,并在前面加“”字符,用來與構造函數(shù)加以區(qū)別。析構函數(shù)不指定數(shù)據(jù)類型,并且也沒有參數(shù)。 2、一個類中只可能定義一個析構函數(shù)。 3、析構函數(shù)可以被調(diào)用,也可以系統(tǒng)調(diào)用。在下面兩種情況下,析構函數(shù)會被自動調(diào)用。 如果一個對象被定義在一個函數(shù)體內(nèi),則當這個函數(shù)結(jié)束時,該對象的析構函數(shù)被自動調(diào)用。 當一個對象是使用new運算符被動態(tài)創(chuàng)建的,在使用delete運算符釋放它時,delete將會自動調(diào)用析構函數(shù)。三、繼承性1為什么要使用繼承類支持層次機制,因此我們可以借用可重用性部件來很容易的從一個或多個已有類出發(fā),來生產(chǎn)各種更符合我們要求的新類。假設我們從類A出發(fā)來派生新的類B,那么我們稱類A為類B的基類(base class),類B為類A的派生類(derived class),類B繼承了類A中的各種行為和狀態(tài),并可添加自己的成員變量和成員函數(shù)。我們先來看一個例子,上圖給出了自然世界中的生物的一種繼承層次圖,最高層次的生物類代表了層次結(jié)構中最一般的概念,較低層次的類表示由上一層的類(即其基類)所派生的特殊的概念。如上面的繼承關系,動物類從其基類生物類中繼承生物類的所有屬性和行為,并且定義了動物類所特有的屬性和行為,類似的,脊椎動物類從動物類那兒繼承了所有的屬性和行為,并且定義了自身特有的屬性和行為;,人類從靈長動物類那兒繼承了所有的屬性和行為,并且定義了人類所特有的屬性和行為。之所以舉上面的例子是為了將程序空間和現(xiàn)實生活空間來進行對比,結(jié)果說明一點,類的繼承使得我們可以以一種自然的方式來模擬生活空間中的對象的層次結(jié)構,也就是說,我們可以以一種符合正常思維邏輯的自然的方式來思考和組織應用程序的結(jié)構,然后,可以將這個結(jié)構幾乎不作修改或者只需作少量的修改地用面向?qū)ο蟮木幊虂肀磉_,從而大大的縮短了軟件系統(tǒng)的開發(fā)周期。下面我們舉一個現(xiàn)實編程中的例子,考慮MFC (Microsoft Foundation Class Library,Microsoft基礎類庫)中的CEdit類,它封裝了Windows中的編輯框控件,圖2.2顯示了CEdit類的繼承結(jié)構。圖2.2 類CEdit在MFC中的繼承層次2怎樣繼承通過繼承機制,可以利用已有的數(shù)據(jù)類型來定義新的數(shù)據(jù)類型。所定義的新的數(shù)據(jù)類型不僅擁有新定義的成員,而且還同時擁有舊的成員。我們稱已存在的用來派生新類的類為基類,又稱為父類。由已存在的類派生出的新類稱為派生類,又稱為子類。 在C+語言中,一個派生類可以從一個基類派生,也可以從多個基類派生。從一個基類派生的繼承稱為單繼承;從多個基類派生的繼承稱為多繼承。派生類的定義格式 單繼承的定義格式如下:class : ;class CEdit:CWnd 其中,是新定義的一個類的名字,它是從中派生的,并且按指定的派生的。常使用如下三種關鍵字給予表示: public 表示公有基類; private 表示私有基類; protected 表示保護基類;四、多態(tài)性多態(tài)性是面向?qū)ο蟪绦蛟O計的重要特性之一。它與前面講過的封裝性和繼承性構成了面向?qū)ο蟪绦蛟O計的三大特性。這三大特性是相互關聯(lián)的。封裝性是基礎,繼承性是關鍵,多態(tài)性是補充,而多態(tài)性又必須存在于繼承的環(huán)境之中。 所謂多態(tài)性是指發(fā)出同樣的消息被不同類型的對象接收時導致完全不同的行為。這里所說的消息主要是指對類的成員函數(shù)的調(diào)用,而不同的行為是指不同的實現(xiàn)。利用多態(tài)性,用戶只需發(fā)送一般形式的消息,而將所有的實現(xiàn)留給接收消息的對象。對象根據(jù)所接收到的消息而做出相應的動作(即操作)。 函數(shù)重載和運算符重載是簡單一類多態(tài)性。重要的多態(tài)性是建立在虛函數(shù)的概念和方法基礎上的。假定我們已經(jīng)定義了一個指向哺乳動物類的實例對象的指針,如下所示:CMammal *pMammal然后我們定義了一個人類的實例對象和一個狒狒類的實例對象,如下所示:CHuman Human;CBaboon Baboon;然后,我們可以將指針pMammal指向Human對象,在C+語言中是可以這樣做的:pMammal=&Human;也可以將指針指向Human對象:pMammal=&Baboon;考查上面的兩種情況,我們假定在哺乳動物類、人類和狒狒類中都定義了一個Eat (吃)方法,很顯然,當我們使用下面的代碼來調(diào)用人類對象和狒狒類對象的Eat方法時不會遇到什么問題:Human.Eat();Baboon.Eat();但是,現(xiàn)在來考慮下面的代碼:pMammal-Eat();當pMammal指向不同的對象時,上面的代碼將發(fā)生什么樣的結(jié)果。很顯然,當pMammal指向一個哺乳動物類的實例對象時,上面的代碼將調(diào)用哺乳動物類的Eat方法。但是,當pMammal指向一個人類的實例對象時,上面的代碼是調(diào)用人類的Eat方法呢,還是仍然調(diào)用哺乳動物類的Eat方法?我們期望的是前面一種情況,這就是類和對象的多態(tài)性。我們期望,當pMammal指向不同的實例對象時,編譯器將根據(jù)實例對象的類型調(diào)用正確的Eat方法。在C+中,類的多態(tài)性是通過虛函數(shù)來實現(xiàn)的。就上面的例子來說,我們將Eat方法定義為一個公有的虛函數(shù),這樣,當pMammal指針指向一個人類的實例對象時,編譯器調(diào)用的就是人類的Eat方法,當pMammal指針指向一個狒狒類的實例對象時,編譯器調(diào)用的就是狒狒類的實例對象,從而實現(xiàn)了運行時的多態(tài)。在C+中,多態(tài)定義為不同函數(shù)的同一接口。封裝性、繼承性和多態(tài)性是面向?qū)ο缶幊痰娜筇卣?,則開始的時候,你也許對它們還沒有非常清晰的概念,但這沒有什么關系,當你使用了一段時間的C+語言,然后再回過頭來看這些概念時,你就會發(fā)現(xiàn)對它們有了更深入的認識和了解。事實上,許多的C+程序正是在使用C+語言進行編程已有相當一段時間時才對這三個概念有了正確而清晰的認識的。第二章 Visual c+概述第一節(jié) Win32應用程序設計在過去,進行Windows程序設計是一件痛苦異常的事情,原因是那時候還沒有現(xiàn)在的這些設計精美的應用程序開發(fā)工具。在Microsoft的另一種易學易用的編程工具Visual Basic中,從某種角度說,Windows程序不是編出來的,而是由程序員畫出來的。但是要知道,一個出色的Windows的應用程序并不僅在于在屏幕上繪出程序的各個窗口和在窗口中恰當?shù)陌才琶恳粋€控件。對于具有一定基礎的程序員而言,更重要的內(nèi)容在于知道Windows和Windows應用程序的運行機制,以及它們之間以何種方式來進行通信,然而,明確自己在編寫Windows時所需做的工作是哪一些。換句話說,我們需要透過Windows漂亮的圖形用戶界面,認清在底層所發(fā)生的每一件事情。然而,這并非是一件容易的事。雖然,使用MFC和AppWizard,我們?nèi)钥赡苤恍枰卮饚讉€簡單的問題和添加少數(shù)的幾條代碼就能夠生成功能完整的Windows應用程序。沒有一個成功的商業(yè)軟件是使用這樣的方式生成的。同時,也只有深入的理解了MFC應用程序框架的運行機制,才可能用好和用活這一工具,才能達到熟悉掌握Visual C+的境界。盡管說MFC應用程序框架提供的是面向?qū)ο蟮腤indows編程接口,這和傳統(tǒng)的使用C語言和SDK來進行的Windows應用程序設計有著很大的不同,但是從底層來說,其中的大部分功能仍是通過調(diào)用最基本的Win32 API來實現(xiàn)的。其中最重要的一點是,Windows應用程序的運行機制仍然沒有改變,它們?nèi)匀皇峭ㄟ^消息來和操作系統(tǒng),進而和用戶進行交互的事件驅(qū)動的應用程序。MFC對這一切進行了比較徹底的封裝,它們隱藏在你所看不見的背面。即使你對這一切一無所知,你仍可以在Visual C+中使用MFC來進行程序設計。但是,經(jīng)驗表明,理解這一切的最好的方式是回過頭去,看一看這些內(nèi)容在SDK編寫的應用程序是如何實現(xiàn)的,然后,再看一看在MFC中是如何把它們一層一層的與程序員隔離開的。我們在本節(jié)主要學習Windows應用程序的消息處理機制。一、事件驅(qū)動的應用程序Windows應用程序是事件驅(qū)動(或稱作消息驅(qū)動)的應用程序。Windows是一個多任務的操作系統(tǒng),也就是說,在同一時刻,在Windows中有著多個應用程序的實例正在運行,比如說這時我正在打開字處理軟件Word來編寫這本書的書稿,同時,還打開了Visual C+的集成開發(fā)環(huán)境Microsoft Developer Studio來調(diào)試書中的示例程序,而且,后臺還在放著歌曲。在這樣的一個操作系統(tǒng)中,不可能像過去的DOS那樣,由一個應用程序來享用所有的系統(tǒng)資源,這些資源是由Windows統(tǒng)一管理的。那么,特定的應用程序如何獲得用戶輸入的信息呢?事實上,Windows時刻監(jiān)視著用戶的一舉一動,并分析用戶的動作與哪一個應用程序相關,然后,將用戶的動作以消息的形式發(fā)送給該應用程序,應用程序時刻等待著消息的到來,一但發(fā)現(xiàn)它的消息隊列中有未處理的消息,就獲取并分析該消息,最后,應用程序根據(jù)消息所包含的內(nèi)容采取適當?shù)膭幼鱽眄憫脩羲鞯牟僮鳌Ee一個例子來說明上面的問題,假設我們編了一個程序,該程序有一個File菜單,那么,在運行該應用程序的時候,如果用戶單擊了File菜單,這個動作將被Windows (而不是應用程序本身!)所捕獲,Windows經(jīng)過分析得知這個動作應該由上面所說的那個應用程序去處理,既然是這樣,Windows就發(fā)送了個叫做WM_COMMAND的消息給應用程序,該消息所包含的信息告訴應用程序:“用戶單擊了File菜單”,應用程序得知這一消息之后,采取相應的動作來響應它,這個過程稱為消息處理。Windows為每一個應用程序(確切地說是每一個線程)維護了相應的消息隊列,應用程序的任務就是不停的從它的消息隊列中獲取消息,分析消息和處理消息,直到一條接到叫做WM_QUIT消息為止,這個過程通常是由一種叫做消息循環(huán)的程序結(jié)構來實現(xiàn)的。Windows所能向應用程序發(fā)送的消息多達數(shù)百種,但是,對于一般的應用程序來說,只是其中的一部分有意義,舉一個例子,如果你的應用程序只使用鼠標,那么如WM_KEYUP、WM_KEYDOWN和WM_CHAR等消息就沒有任何意義,也就是說,應用程序中事實上不需要處理這些事件,對于這些事件,只需要交給Windows作默認的處理即可。因此,在應用程序中,我們需要處理的事件只是所有事件中的一小部分。因此,從某種角度上來看,Windows應用程序是由一系列的消息處理代碼來實現(xiàn)的。這和傳統(tǒng)的過程式編程方法很不一樣,編程者只能夠預測用戶所利用應用程序用戶界面對象所進行的操作以及為這些操作編寫處理代碼,卻不可以這些操作在什么時候發(fā)生或者是以什么順序來發(fā)生,也就是說,我們不可能知道什么消息會在什么時候以什么順序來臨。圖3. 1 Windows應用程序的基本流程什么是消息1、消息的組成:一個消息由一個消息名稱(UINT),和兩個參數(shù)(WPARAM,LPARAM)。當用戶進行了輸入或是窗口的狀態(tài)發(fā)生改變時系統(tǒng)都會發(fā)送消息到某一個窗口。例如當菜單轉(zhuǎn)中之后會有WM_COMMAND消息發(fā)送,WPARAM的高字中(HIWORD(wParam))是命令的ID號,對菜單來講就是菜單ID。當然用戶也可以定義自己的消息名稱,也可以利用自定義消息來發(fā)送通知和傳送數(shù)據(jù)。 2、誰將收到消息:一個消息必須由一個窗口接收。在窗口的過程(WNDPROC)中可以對消息進行分析,對自己感興趣的消息進行處理。例如你希望對菜單選擇進行處理那么你可以定義對WM_COMMAND進行處理的代碼,如果希望在窗口中進行圖形輸出就必須對WM_PAINT進行處理。 3、未處理的消息到那里去了:M$為窗口編寫了默認的窗口過程,這個窗口過程將負責處理那些你不處理消息。正因為有了這個默認窗口過程我們才可以利用Windows的窗口進行開發(fā)而不必過多關注窗口各種消息的處理。例如窗口在被拖動時會有很多消息發(fā)送,而我們都可以不予理睬讓系統(tǒng)自己去處理。 4、窗口句柄:說到消息就不能不說窗口句柄,系統(tǒng)通過窗口句柄來在整個系統(tǒng)中唯一標識一個窗口,發(fā)送一個消息時必須指定一個窗口句柄表明該消息由那個窗口接收。而每個窗口都會有自己的窗口過程,所以用戶的輸入就會被正確的處理。例如有兩個窗口共用一個窗口過程代碼,你在窗口一上按下鼠標時消息就會通過窗口一的句柄被發(fā)送到窗口一而不是窗口二。第二節(jié) Visual C+和MFC Visual C+的核心是Microsoft基礎類庫,即通常所說的MFC。盡管使用Visual C+進行編程并不一定要使用MFC,使用MFC也不一定就要使用Visual C+,Borland C+的新版本也提供了對MFC的支持,然而事實上,在很多情況下,我們提到Visual C+時指的就是MFC,而提到MFC時指的也就是Visual C+。MFC相當徹底的封裝了Win32軟件開發(fā)工具包(Software Development Kit,即通常所說的SDK)中的結(jié)構、功能,它為編程者提供了一個應用程序框架,這個應用程序框架為編程者完成了很多Windows編程中的例行性工作,如管理窗口、菜單和對話框,執(zhí)行基本的輸入和輸出、使用集合類來保存數(shù)據(jù)對象等等,并且,MFC使得在程序中使用很多過去很專業(yè)、很復雜的編程課題,如ActiveX、OLE、本地數(shù)據(jù)庫和開放式數(shù)據(jù)庫互聯(lián)ODBC和Internet應用程序設計等,以及其它的應用程序界面特性,如屬性頁(也叫標簽對話框)、打印和打印預覽、浮動的和可定制的工具條變得更加的容易。附表1 MFC類庫層次表第二節(jié) 框架、文檔和視21 文檔類一、 單文檔和多文檔結(jié)構在一個程序中處理多個文檔,稱為多文檔結(jié)構(MDI),例如word和excel,在一個程序中處理一個文檔,成為單文檔結(jié)構(SDI)。如果你的程序適合文檔/視模式,你會發(fā)現(xiàn)使用文檔/視體系的SDI或MDI來創(chuàng)建應用程序會大大簡化工作量。在文檔/視結(jié)構中,文檔用于管理數(shù)據(jù)而視圖用于顯示數(shù)據(jù)并處理用戶的操作。所以數(shù)據(jù)的管理和顯示是分開的。二、 文檔類(CDocument)在文檔/視結(jié)構中,文檔的任務通常是對數(shù)據(jù)進行管理和維護。我們通常將數(shù)據(jù)保存在文檔類的成員變量中。視可以直接或間接的訪問文檔類中的這些成員變量,并通過這種方式來顯示和更新數(shù)據(jù)。文檔還負責將數(shù)據(jù)保存到永久存儲介質(zhì)中。常見的情況是將數(shù)據(jù)保存到磁盤文件或數(shù)據(jù)庫中。在Visual C+的與文檔/視結(jié)構相關的文檔中,我們稱這個過程叫串行化(serialize)。MFC類庫為數(shù)據(jù)的串行化提供了默認的支持,我們只需要在此基礎中稍加修改就可以為自定義的文檔類提供串行化支持。文檔類還可以處理命令消息,這里所謂的命令消息是指來自如菜單、工具欄按鈕和加速鍵的WM_COMMAND通知消息。與Windows消息和控件通知消息不同,命令消息可以被多種對象處理,這些對象除了窗口和視外,還可以是文檔、文檔模板或應用程序本身。除了WM_COMMAND外,文檔不能處理其它的Windows消息。所有的文檔類都以CDocument類為其基類。CDocument類提供了文檔類所需要的最基本的功能實現(xiàn)。更重要的是,CDocument類為文檔對象以及文檔和其它對象(如視對象、應用程序?qū)ο笠约翱蚣艽翱诘?交互的實現(xiàn)提供了一個框架。我們所做的工作基本上是在這個已有框架的基礎上,添加與特定應用程序相關的實現(xiàn)。從CDocument類派生自己的文檔類所需的典型步驟為:1. 為每一個文檔類型從CDocument類(當然也可以是其它CDocument類的派生類)派生一個相應的文檔類。2. 為文檔類添加成員變量。這些成員變量用來保存文檔的數(shù)據(jù),其它對象(如與文檔相關聯(lián)的視)直接或間接的訪問這些成員變量來讀取或更新文檔的數(shù)據(jù)。3. 重載Serialize成員函數(shù),實現(xiàn)文檔數(shù)據(jù)的串行化。如果您的應用程序只使用一種文檔類型,那么,在創(chuàng)建應用程序工程時,AppWizard已為我們完成了一部分工作。典型地,AppWizard為應用程序框架生成一個CDocument類的派生類,在默認情況下該類的命名依賴于工程的名稱。然后,AppWizard在該文檔類中重載了基類的幾個成員函數(shù),包括OnNewDocument和Serialize等。但是,AppWizard在這些重載函數(shù)中只是簡單地調(diào)用基類的相應函數(shù),我們可以根據(jù)自己的需要來修改它們。下面我們來看一個簡單的例子。1. 首先創(chuàng)建一個MFC AppWizard (exe)工程,并取名為Example。如果需要了解如何使用AppWizard創(chuàng)建一個基于文檔/視結(jié)構的多文檔界面應用程序框架。2. 在Workspace窗口的ClassView選項卡中展開Example classes,可以看到AppWizard為Example程序生成的所有類。右擊CExampleDoc類,單擊Add Member Variable.,在Variable Type框中輸入成員變量的類型CString,在Variable Declaration框中輸入成員變量名m_str。由于我們希望其它類的對象可以訪問該成員變量,因此在Access框中選擇其訪問類型為Public。單擊 “OK”,Visual C+將該成員變量的定義添加類的定義中。再按照與上面的過程相同的方法,在類CExampleDoc中添加類型為LOGFONT的公有成員變量m_lf。在類CExampleDoc的定義中包括多個public塊。我們可以把這些定義都放到同一個public塊中,在定義中包括多個public塊只是為了區(qū)別開不同用途的公有成員。3. 為了測試該程序中,我們在CExampleDoc的OnNewDocument成員變量中為公有成員m_str賦以初值 “您好, 歡迎使用本程序!”,并彈出一個字體對話框讓用戶為該字符串選定字體。方法是使用下面的代碼替換OnNewDocument的實現(xiàn)代碼中的/ TODO注釋:m_str=您好, 歡迎使用本程序!;CFontDialog dlg;dlg.GetCurrentFont(&m_lf);/ 將用戶選定的字體信息填充到LOGFONT類型的結(jié)構m_lf中,以供視類使用if(dlg.DoModal()=IDOK)dlg.GetCurrentFont(&m_lf);4.在MFC應用程序中,文檔類是和視類一起協(xié)作以完成應用程序功能的。下面我們將為Example程序的視類CExampleView類的OnDraw成員函數(shù)添加一些代碼,以將文檔類中的m_str成員變量的內(nèi)容顯示到視的框架窗口中。我們用下面的代碼來替換類CExampleView的OnDraw成員函數(shù)。/ 獲取當前客戶區(qū)的大小CRect rectClient;GetClientRect(rectClient);CSize sizeClient=rectClient.Size();/ 從文件中讀取數(shù)據(jù)CExampleDoc* pDoc=(CExampleDoc*) GetDocument();CString str=pDoc-m_str;LOGFONT lf=pDoc-m_lf;/ 使字體充滿整個客戶區(qū)lf.lfHeight=sizeClient.cy;lf.lfWidth=long(sizeClient.cx/str.GetLength();/ 用當前字體信息生成CFont對象CFont *pFont=new CFont;pFont-CreateFontIndirect(&lf);/ 改變當前所用字體,并保存舊字體CFont *pOldFont=pDC-SelectObject(pFont);/ 用新選定的字體繪制字符串 您好, 歡迎使用本程序!CSize sizeTextExtent=pDC-GetTextExtent(str);pDC-TextOut(sizeClient.cx-sizeTextExtent.cx)/2,(sizeClient.cy-sizeTextExtent.cy)/2,str);/ 恢復系統(tǒng)默認字體pDC-SelectObject(pOldFont);在上面的示例程序中,我們在文檔類中定義了兩個公有的成員變量m_str和m_lf,然后在視類的OnDraw成員函數(shù)中訪問了這兩個成員變量,通過這些變量從文檔中獲取所要顯示的字符串和所使用的字體。三、串行化數(shù)據(jù)在Visual C+術語中,我們把對象的保存到磁盤中或從磁盤中讀取對象稱作串行化。串行化的基本觀點是每一個對象都應該能夠?qū)⒆陨淼漠斍皵?shù)據(jù)保存到磁盤中,這些數(shù)據(jù)一般由其成員變量所提供;在需要的時候,對象還應該能夠從磁盤中讀出所保存的數(shù)據(jù),并用這些數(shù)據(jù)來重建該對象。無論是保存文檔或是打開文檔,應用程序都是通過調(diào)用文檔類的Serialize成員函數(shù)來完成串行化操作的。因此,在大多數(shù)情況下,我們都通過重載Serialize成員函數(shù)來實現(xiàn)文檔的串行化。 圖8.7 保存文件時的串行化過 圖8.8 打開文檔時的串行化過程Serialize成員函數(shù)帶有一個CArchive類型的參數(shù),這是一個與所打開的文件相關聯(lián)的對象。一般情況下,我們總是使CArchive對象來保存和打開文檔。例如我們把字體保存入文件中:void CExampleDoc:Serialize(CArchive& ar)if (ar.IsStoring()arm_str;arm_lf.lfHeightm_lf.lfWidthm_lf.lfEscapementm_lf.lfOrientationm_lf.lfWeightm_lf.lfItalicm_lf.lfUnderlinem_lf.lfStrikeOutm_lf.lfCharSetm_lf.lfOutPrecisionm_lf.lfClipPrecisionm_lf.lfQualitym_lf.lfPitchAndFamilym_str;CString lfFaceName;arm_lf.lfHeightm_lf.lfWidthm_lf.lfEscapementm_lf.lfOrientationm_lf.lfWeightm_lf.lfItalicm_lf.lfUnderlinem_lf.lfStrikeOutm_lf.lfCharSetm_lf.lfOutPrecisionm_lf.lfClipPrecisionm_lf.lfQualitym_lf.lfPitchAndFamilylfFaceName;strcpy(m_lf.lfFaceName,lfFaceName);42 視圖類在MFC中視類用于向用戶顯示文檔中的數(shù)據(jù)、以及接受用戶的輸入。MFC提供了很多視圖類,這些類都是基于Cview,這個類提供了使用視極其相關文檔時所必需的功能。一、CViewCView類在整個系統(tǒng)類體系中的位置。圖8.17 類CView的繼承示意圖類CWnd為類CView的直接基類。從這里,我們至少可以得到的一個最基本的概念就是,視類的對象具有窗口的一些基本特性。視類CView是一個用戶定義視類的常用基類。一個視類與一個文檔相連接,在文檔與用戶之間起了一個橋梁的作用。一個視類可以直接地接受文檔的數(shù)據(jù),也可以通過成員函數(shù)的調(diào)用來實現(xiàn)。在視中調(diào)用文檔可以通過GetDocument()函數(shù)實現(xiàn)。當一個類的數(shù)據(jù)發(fā)生變化時,該文檔所關聯(lián)的視類通常通過調(diào)用函數(shù)CDocument:UpdateAllViews來作出響應。這個函數(shù)是維護數(shù)據(jù)正確顯示的常用手段。視類CView具有為數(shù)不多的成員函數(shù)。但這些成員函數(shù)中的很多個是有著重要的意義的。函數(shù)OnBeginPrinting初始化打印,OnEndPrinting結(jié)束一個打印任務,而OnEndPrintPreview則更是關于打印預覽操作的一個重要函數(shù),而函數(shù)OnPreparePrinting則負責了對打印以及打印預覽的全面支持。另外,視類中的兩個成員函數(shù)OnDraw(該函數(shù)在屏幕發(fā)生變化或因為焦點的變易需要重繪時調(diào)用,沒有該函數(shù),就不可能在程序的切換后保證屏幕的正確顯示),OnUpdate則對維護程序的正確顯示負有重要的責任。(當一個文檔發(fā)生變化時,絕大多數(shù)情況下總是希望其各個視圖中的數(shù)據(jù)能得到同步的正確顯示的。)函數(shù)UpdateAllViews則是實現(xiàn)單文檔多視圖程序不可缺少的手段。(在一個文檔的任一視發(fā)生變化時,通過該類實現(xiàn)各視圖的正確顯示。)二、CScrollView:該類為視增加了滾動條。盡管我們?nèi)孕枰谝曋挟嬜约旱膱D形,該類仍可以做許多工作,如:管理窗口和原點、管理映射模式,以及收到滾動條的消息時自動滾動。類CScrollView的繼承層次如圖圖8.22 類CScrollView的繼承圖解三、 CEditView類CEditView主要被設計來支持類似編輯控件所要實現(xiàn)的功能,通過打印,查找/替換的支持。它們擁有自己的內(nèi)存,可以在程序中被任意正確地使用。四、 CRichEditView五、 CtreeView圖8.20 類CTreeView的繼承圖解該類主要提供一些樹型控件所實現(xiàn)的功能的支持。六、 ClistView提供基于列表控件視。七、CFormView和CRecordView類:CFormView提供類似填空形式的視,CRecordView提供支持ODBC的視。例:為上例加上鍵盤處理,由鍵盤輸入的字符加入到屏幕上。因而對類CkeyView進行自定義使它能處理擊鍵。鍵擊消息只有五個(發(fā)往具有當前焦點的窗口),如下所示:WM_KEYDOWN 鍵已按下WM_SYSKEYDOWN 系統(tǒng)鍵被按下WM_KEYUP 鍵已釋放WM_SYSKEYUP 系統(tǒng)鍵已釋放WM_CHAR 轉(zhuǎn)換鍵MFC庫中的視窗函數(shù)OnKeyDown和OnKeyUp按下列方式處理WM_KEYDOWN和WM_KEYUP消息:void OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags);void OnKeyUp(UINT nChar,UINT nRepCnt,UINT nFlags);當程序員表明要處理WM_KEYDOWN和M_KEYUP消息時,Visual C+ 將生成這些函數(shù)的框架。處理鍵盤消息的一個更有效的途徑是處理消息WM_CHAR,即在類View中建立OnChar。void CKeyView:OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) / TODO: Add your message handler code here and/or call defaultCKeyDoc *pDoc=GetDocument();pDoc-data_string+=nChar;/ .CView:OnChar(nChar, nRepCnt, nFlags);CClientDC dc(this);dc.TextOut(0,0,pDoc-data_string,Pdoc-data_string.GetLength());/ .23 在視圖中繪圖一、CView的OnDraw函數(shù)如果在視圖中自己想繪圖,那么通常兩個地方中的一個需要編寫代碼。一個是視圖中ondraw函數(shù)是一個虛函數(shù),這個函數(shù)被主框架調(diào)用顯示文檔。第二個是截獲WM_PAINT消息,處理視圖的OnPaint函數(shù)。OnDraw(CDC* pDC)二、CDC類繪圖工作是基于設備環(huán)境(DC)中進行的。DC包含將要被繪制的設備的信息,以及不同的對象,如畫筆、字體等,并提供了進行繪圖的函數(shù)。DC(Device Context設備環(huán)境)對象是一個抽象的作圖環(huán)境,可能是對應屏幕,也可能是對應打印機或其它。這個環(huán)境是設備無關的,所以你在對不同的設備輸出時只需要使用不同的設備環(huán)境就行了,而作圖方式可以完全不變。這也就是Windows耀眼的一點設備無關性。如同你將對一幅畫使用照相機或復印機將會產(chǎn)生不同的輸出,而不需要對畫進行任何調(diào)整。在MFC中,設備環(huán)境(DC)被封裝在CDC類中,CDC類中包含絕大多數(shù)GDI調(diào)用。實際上,CDC類有兩個設備環(huán)境,m_hDC(用于輸出)和m_hAttribDC(用于屬性查詢)。三、和GDI有關的各種對象在Windows中有各種GDI對象(不要和C+對象混淆),通過使用這幾中對象來影響繪圖效果,當你在進行繪圖就需要利用這些對象。而各種對象都擁有各種屬性,下面分別講述各種GUI對象和擁有的屬性。1 字體對象Cfont用于輸出文字時選用不同風格和大小的字體。可選擇的風格包括:是否為斜體,是否為粗體,字體名稱,是否有下劃線等。顏色和背景色不屬于字體的屬性。關于如何創(chuàng)建和使用字體使用字體時必須首先創(chuàng)建字體。設置字體的顏色和背景是通過調(diào)用CDC的函數(shù)來實現(xiàn)的。SetTextColor()SetBkColor()該類封裝一個Window的圖形設備接口(GDI)字體并且提供了操縱字體的成員函數(shù),要想使用CFont對象,首先要構造一個CFont對象,然后使用成員函數(shù)CreateFont、CreateFontIndirect、CreatePointFont或CreatePointFontIndirect進行初始化,把該對象與Windows字體相連,這樣用戶使可以使用該對象的成員函數(shù)來操縱字體。2 刷子CBrush對象決定填充區(qū)域時所采用的顏色或模板。對于一個固定色的刷子來講它的屬性為顏色,是否采用網(wǎng)格和網(wǎng)格的類型如水平的,垂直的,交叉的等。你也可以利用8*8的位圖來創(chuàng)建一個自定義模板的刷子,在使用這種刷子填充時系統(tǒng)會利用位圖逐步填充區(qū)域。第一個構造函數(shù)構造了一支未被初始化的畫刷,如果用戶使用了該構造函數(shù),則必須對所得到的Brush對象進行初始化。本小節(jié)后面將介紹幾種初始化的方法。其他重裁的構造函數(shù)分別使用指定的顏色、陰影線模式和顏色或位圖指針來構造一支以被初始化的畫刷。如果在調(diào)用過程中遇到錯誤,則會產(chǎn)生一個異常。 下面是對這些構造函數(shù)所用到的參數(shù)的詳細說明: 參數(shù)crColor:以RGB顏色指定畫刷的前景色。如果是表示陰影線的畫刷,定的是陰影線的顏色。 參數(shù)nIndex:指定了畫刷的陰影線的風格,詳細介紹如表18所示。創(chuàng)建畫刷的函數(shù)BOOL CreateSolidBrush(COLORREF crColor);創(chuàng)建以指定顏色填充的實體畫刷BOOL CreateHatchBrush(int index,COLORREF crColor);創(chuàng)建一個陰影填充畫刷,index對應上表的取值BOOL CreatePatternBrush(CBitmap* pBitmap);創(chuàng)建一個用指定位圖填充的畫刷BOOL CreateBrushIndirect(const LPBRUSH lpBrush);創(chuàng)建一個用指定結(jié)構定義參數(shù)的畫刷3畫筆CPen對象在畫點和畫線時有用。它的屬性包括顏色,寬度,線的風格,如虛線,實線,點劃線等。 第一個構造函數(shù)不帶任何參數(shù),由于它所構造的只是一個未初始化的CPen對象,對該對象進行初始化的方法將在本節(jié)后面詳細介紹,另外,該構造函數(shù)總是可以被成功調(diào)用的。不創(chuàng)建筆。需要用其他函數(shù)創(chuàng)建筆。 第二個構造函數(shù)帶有3個參數(shù),分別對畫筆的線形、線寬和顏色進行了初始化。下面分別對其常用的參數(shù)進行介紹: 參數(shù)nPenSty1e:指定畫筆的風格(樣式),也就是畫筆的線形。該參數(shù)該構造函數(shù)中可以為如表15所列值。 參數(shù)nWidth:該參數(shù)指定畫筆的寬度。對于該構造函數(shù),無論什么映射模式,設備單位的寬度總是1個像素。 參數(shù)rColor:包含了一個畫筆所具有的RGB顏色。第三個構造函數(shù)帶有5個參數(shù),下面分別加以介紹: 前3個參數(shù)功能同上,nPenstyle除了具有上一個構造函數(shù)中所介紹的參數(shù)值外,表16所列的參數(shù)值。參數(shù)nWidth;含義基本與上一構造函數(shù)的同一參數(shù)含義相同,區(qū)別在于如果參數(shù)nPenStyle的值為PS_GEOMETRIC,那么該參數(shù)值是針對邏輯單位而言的,并且該參
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年餐飲行業(yè)未簽訂勞動合同現(xiàn)象普遍
- 2024年包裝材料加工機械資金籌措計劃書代可行性研究報告
- 茶館服務流程優(yōu)化考核試卷
- 自動化測試工具使用試題及答案
- 數(shù)字版權運營服務補充協(xié)議
- 珠寶首飾定制設計與售后服務合同
- 影視制作基地電力需求預測及備用電源儲備合同
- 股權質(zhì)押融資業(yè)務合規(guī)審查合同
- 草原牧場放牧經(jīng)營權流轉(zhuǎn)及生態(tài)補償合同
- 電商企業(yè)客服知識庫建設與智能問答系統(tǒng)合同
- 信息安全基礎試題及答案
- 肛瘺護理查房
- T-PPAC 701-2021 企業(yè)商業(yè)秘密管理規(guī)范
- 經(jīng)絡腧穴學試題庫與參考答案
- 2025年保健按摩師(高級)資格認證考試題庫(附答案)
- 2024-2025人教七上數(shù)學26第3章代數(shù)式小結(jié)與復習【教案】
- 評估與反饋機制在教研中的重要性
- 供應商廉潔態(tài)發(fā)言材料
- 字節(jié)跳動經(jīng)營分析報告
- 微信解除保全申請書
- 起重機委托使用協(xié)議書范本
評論
0/150
提交評論