第一部分:MFC簡介
Visual C++ 不僅僅是一個編譯器,。它是一個全面的應(yīng)用程序開發(fā)環(huán)境,,使用它你充分利用具有面向?qū)ο筇匦缘?C++ 來開發(fā)出專業(yè)級的 Windows 應(yīng)用程序。為了能充分利用這些特性,,你必須理解 C++ 程序設(shè)計語言,。掌握了C++,你就必須掌握 Microsoft 基本類庫 (MFC) 的層次結(jié)構(gòu),。該層次結(jié)構(gòu)包容了 Windows API 中的用戶界面部分,,并使你能夠很容易地以面向?qū)ο蟮姆绞浇?Windows 應(yīng)用程序。這種層次結(jié)構(gòu)適用于所有版本的 Windows 并彼此兼容,。你用 MFC 所建立的代碼是完全可移植的,。 簡單介紹MFC的基本概念和術(shù)語以及事件驅(qū)動程序設(shè)計方法。輸入,、編譯和運行一個簡單的MFC程序,。第二部分中將詳細(xì)解釋這些代碼。第三部分討論了MFC控件和如何定制它們,。 什么是MFC,? 如果你要建立一個 Windows 應(yīng)用程序,應(yīng)該如何下手,? 好的開端是從設(shè)計用戶界面開始,。首先,你要決定什么樣的用戶能使用該程序并根據(jù)需要來設(shè)置相應(yīng)的用戶界面對象,。Windows 用戶界面有一些標(biāo)準(zhǔn)的控件,,如按鈕、菜單、滾動條和列表等,,這對那些 Windows 用戶已經(jīng)是很熟悉了,。 要記住的是,作為程序員必須選擇一組控件并決定如何把它們安排到屏幕上,。傳統(tǒng)上,,你需要在紙上做一下用戶界面的草圖,直到對各元素感到滿意為止,。這對于一些比較小的項目,,以及一些大項目的早期原型階段是可以的。下一步,,是要實現(xiàn)代碼,。為任何 Windows 平臺建立應(yīng)用程序時,程序員都有兩種選擇:C 或 C++,。 使用 C,,程序員是在 Windows 應(yīng)用程序界面 ( API ) 的水平上編寫代碼。該界面是由幾百個 C 函數(shù)所組成,,這些函數(shù)在Windows API 參考手冊中都有介紹,。對于Windows NT, API 被稱為 "Win32 API",以區(qū)別于其用于Windows 3.1的16位 API, Microsoft 也提供了 C++ 庫,,它位于任何 Windows API 之上,,能夠使程序員的工作更容易。它就是Microsoft基本類庫 (MFC),,該庫的主要優(yōu)點是效率高,。它減少了大量在建立 Windows 程序時必須編寫的代碼。同時它還提供了所有一般 C++ 編程的優(yōu)點,,例如繼承和封裝,。MFC 是可移植的,例如,,在 Windows 3.1下編寫的代碼可以很容易地移植到Windows NT 或 Windows 95 上,。因此,MFC 很值得推薦的開發(fā)Windows 應(yīng)用程序的方法,。在本教程自始至終使用的都是 MFC,。當(dāng)是使用MFC時,你編寫的代碼是用來建立必要的用戶界面控件并定制其外觀,。同時你還要編寫用來響應(yīng)用戶操作這些控件的代碼,。例如,如果用戶單擊一個按鈕時,,你應(yīng)該有代碼來響應(yīng)。這就是事件驅(qū)動代碼,它構(gòu)成了所有應(yīng)用程序,。一旦應(yīng)用程序正確的響應(yīng)了所有允許的控制,,它的任務(wù)也就完成了 。 Visual C++ 應(yīng)用程序開發(fā)程序環(huán)境特別適合于使用 MFC (也有其它開發(fā)環(huán)境使用MFC,,如C++ builder也包含了對MFC的支持),,所以一起學(xué)習(xí) MFC和 Visual C++ 能夠增強你的開發(fā)程序的能力。 Windows應(yīng)用程序使用幾個標(biāo)準(zhǔn)的控件: 靜態(tài)文本標(biāo)簽 按鈕 列表框 組合框(一種更高級的列表框) 單選按鈕 (單選框) 檢查按鈕 (復(fù)選框) 編輯框(單行和多行) 滾動條 你可以通過代碼或"資源編輯器"來建立這些控件,,在資源編輯器中可以建立對話框和這些控件,。在本教程中,我們將使用代碼來建立它們,。 Windows支持幾種類型的應(yīng)用程序窗口,。一個典型的應(yīng)用程序應(yīng)該活動在稱為"框架窗口"中。一個框架窗口是一個全功能的主窗口,,用戶可以改變尺寸,、最小化、最大化等,。Windows也支持兩種類型的對話框:模式和無模式對話框,。模式對話框一旦出現(xiàn)在屏幕上只有當(dāng)它退出時,屏幕上該應(yīng)用程序的其余部分才能響應(yīng),。無模式對話框出現(xiàn)在屏幕上時,,程序的其余部分也可以作出響應(yīng),它就象浮動在上面一樣,。 最簡單的 Windows 應(yīng)用程序是使用單文檔界面(SDI),,只有一個框架窗口。Windows的鐘表,、PIF 編輯器,、記事本等都是 SDI 應(yīng)用程序的例子。Windows 也提供了一種稱為多文檔界面的組織形式,,它可用于更復(fù)雜的應(yīng)用程序,。MDI 系統(tǒng)允許用戶在同一應(yīng)用程序中同時可以查看多個文檔。例如,,一個文本編輯器可以允許用戶同時打開多個文本文件,。使用 MDI時,應(yīng)用程序有一個主窗口,,在主窗口中有一些子窗口,,每個子窗口中各自包含有各自的文檔。在MDI框架中,,主窗口有一個主菜單,,它對主框架中最頂端窗口有效,。各子窗口都可以縮成圖標(biāo)或展開,MDI主窗口也可以變成桌面上的一個圖標(biāo),。MDI界面可能會給你一種第二桌面的感覺,,它對窗口的管理和刪除混亂的窗口有很大的幫助。 你所建立的每一個應(yīng)用程序都會使用它自己的一套控件,、菜單結(jié)構(gòu)以及對話框,。應(yīng)用程序界面的好壞取決于你如何選擇和組織這些界面對象。Visual C++ 中的資源編輯器可以使你能容易的建立和定制這些界面對象,。 事件驅(qū)動軟件和詞匯 所有基于窗口的GUI 都包含相同的基本元素,,它們的操作方式都是相同的。在屏幕上,,用戶所看到的是一組窗口,,每個窗口都包含有控件、圖標(biāo),、對象以及一些處理鼠標(biāo)和鍵盤的元素,。從用戶角度來看,各系統(tǒng)的界面對象都是相同的:按鈕,、滾動條,、圖標(biāo),、對話框以及下拉菜單等等,。盡管這些界面元素的"外觀和感覺"可能有些不同,但這些界面對象的工作方式都是相同的,。例如,,滾動條對于Windows,、Mac和Motif 可能有些不同,但他們的作用完全是一樣的,。 從程序員的角度來看,,這些系統(tǒng)在概念上是相似的,盡管它們可能有很大的不同,。為了建立GUI 程序,,程序員第一步要把所有需要的用戶界面控件都放到窗口上。例如,,如果程序員要建立一個從攝氏到華氏的轉(zhuǎn)換的簡單程序,,則程序員所選擇的用戶界面對象來完成并在屏幕上把結(jié)果顯示出來。在這個簡單的程序中,,程序員可能需要用戶在一個可編輯的編輯框中輸入溫度值,,在一個不可編輯的編輯框中顯示轉(zhuǎn)換結(jié)果,然后讓用戶可以單擊一個標(biāo)有"退出"的按鈕來退出應(yīng)用程序,。 因為是用戶來操作應(yīng)用程序的控制,,所以程序必須作出響應(yīng),。所做的響應(yīng)依賴于用戶使用鼠標(biāo)或鍵盤在不同控制上的操作。屏幕上的每個用戶界面對象對事件的響應(yīng)是不同的,。例如,,如果用戶單擊退出按鈕,,則該按鈕必須更新屏幕,、加亮它自己。然后程序必須響應(yīng)退出,。 Windows 所用的模式也是類似的,。在一個典型的應(yīng)用程序中,你將建立一個主窗口,,并且在其中放置了一些用戶界面控件,。這些控件通常被稱為子窗口--它們就象一些在主窗口中的更小更特殊的子窗口。作為程序員,,你應(yīng)該通過函數(shù)調(diào)用來發(fā)送信息操作這些控件,、通過把信息發(fā)送給你到代碼來響應(yīng)用戶的操作。 如果你從未做過事件驅(qū)動程序設(shè)計,,則所有這些對你來說可能是很陌生的,。但是,事件驅(qū)動程序設(shè)計方式是很容易理解的,。具體的細(xì)節(jié)對不同的系統(tǒng)可能有些不同,,但是其基本概念是類似的。在一個事件驅(qū)動界面中,,應(yīng)用程序會在屏幕上繪制幾個界面對象,,如按鈕、文本區(qū)和菜單,。應(yīng)用程序通常通過一段稱為事件循環(huán)的的代碼來響應(yīng)用戶的操作,。用戶可以使用鼠標(biāo)或鍵盤來任意操作屏幕上的對象。例如,,用戶用鼠標(biāo)單擊一個按鈕,。用鼠標(biāo)單擊就稱為一個事件。事件驅(qū)動系統(tǒng)把用戶的動作如鼠標(biāo)單擊和鍵盤操作定義為事件,,也把系統(tǒng)操作如更新屏幕定義為事件,。 在比較低級的編程方法中,如用C直接編寫Windows API應(yīng)用程序,,代碼量是非常大的,,因為你所要照顧的細(xì)節(jié)太多了。例如,,你用某種類型的結(jié)構(gòu)來接收單擊鼠標(biāo)事件,。你的事件循環(huán)中的代碼會查看結(jié)構(gòu)中不同域,,以確定哪個用戶界面對象受到了影響,然后會完成相應(yīng)的操作,。當(dāng)屏幕上有很多對象時,,應(yīng)用程序會變得很大。只是簡單地處理哪個對象被單擊和對它需要做些什么要花費大量的代碼,。 幸運的是,,你可以在比較高級的方法來進行編程,這就是使用MFC,。在MFC中,,幾乎所有的低級的細(xì)節(jié)處理都為你代辦了。如果你把某一用戶界面對象放在屏幕上,,你只需要兩行代碼來建立它。如果用戶單擊一個按鈕,,則按鈕自己會完成一切必要的操作,,從更新屏幕上的外觀到調(diào)用你程序中的預(yù)處理函數(shù),。該函數(shù)包含有對該按鈕作出相應(yīng)操作的代碼,。MFC 為你處理所有的細(xì)節(jié):你建立按鈕并告知它特定的處理函數(shù),,則當(dāng)它被按下時,,它就會調(diào)用相應(yīng)的函數(shù),。第四部分介紹了怎樣使用消息映射來處理事件。 例子: 理解一個典型的 MFC程序的結(jié)構(gòu)和樣式的最好方法是輸入一段小程序,,然后編譯和運行它,。下面的程序是一段簡單的"hello world"程序,。這對很多C程序員都是很熟悉了,,讓我們看一下如何用MFC 方法來實現(xiàn)。如果你是第一次看到這類程序,,也許比較難理解,。這沒關(guān)系,我們后面會詳細(xì)介紹。現(xiàn)在你只要用Visual C++ 環(huán)境中建立、編譯和運行它就可以了,。 //hello.cpp #include <afxwin.h> // 說明應(yīng)用程序類 class CHelloApp : public CWinApp { public: virtual BOOL InitInstance(); }; // 建立應(yīng)用程序類的實例 CHelloApp HelloApp; // 說明主窗口類 class CHelloWindow : public CFrameWnd { CStatic* cs; public: CHelloWindow(); }; // 每當(dāng)應(yīng)用程序首次執(zhí)行時都要調(diào)用的初始化函數(shù) BOOL CHelloApp::InitInstance() { m_pMainWnd = new CHelloWindow(); m_pMainWnd->ShowWindow(m_nCmdShow); m_pMainWnd->UpdateWindow(); return TRUE; } // 窗口類的構(gòu)造函數(shù) CHelloWindow::CHelloWindow() { // 建立窗口本身 Create(NULL, "Hello World!", WS_OVERLAPPEDWINDOW, CRect(0,0,200,200)); // 建立靜態(tài)標(biāo)簽 cs = new CStatic(); cs->Create("hello world", WS_CHILD|WS_VISIBLE|SS_CENTER, CRect(50,80,150,150), this); } 上面的這段程序如果用C 來實現(xiàn),,得需要幾頁的代碼,。這個簡單的例子做了三件事。第一,,它建立了一個應(yīng)用程序?qū)ο?。你所編寫的每個MFC 程序都有一個單一的程序?qū)ο笫翘幚?MFC 和 Windows 的初始細(xì)節(jié)的,。第二,,應(yīng)用程序建立了一個窗口來作為應(yīng)用程序的主窗口。最后,在應(yīng)用程序的窗口中建立了一個靜態(tài)文本標(biāo)簽,它包含有"hello world"幾個字,。在第二部分中我們會仔細(xì)研究這段程序,,以理解其結(jié)構(gòu)。 建立項目和編譯代碼 為了在 Visual C++ 中編譯代碼,你必須要建立一個項目,。一個項目主要保存著下面三種不同類型的信息: 1.它可以記住建立一個可執(zhí)行程序所需要的所有源程序代碼文件,。在這個簡單的例子中,文件 HELLO.CPP 是唯一的源文件,,但是在一個大型的應(yīng)用程序中,,為了便于管理和維護,,你可以會有許多個不同的源文件。項目會維護這些不同文件的列表,并當(dāng)你要建立下一個新的可執(zhí)行程序時,在必要時編譯它們,。 2.它會記住針對你的應(yīng)用程序所使用的編譯器和連接器選項。例如,,它會記住把哪個庫連接到了執(zhí)行程序中,你是否預(yù)編譯了頭文件等等,。 3.它會記住你想要建立的項目類型: 一個控制臺應(yīng)用程序,或一個窗口應(yīng)用程序等等。如果你已經(jīng)對項目文件有所了解,,則會很容易明白作為機器產(chǎn)生的項目文件的作用。 第二部分:一個簡單的MFC程序 我們將一段一段地來研究提到的 MFC 應(yīng)用程序,,以便能理解它的結(jié)構(gòu)和概念框架,。我們將先介紹 MFC,然后在介紹如何用 MFC 來建立應(yīng)用程序,。 MFC簡介 MFC 是一個很大的,、擴展了的 C++ 類層次結(jié)構(gòu),它能使開發(fā) Windows 應(yīng)用程序變得更加容易,。MFC 是在整個 Windows 家族中都是兼容的,,也就是說,,無論是 Windows3.x、Windows95 還是 Windows NT,,所使用的 MFC 是兼容的,。每當(dāng)新的 Windows 版本出現(xiàn)時,MFC 也會得到修改以便使舊的編譯器和代碼能在新的系統(tǒng)中工作,。MFC 也回得到擴展,,添加新的特性、變得更加容易建立應(yīng)用程序,。 與傳統(tǒng)上使用 C 語言直接訪問 Windows API相反,,使用 MFC 和 C++ 的優(yōu)點是 MFC 已經(jīng)包含和壓縮了所有標(biāo)準(zhǔn)的"樣板文件"代碼,這些代碼是所有用 C 編寫的 Windows 程序所必需的,。因此用 MFC 編寫的程序要比用C語言編寫的程序小得多,。另外,MFC所編寫的程序的性能也毫無損失,。必要時,,你也可以直接調(diào)用標(biāo)準(zhǔn) C 函數(shù),因為 MFC 不修改也不隱藏 Windows 程序的基本結(jié)構(gòu),。 使用 MFC 的最大優(yōu)點是它為你做了所有最難做的事,。MFC 中包含了上成千上萬行正確、優(yōu)化和功能強大的 Windows 代碼,。你所調(diào)用的很多成員函數(shù)完成了你自己可能很難完成的工作,。從這點上將,MFC 極大地加快了你的程序開發(fā)速度,。 MFC 是很龐大的,。例如,版本4.0中包含了大約200個不同的類,。萬幸的是,,你在典型的程序中不需要使用所有的函數(shù)。事實上,,你可能只需要使用其中的十多個 MFC 中的不同類就可以建立一個非常漂亮的程序,。該層次結(jié)構(gòu)大約可分為幾種不同的類型的類: 應(yīng)用程序框架 圖形繪制的繪制對象 文件服務(wù) 異常處理 結(jié)構(gòu) - List、Array 和 Map Internet 服務(wù) OLE 2 數(shù)據(jù)庫 通用類 我們將集中討論可視對象,。下面的列表給出了部分類: CObject CCmdTarget CWinThread CWinApp CWnd CFrameWnd CDialog CView CStatic CButton CListBox CComboBox CEdit CScrollBar 在上面的列表中,有幾點需要注意,。第一,,MFC 中的大部分類都是從基類 CObject 中繼承下來的。該類包含有大部分MFC類所通用的數(shù)據(jù)成員和成員函數(shù),。第二,,是該列表的簡單性,。CWinApp 類是在你建立應(yīng)用程序是要用到的,并且任何程序中都只用一次,。CWnd 類匯集了 Windows 中的所有通用特性,、對話框和控制。CFrameWnd 類是從 CWnd 繼承來的,,并實現(xiàn)了標(biāo)準(zhǔn)的框架應(yīng)用程序,。CDialog 可分別處理無模式和有模式兩種類型的對話框?! View 是用于讓用戶通過窗口來訪問文檔,。最后,Windows 支持六種控制類型:靜態(tài)文本框,、可編輯文本框,、按鈕、滾動條,、列表框和組合框(一種擴展的列表框),。一旦你理解了這些,你也就能更好的理解 MFC 了,。MFC 中的其它類實現(xiàn)了其它特性,,如內(nèi)存管理、文檔控制等,。 為了建立一個MFC應(yīng)用程序,,你既要會直接使用這些類,而通常你需要從這些類中繼承新的類,。在繼承的類中,,你可以建立新的成員函數(shù),這能更適用你自己的需要,。在簡單例子中已經(jīng)看到了這種繼承過程,,下面會詳細(xì)介紹。CHelloApp 和 CHelloWindow 都是從已有的 MFC 類中繼承的,。 設(shè)計一個程序 在討論代碼本身之前,,我們需要花些工夫來簡單介紹以下 MFC 中程序設(shè)計的過程。例如,,假如你要編一個程序來向用戶顯示"Hello World"信息,。這當(dāng)然是很簡單的,但仍需要一些考慮,。 "hello world"應(yīng)用程序首先需要在屏幕上建立一個窗口來顯示"hello world",。然后需要實際把"hello world"放到窗口上。我們需要三個對象來完成這項任務(wù): 1.一個應(yīng)用程序?qū)ο?,用來初始化?yīng)用程序并把它掛到 Windows 上,。該應(yīng)用程序?qū)ο筇幚硭械牡图壥录?2.一個窗口對象來作為主窗口,。 3.一個靜態(tài)文本對象,用來顯示"hello world",。 你用 MFC 所建立的每個程序都會包含頭兩個對象,。第三個對象是針對該應(yīng)用程序的。每個應(yīng)用程序都會定義它自己的一組用戶界面對象,,以顯示應(yīng)用程序的輸出和收集應(yīng)用的輸入信息,。 一旦你完成了界面的設(shè)計,并決定實現(xiàn)該界面所需要的控件,,你就需要編寫代碼來在屏幕上建立這些控件,。你還會編寫代碼來處理用戶操作這些控件所產(chǎn)生的信息。在"hello world"應(yīng)用程序中,,只有一個控件,。它用來輸出"hello world"。復(fù)雜的程序可能在其主窗口和對話框中需要上百個控件,。 應(yīng)該注意,,在應(yīng)用程序中有兩種不同的方法來建立用戶控件。這里所介紹的是用 C++代碼方式來建立控件,。但是,,在比較大的應(yīng)用程序中,這種方法是不可行的,。因此,,在通常情況下要使用資源文件的圖形編輯器來建立控件。這種方法要方便得多,。 理解"hello world"的代碼 下面列出了"hello world"程序的代碼,。 1 //hello.cpp 2 #include <afxwin.h> 3 // Declare the application class 4 class CHelloApp : public CWinApp 5 { 6 public: 7 virtual BOOL InitInstance(); 8 }; 9 // Create an instance of the application class 10 CHelloApp HelloApp; 11 // Declare the main window class 12 class CHelloWindow : public CFrameWnd 13 { 14 CStatic* cs; 15 public: 16 CHelloWindow(); 17 }; 18 // The InitInstance function is called each 19 // time the application first executes. 20 BOOL CHelloApp::InitInstance() 21 { 22 m_pMainWnd = new CHelloWindow(); 23 m_pMainWnd->ShowWindow(m_nCmdShow); 24 m_pMainWnd->UpdateWindow(); 25 return TRUE; 26 } 27 // The constructor for the window class 28 CHelloWindow::CHelloWindow() 29 { 30 // Create the window itself 31 Create(NULL, 32 "Hello World!", 33 WS_OVERLAPPEDWINDOW, 34 CRect(0,0,200,200)); 35 // Create a static label 36 cs = new CStatic(); 37 cs->Create("hello world", 38 WS_CHILD|WS_VISIBLE|SS_CENTER, 39 CRect(50,80,150,150), 40 this); 41 } 該程序由六小部分組成。 首先,,該程序包含了頭文件 afxwin.h (第 2 行),。該頭文件包含有 MFC 中所使用的所有的類型、類,、函數(shù)和變量,。它也包含了其它頭文件,如 Windows API 庫等,。 第 3 至 8 行從 MFC 說明的標(biāo)準(zhǔn)應(yīng)用程序類 CWinApp 繼承出了新的應(yīng)用程序類 CHelloApp,。該新類是為了要重載 CWinApp 中的 InitInstance 成員函數(shù)。InitInstance是一個應(yīng)用程序開始執(zhí)行時要調(diào)用的可重載函數(shù),。 在第10行中,,說明了應(yīng)用程序作為全局變量的一個實例。該實例是很重要的,,因為它要影響到程序的執(zhí)行,。當(dāng)應(yīng)用程序被裝入內(nèi)存并開始執(zhí)行時,全局變量的建立會執(zhí)行CWinApp 類的缺省構(gòu)造函數(shù),。全局變量創(chuàng)建完成后首先執(zhí)行WinMain(),在WinMain()中將調(diào)用在18至26行定義的 InitInstance 函數(shù),。 即: CWinApp::CWinApp() WinMain() { theApp.InitInstance(); theApp.Run(){ While (GetMessage()) DispathMessage; } } 在第11至17中,CHelloWindow 類是從 MFC 中的 CFrameWnd 類繼承來的,。CHelloWindow 是作為應(yīng)用程序在屏幕上的窗口,。建立新的類以便實現(xiàn)構(gòu)造函數(shù)、析構(gòu)函數(shù)和數(shù)據(jù)成員,。 第18至26行實現(xiàn)了 InitInstance 函數(shù),。該函數(shù)產(chǎn)生一個 CHelloWindow 類的實例,因此會執(zhí)行第27行至41行中類的構(gòu)造函數(shù),。它也會把新窗口放到屏幕上,。 第27至41實現(xiàn)了窗口的構(gòu)造函數(shù)。該構(gòu)造函數(shù)實際是建立了窗口,,然后在其中建立一個靜態(tài)文本控制,。 要注意的是,在該程序中沒有 main 或 WinMain 函數(shù),,也沒有事件循環(huán),。然而它實際上處理了事件。窗口可以最大或最小化,、移動窗口等等,。所有這些操作都隱藏在主應(yīng)用程序類 CWinApp 中,并且我們不必為它的事件處理而操心,,它都是自動執(zhí)行,、在 MFC 中不可見的。 程序?qū)ο?br> 用 MFC 建立的每個應(yīng)用程序都要包括一個單一從 CWinApp 類繼承來的應(yīng)用程序?qū)ο?。該對象必須被說明成全局的(第10行),,并且在你的程序中只能出現(xiàn)一次。從 CWinApp 類繼承的對象主要是處理應(yīng)用程序的初始化,,同時也處理應(yīng)用程序主事件循環(huán),。CWinApp 類有幾個數(shù)據(jù)成員和幾個成員函數(shù)。在上面的程序中,,我們只重載了一個 CWinApp 中的虛擬函數(shù) InitInstance,。 應(yīng)用程序?qū)ο蟮哪康氖浅跏蓟涂刂颇愕某绦颉R驗?Windows 允許同一個應(yīng)用程序的多個實例在同時執(zhí)行,,因此 MFC 把初始化過程分成兩部分并使用兩個函數(shù) InitApplication 和 InitInstance 來處理它,。此處,我們只使用了一個 InitInstance 函數(shù),,因為我們的程序很簡單,。當(dāng)每次調(diào)用應(yīng)用程序時都會調(diào)用一個新的實例,。第3至8行的代碼建立了一個稱為 CHelloApp 的類,它是從 CWinApp 繼承來的,。它包含一個新的 InitInstance 函數(shù),,是從 CWinApp 中已存在的函數(shù)(不做任何事情)重載來的: 3 // Declare the application class 4 class CHelloApp : public CWinApp 5 { 6 public: 7 virtual BOOL InitInstance(); 8 }; 在重載的 InitInstance 函數(shù)內(nèi)部,第18至26行,,程序使用 CHelloApp 的數(shù)據(jù)成員 m_pMainWnd 來建立并顯示窗口: 18 // The InitInstance function is called each 19 // time the application first executes. 20 BOOL CHelloApp::InitInstance() 21 { 22 m_pMainWnd = new CHelloWindow(); 23 m_pMainWnd->ShowWindow(m_nCmdShow); 24 m_pMainWnd->UpdateWindow(); 25 return TRUE; 26 } InitInstance 函數(shù)返回 TRUE 表示初始化已成功的完成,。如果返回了FALSE,則表明應(yīng)用程序會立即終止,。在下一節(jié)中我們將會看到窗口初始化的詳細(xì)過程,。 當(dāng)應(yīng)用程序?qū)ο笤诘?0行建立時,它的數(shù)據(jù)成員(從 CWinApp 繼承來的) 會自動初始化,。例如,,m_pszAppName、m_lpCmdLine 和 m_nCmdShow 都包含有適當(dāng)?shù)某跏蓟?。你可參?MFC 的幫助文件來獲得更詳細(xì)的信息,。我們將使用這些變量中的一個。 窗口對象 MFC 定義了兩個類型的窗口: 1) 框架窗口,,它是一個全功能的窗口,,可以改變大小、最小化,、最大化等等; 2) 對話框窗口,,它不能改變大小??蚣艽翱谑堑湫偷闹鲬?yīng)用程序窗口,。 在下面的代碼中,從 CFrameWnd 中繼承了一個新的類 CHelloWindow: 11 // Declare the main window class 12 class CHelloWindow : public CFrameWnd 13 { 14 CStatic* cs; 15 public: 16 CHelloWindow(); 17 }; 它包括一個新的構(gòu)造函數(shù),,同時還有一個指向程序中所使用的唯一用戶界面控制的數(shù)據(jù)成員,。你多建立的每個應(yīng)用程序在主窗口中都會有唯一的一組控制。因此,,繼承類將有一個重載的構(gòu)造函數(shù)以用來建立主窗口所需要的所有控制,。典型情況下,該類會包含有一個析構(gòu)函數(shù)以便在窗口關(guān)閉時來刪除他們,。我們這里沒有使用析構(gòu)函數(shù),。在第四講中,我們將會看到繼承窗口類也會說明一個消息處理函數(shù)來處理這些控制在響應(yīng)用戶事件所產(chǎn)生的消息,。 典型地,,一個應(yīng)用程序?qū)⒂幸粋€主應(yīng)用程序窗口。因此,CHelloApp 應(yīng)用程序類定義了一個名為 m_pMainWnd 成員變量來指向主窗口,。為了建立該程序的主窗口,,InitInstance函數(shù)(第18至26行)建立了一個 CHelloWindow 事例,并使用 m_pMainWnd 來指向一個新的窗口,。我們的 CHelloWindow 對象是在第22行建立的: 18 // The InitInstance function is called each 19 // time the application first executes. 20 BOOL CHelloApp::InitInstance() 21 { 22 m_pMainWnd = new CHelloWindow(); 23 m_pMainWnd->ShowWindow(m_nCmdShow); 24 m_pMainWnd->UpdateWindow(); 25 return TRUE; 26 } 只建立一個簡單的框架窗口是不夠的,。還要確保窗口能正確地出現(xiàn)在屏幕上。首先,,代碼必須要調(diào)用窗口的 ShowWindow 函數(shù)以使窗口出現(xiàn)在屏幕上(第23行)。其次,,程序必須要調(diào)用 UpdateWindow 函數(shù)來確保窗口中的每個控制和輸出能正確地出現(xiàn)在屏幕上(第24行),。 ShowWindow 和 UpdateWindow 函數(shù)是在哪兒定義的。ChelloWindow繼承于CFrameWnd ,。但是 CFrameWnd 中并不包含有這些成員函數(shù),。CFrameWnd 是從 CWnd 類繼承來的。CWnd包含有200多個不同的成員函數(shù),,包括ShowWindow 和UpdateWindow,。 ShowWindow 只有一個參數(shù),可以設(shè)置不同的參數(shù)值,。我們把它設(shè)置成程序中CHelloApp 的數(shù)據(jù)成員變量 m_nCmdShow (第23行),。m_nCmdShow 變量是用來初始化應(yīng)用程序啟動的窗口顯示方式的。例如,,用戶可能在程序管理器中啟動應(yīng)用程序,,并可通過應(yīng)用程序?qū)傩詫υ捒騺砀嬷绦蚬芾砥鲬?yīng)用程序在啟動時要保持最小化狀態(tài)。m_nCmdShow 變量將被設(shè)置成 SW_SHOWMINIMIZED,,并且應(yīng)用程序會以圖標(biāo)的形式來啟動,,也就是說,程序啟動后,,是一個代表該程序的圖標(biāo),。m_nCmdShow 變量是一種外界與應(yīng)用程序通訊的方式。 第22行是初始化窗口,。它為調(diào)用 new 函數(shù)分配內(nèi)存,。在這一點上,程序在執(zhí)行時會調(diào)用CHelloWindow的構(gòu)造函數(shù),。該構(gòu)造函數(shù)在每次該類的實例被分配時都要調(diào)用,。在窗口構(gòu)造函數(shù)的內(nèi)部,窗口必須建立它自己,。它是通過調(diào)用 CFrameWnd 的 Create 成員函數(shù)來實現(xiàn)的(第31行): 27 // The constructor for the window class 28 CHelloWindow::CHelloWindow() 29 { 30 // Create the window itself 31 Create(NULL, 32 "Hello World!", 33 WS_OVERLAPPEDWINDOW, 34 CRect(0,0,200,200)); 建立函數(shù)共傳遞了四個參數(shù),。通過查看 MFC 文檔,可以了解不同類型。NULL 參數(shù)表示使用缺省的類名,。第二個參數(shù)為出現(xiàn)在窗口標(biāo)題欄上的標(biāo)題,。第三個參數(shù)為窗口的類型屬性。該程序使用了正常的,、可覆蓋類型的窗口,。第四個參數(shù)指出窗口應(yīng)該放在屏幕上的位置和大小,左上角為(0,0), 初始化大小為 200×200個象素,。如果使用了 rectDefault,,則 Windows 會為你自動放置窗口及大小。 靜態(tài)文本控制 程序在從 CFrameWnd 類中繼承 CHelloWindow 類時(第11至17行)時,,說明了一個成員類型 CStatic及其構(gòu)造函數(shù),。 正如在前面所見到的,CHelloWindow 構(gòu)造函數(shù)主要做兩件事情,。第一是通過調(diào)用Create函數(shù)(第31行)來建立應(yīng)用程序的窗口,。然后分配和建立屬于窗口的控制。在程序中,,只使用了一個控制,。在 MFC 中建一個對象總要經(jīng)過兩步。第一是為類的實例分配內(nèi)存,,然后是調(diào)用構(gòu)造函數(shù)來初始化變量,。下一步,調(diào)用 Create 函數(shù)來實際建立屏幕上的對象,。代碼使用這兩步分配,、構(gòu)造和建立了一個靜態(tài)文本對象(第36至40行): 27 // The constructor for the window class 28 CHelloWindow::CHelloWindow() 29 { 30 // Create the window itself 31 Create(NULL, 32 "Hello World!", 33 WS_OVERLAPPEDWINDOW, 34 CRect(0,0,200,200)); 35 // Create a static label 36 cs = new CStatic(); 37 cs->Create("hello world", 38 WS_CHILD|WS_VISIBLE|SS_CENTER, 39 CRect(50,80,150,150), 40 this); 41 } CStatic 構(gòu)造函數(shù)是在為其分配內(nèi)存時調(diào)用的,然后就調(diào)用了 Create 函數(shù)來建立 CStatic 控制的窗口,。Create 函數(shù)所使用的參數(shù)與窗口建立函數(shù)所使用的參數(shù)是類似的(第31行),。第一個參數(shù)指定了控制中所要顯示的文本內(nèi)容。第二個參數(shù)指定了類型屬性,。類型屬性在下一講中將詳細(xì)介紹,。在次我們使用的是子窗口類型(既在別的窗口中顯示的窗口),還有它是可見的,,還有文本的顯示位置是居中的,。第三個參數(shù)決定了控制的大小和位置。第四參數(shù)表示該子窗口的父窗口,。已經(jīng)建立了一個靜態(tài)控制,,它將出現(xiàn)在應(yīng)用程序窗口上,并顯示指定的文本,。 第三部分:MFC中控件的樣式 控件是用來建立Windows應(yīng)用程序用戶界面的用戶界面對象,。你所見到的大部分Windows應(yīng)用程序和對話框只不過是由一些控件所組成的、用來實現(xiàn)程序功能的東西。為了建立有效的應(yīng)用程序,,你必須完全理解在Windows應(yīng)用程序中應(yīng)該如何合理的使用控件,。有六個基本的控件:CStatic、CButton,、CEdit,、CList、CComboBox和CScrollBar,。另外,,Windows 95又增加了增強了的控件。你需要理解的是那個控件能做些什么,、你應(yīng)該如何控制它的外表和行為以及如何讓控件能響應(yīng)用戶事件,。只要掌握了這些,再加上掌握了菜單和對話框,,你就可以建立你所想象的任何Windows應(yīng)用程序。你可以用程序代碼來建立控件,,也可以使用資源編輯器通過資源文件來建立,。當(dāng)然,對話框編輯器更方便些,,它對于已經(jīng)基本掌握了控件的情況下特別有用,。 下面以CStatic控件為例來說明控件的使用。 最簡單的控件是CStatic, 它是用來顯示靜態(tài)文本的,。CStatic類沒有任何數(shù)據(jù)成員,,它只有少量的成員函數(shù):構(gòu)造函數(shù)、Create函數(shù)(用于獲取和設(shè)置靜態(tài)控制上的圖標(biāo))等等,。它不響應(yīng)用戶事件,。因為它的簡單性,所以最好把它作為學(xué)習(xí)Windows控件的開端,。 MFC中的CStatic類是用來顯示靜態(tài)文本信息的,。這些信息能夠可以作為純信息(例如,顯示在信息對話框中的錯誤消息), 或作為小的標(biāo)簽等,。 CStatic控件還有幾種其它的顯示格式,。你可以通過修改標(biāo)簽的樣式來使它表現(xiàn)為矩形、邊框或圖標(biāo)等,。 CStatic控件總是作為子窗口的形式出現(xiàn)的,。典型情況下,其父窗口是應(yīng)用程序的主窗口或?qū)υ捒?。正如上一講所介紹的,,用兩行代碼就可以建立一個靜態(tài)控件: CStatic *cs; .... cs = new CStatic(); cs->Create("hello world", WS_CHILD|WS_VISIBLE|SS_CENTER, CRect(50,80, 150, 150), this); 這兩行代碼是典型的MFC建立所有控件的代碼。調(diào)用new來為CStatic類的實例分配內(nèi)存,然后調(diào)用類的構(gòu)造函數(shù),。構(gòu)造函數(shù)是用來完成類所需要的初始化功能的,。Create函數(shù)建立控件并把它放到屏幕上。 Create函數(shù)有五個參數(shù): lpszText指定了要顯示的文本,。rect控件文本區(qū)域的位置,、大小和形狀。pParentWnd指明CStatic控件的父窗口,。該控件會出現(xiàn)在其父窗口中,,且其位置是相對于其父窗口的用戶區(qū)域而言的。nID整數(shù)值,,表示該控件的標(biāo)識符,。dwStyle最重要的參數(shù)。它控制著控件的外觀和行為,。 CStatic樣式 所有的控件都有各種顯示樣式,。樣式是在用Create函數(shù)建立控件時傳遞給它的dwStyle參數(shù)所決定的。對CStatic有效的樣式簡介如下: 從CWnd繼承來的樣式: WS_CHILD CStatic所必須的,。 WS_VISIBLE 表示該控件對用戶應(yīng)該是可見的,。 WS_DISABLED 表示該控件拒絕接受用戶事件。 WS_BORDER 控件的文本區(qū)域帶有邊框,。 CStatic固有的樣式: SS_BLACKFRAME 該控件區(qū)域以矩形邊界顯示,。顏色與窗口框架相同。 SS_BLACKRECT 該控件以填充的矩形顯示,。顏色與當(dāng)前的窗口框架相同,。 SS_CENTER 文本居中。 SS_GRAYFRAME 控件以矩形邊框方式顯示,。顏色與當(dāng)前桌面相同,。 SS_GRAYRECT 該控件以填充的矩形顯示。顏色與當(dāng)前的桌面相同,。 SS_ICON 控件以圖標(biāo)形式顯示,。文本作為圖標(biāo)在資源文件的名稱。rect參數(shù)只控制位置,。 SS_LEFT 文本居左顯示,。文字可回繞。 SS_LEFTNOWORDWRAP 文本居左顯示,。多余的文字被剪裁,。 SS_NOPREFIX 表示字符串中的"&"字符不表示為加速前綴。 SS_RIGHT 文本居右顯示,。文字可回繞,。 SS_SIMPLE 只簡單的顯示一行文本,。任何CTLCOLOR信息都被其父窗口忽略。 SS_USERITEM 用戶定義項,。 SS_WHITEFRAME 控件以矩形邊框方式顯示,。顏色與當(dāng)前窗口背景顏色相同。 SS_WHITERECT 控件以填充矩形方式顯示,。顏色與當(dāng)前窗口背景顏色相同,。 這些常數(shù)中,"SS"(Static Style)開頭的表示只能用于CStatic控件,。以"WS"(Window Style)開頭的常數(shù)表示可適用于所有窗口,,它們定義在CWnd對象中。CWnd中還有很多以"WS"樣式常數(shù),??梢栽贛FC文檔中的CWnd::Create函數(shù)中找到它們。上面的四種是只用于CStatic對象的,。 CStatic對象至少要帶有兩個樣式:WS_CHILD和WS_VISIBLE,。該控件必須作為另一窗口的子窗口來建立。如果不使用WS_VISIBLE,,則所建立的控件是看不見的,。WS_DISABLED控制著標(biāo)簽對事件的響應(yīng),因為CStatic不接收鍵盤或鼠標(biāo)事件,,所以使用該項是多余的。 所有的其它樣式選項都是可選的,,它們控制著標(biāo)簽的外觀,。在CStatic::Create函數(shù)中使用這些可以控制CStatic在屏幕上的顯示。 對話框: 對話框可分為"模式"和"無模式"兩類:模式對話框如Open File對話框,,在該對話框被關(guān)閉之前,,用戶無法在同一應(yīng)用程序(更確切地說,似乎在同一用戶接口線程里)的其他地方進行工作,;而對于無模式對話框如Word中的Find and Replace對話框,,在它仍然保留在屏幕上的同時,用戶還可以在應(yīng)用程序的其他窗口中進行工作,。這兩類對話框的基類都為CDialog,,下面分別就在應(yīng)用程序中使用模式和無模式對話框作些說明。 模式對話框的使用: 1,、利用對話框編輯器創(chuàng)建包含各種空間的對話框資源,。 2、利用ClassWizard來創(chuàng)建CDialog的派生類,。ClassWizard將會生成對話框代碼文件: CMyDialog::CMyDialog(CWnd * pParent) :CDialog(CMyDialog::IDD,pParent) { } 3,、在對話框代碼文件中編寫應(yīng)用所需要的函數(shù),。 4、編輯視圖類,,通過 { CMyDialog myDlg; myDlg.DoModal(); } 來激活該對話框,。 其中DoModal()的處理過程如下: CDialog::DoModal() CMyDialog::OnInitDialog() ...其他初始化... CDialog::OnInitDialog CWnd::UpdateData(false) CMyDialog::DoDataExchange() 用戶數(shù)據(jù)輸入... 用戶單擊OK按扭 CMyDialog::OnOk() ...其他的確認(rèn)處理... CDialog::OnOK() CWnd::UpdateData(TRUE) CMyDialog::DoDataExchange() CDialog::EndDialog(IDOK) {注:層次的遞進表示函數(shù)的調(diào)用關(guān)系) 無模式對話框的使用: 1、利用對話框編輯器創(chuàng)建包含各種空間的對話框資源,。 2,、利用ClassWizard來創(chuàng)建CDialog的派生類。ClassWizard將會生成對話框代碼文件: CMyDialog::CMyDialog(CWnd * pParent) :CDialog(CMyDialog::IDD,pParent) { }//該構(gòu)造函數(shù)是創(chuàng)建模式對話框所用,; 3,、在對話框代碼文件中的模式對話框構(gòu)造函數(shù)修改成無模式對話框的構(gòu)造函數(shù) CMyDialog::CMyDialog(CView * pView) { } 及其他需要的函數(shù)。 4,、在視圖類中通過 { CMyDialog *pDlg=new CMyDialog(this); myDlg.Create(IDD); }來激活無模式對話框,。 兩者的比較(不同點): 1、使用的構(gòu)造函數(shù):模式對話框-->以資源ID作為參數(shù)的構(gòu)造函數(shù),;無模式對話框-->默認(rèn)構(gòu)造函數(shù)(無參數(shù)). 2,、建立窗口的函數(shù):模式對話框-->DoModal();無模式對話框-->Create(IDD). 3、刪除窗口(即終止)的函數(shù):模式對話框-->EndDialog();無模式對話框-->DestroyWindow(). 注:CDialog::OnOK()和OnCancel()的實現(xiàn)是調(diào)用EndDialog(),所以無模式對話框中應(yīng)該重載OnOK()及OnCancel()函數(shù),,加入DestroyWindow()以便刪除窗口,。 4、正確刪除對話框?qū)ο螅ㄗ⒁獠煌趯υ捒虼翱趯ο螅?br> 模式對話框-->在視圖類中DoModal()返回后即可刪除對話框?qū)ο?;無模式對話框-->視圖類并不知道對話框何時該刪除,,故應(yīng)該通過CMyDialog::PostNcDestroy ( ){delete this;}來刪除該對象。該函數(shù)在窗口撤消時被應(yīng)用程序框架調(diào)用,。 菜單: 菜單欄包含在主框架窗口(MainFrame)中,,基類為CMenu.通常有兩種應(yīng)用。應(yīng)用一:創(chuàng)建主菜單的使用步驟: 1,、利用資源編輯器來編輯菜單,。可以加入一個分隔符,,可以為菜單項添加快捷鍵和鍵盤加速鍵以及在狀態(tài)欄中顯示提示字符串等屬性,。 2、利用ClassWizard為視圖類增加命令消息(COMMAND)控制函數(shù)和更新命令UI消息(Update_COMMAND_UI)控制函數(shù),。每一菜單項都有一個ID,,即命令I(lǐng)D,只有當(dāng)該ID在0x8000-0xDFFF范圍內(nèi),才能夠發(fā)送COMMAND消息,。當(dāng)我們選中某一菜單項時,,將會執(zhí)行相應(yīng)的命令消息控制函數(shù);每當(dāng)彈出式菜單第一次顯示時,,都會調(diào)用更新命令用戶界面(UI)控制函數(shù),。更新命令UI控制函數(shù)可以用來對菜單項的顯示進行修改,,但是注意只適用于彈出式菜單的菜單項,而對長久顯示的頂層菜單項則不適用,。 MFC中,,應(yīng)用程序框架提供了一個命令消息傳遞系統(tǒng)。當(dāng)應(yīng)用程序框架接受到框架窗口命令時,,它將按如下次序來尋找相應(yīng)的消息控制函數(shù): SDI應(yīng)用程序:視圖-->文檔-->SDI主框架窗口-->應(yīng)用程序 MDI應(yīng)用程序:視圖-->文檔-->MDI子框架窗口-->MDI主框架窗口-->應(yīng)用程序 所以,,我們幾乎在程序中的任何地方對消息進行控制。如果某菜單項在當(dāng)前命令傳遞路徑中無法找到相應(yīng)的命令消息控制函數(shù),,則此時應(yīng)用程序框架就可以禁用該菜單項,。但如果我們將CFrameWnd的數(shù)據(jù)成員m_bAutoMenuEnable置成了FALSE,那么我們可以禁用這一特性。 3,、當(dāng)主框架窗口的Create()或LoadFrame()被調(diào)用時,,菜單的資源都被直接連到了框架窗口中,因此,,我們不必另外專門創(chuàng)建CMenu對象,。我們可以通過CWnd的GetMenu()來返回一個CMenu對象的指針,通過該指針來對菜單對象進行訪問和更新,。 我們也可以動態(tài)創(chuàng)建菜單,,方法如下: { CMenu menu; menu.LoadMenu(IDR_MYMENU)//菜單的ID;將菜單從資源中裝入; menu.SetMenu();//將菜單連到框架窗口中,; ...... menu.Detach();//將menu對象與菜單獨立出來,,這樣menu對象生存期 //結(jié)束后該菜單依然在內(nèi)存中。 } 應(yīng)用二:創(chuàng)建浮動的彈出式菜單 1,、利用資源編輯器來編輯菜單,。 2、利用ClassWizard編輯菜單項的命令控制函數(shù),。 3、在視圖類中編輯WM_CONTEXTMENU消息控制函數(shù)(當(dāng)鼠標(biāo)右鍵彈起時發(fā)送此消息),。 void CMyView::OnContextMenu(CWnd *pWnd,CPoint point) { CMenu menu; menu.LoadMenu(IDR_MYMENU); menu.GetSubMenu(0)->TrackPopupMenu (TPM_LEFTALLGN|TPM_RIGHTBUTTON,point.x,point.y,this); //顯示浮動彈出菜單,; } MFC中的文檔和視圖的關(guān)系 文檔對象是用來保存程序運行過程中所使用的數(shù)據(jù)的,視圖對象是用來顯示數(shù)據(jù)的,,并且允許用戶對數(shù)據(jù)進行編輯,,編輯的結(jié)果應(yīng)該再存儲在文檔對象中。 1.應(yīng)用程序類: WINDOWS應(yīng)用程序的初始化,、運行和結(jié)束都是由應(yīng)用程序類完成的,。應(yīng)用程序類構(gòu)成了應(yīng)用程序執(zhí)行的主線程。每個MFC程序有且僅有一個從CwinApp類派生的類對象,。如CsampleApp theApp,。 2.文檔模板: 應(yīng)用程序?qū)ο笫褂梦臋n模板存放與應(yīng)用程序文檔,、視圖和邊框窗口有關(guān)的信息。應(yīng)用程序使用文檔模板創(chuàng)建文檔類對象來存放文檔,,創(chuàng)建邊框窗口類對象來畫出視圖窗口,,創(chuàng)建視圖類對象來顯示文檔,多個視圖類對象可以共享一個邊框窗口類對象,。文檔類,,視圖類和邊框窗口類之間的關(guān)系由文檔模板管理。 在應(yīng)用程序類的InitInstance函數(shù)中創(chuàng)建并注冊文檔模板: BOOL CsampleApp::InitInstance() { CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CsampleDoc), RUNTIME_CLASS(CMainFrame), // main SDI frame window RUNTIME_CLASS(CsampleView)); AddDocTemplate(pDocTemplate); return TRUE; } 傳給CsingleDocTemplate構(gòu)造函數(shù)的第一個參數(shù)是資源符號IDR_MAINFRAME,,該資源包含邊框的圖標(biāo)和選單等,,傳給CsingleDocTemplate構(gòu)造函數(shù)的其余三個參數(shù)是對RUNTIME_CLASS宏的調(diào)用,每次調(diào)用都返回指定類的信息,,從而使應(yīng)用程序可以動態(tài)的創(chuàng)建該類的一個實例,,即返回一個指向參數(shù)類的對象的指針。AddDocTemplate注冊文檔模板對象,,將文檔模板存放在應(yīng)用程序?qū)ο笾小?br> 3.文檔和視圖的關(guān)系: 在創(chuàng)建MFC的應(yīng)用程序的框架時,,AppWizard為應(yīng)用程序創(chuàng)建文檔和視圖類的基本結(jié)構(gòu)。由AppWizard創(chuàng)建的文檔類是從CDocument 類派生的,,視圖類是從CView類派生的,。CDocument類為應(yīng)用程序定義的文檔類提供基本功能,而CView類為應(yīng)用程序定義的視圖類提供基本功能,。視圖是與文檔聯(lián)系在一起的,,在文檔與用戶之間起中介作用。視圖在屏幕上顯示文檔數(shù)據(jù)并把用戶輸入轉(zhuǎn)換成對文檔的操作,。MFC中文檔與視圖的這種實現(xiàn)方法把數(shù)據(jù)與數(shù)據(jù)的顯示以及用戶對數(shù)據(jù)所作的操作分離開來,。數(shù)據(jù)的所有更改都通過文檔類管理,而視圖則調(diào)用這個接口來訪問和更新數(shù)據(jù),。視圖類對象可以通過CsampleDoc* CsampleView::GetDocument() 函數(shù)得到其所屬的文檔對象的指針,,以對文檔的數(shù)據(jù)進行操作。 文檔用于管理應(yīng)用程序的數(shù)據(jù),,使用方法如下: ?。?) 從CDocument類派生出各種不同類型的文檔類,每種類型對應(yīng)一種文檔,。 ?。?) 添加用于存儲文檔數(shù)據(jù)的成員變量。 ?。?) 根據(jù)需要重載CDocument類的其他成員函數(shù),。 視圖以圖形方式顯示文檔數(shù)據(jù)、接受用戶輸入并將其解釋成對文檔的操作: ?。?) 處理視圖類的OnDraw成員函數(shù),,該函數(shù)負(fù)責(zé)提供文檔數(shù)據(jù),。調(diào)用函數(shù)GetDocument()得到文檔數(shù)據(jù)。 ?。?) 映射并實現(xiàn)消息處理函數(shù),,以便解釋用戶的輸入。 ?。?) 根據(jù)需要重載CView類的其他成員函數(shù),。如:重載OnInitialUpdate,以便進行必要的視圖初始化工作,,重載OnUpdate,,以便在視圖即將重新繪制前進行必要的處理。 應(yīng)用程序可以是單文檔或多文檔,,每個文檔可以有單個或多個視圖,,但一個視圖只隸屬于一個文檔。最簡單的應(yīng)用是單文檔單視圖的,,MFC也支持單文檔多視圖,。每個文檔對象保存有該文檔的視圖列表,并提供用于添加和刪除視圖的成員函數(shù),,以及在文檔數(shù)據(jù)發(fā)生變化時提供UpdateAllView成員函數(shù)來更新所有視圖,。單文檔程序中主邊框窗口和文檔邊框窗口重合,合二為一,。多文檔程序中主邊框窗口中有客戶窗口,,客戶窗口中又包含多個文檔邊框窗口。 MFC支持以下三種多視圖模式: ?。?) 同一文檔的多個視圖對象,,每個對象置于獨立的文檔邊框窗口中。 ?。?) 同一文檔邊框窗口中有同一文檔的多個視圖對象,。如分割窗口。 ?。?) 單個文檔邊框窗口中有不同類的視圖對象,,多個視圖共享單個邊框窗口,每個視圖從不同的類構(gòu)造,。 4.MFC中各對象之間的關(guān)系: ?。?) 文檔中含有該文檔的視圖列表和指向創(chuàng)建該文檔的文檔模板的指針,。 ?。?) 視圖中含有指向文檔的指針,視圖窗口是文檔邊框窗口的子窗口,。 ?。?) 文檔邊框窗口含有指向當(dāng)前活動視圖的指針,。 (4) 文檔模板含有已打開文檔的一個列表,。 ?。?) 應(yīng)用程序?qū)ο蠛形臋n模板的一個列表 (6) Windows跟蹤所有已打開的窗口并發(fā)送消息給這些窗口,。 通過調(diào)用AfxGetApp,任何對象都可以獲得指向應(yīng)用程序?qū)ο蟮闹羔槨?br> 各對象之間的訪問方法: 文檔:調(diào)用GetFirstViewPosition和GetNextView函數(shù)訪問文檔的視圖列表,。調(diào)用GetDocTemplate函數(shù)獲取創(chuàng)建該文檔的文檔模板的指針。 視圖:調(diào)用GetDocument函數(shù)獲取指向文檔的指針,。調(diào)用GetParentFrame函數(shù)獲取指向文檔邊框窗口的指針,。 文檔邊框窗口:調(diào)用GetActiveView函數(shù)獲取當(dāng)前視圖。調(diào)用GetActiveDocument函數(shù)獲取當(dāng)前視圖的文檔,。 MDI主邊框窗口:調(diào)用MDIGetActive函數(shù)獲取當(dāng)前活動的MDI子窗口,。 |
|