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