一個簡單的MFC應用程序
在現在的"面向對象"程序設計中,我們經常會聽說過"類"和"對象"的概念。那麼什麼是"類"呢?"類"的實質上是一種新的復雜數據類型。說它"新",是因為它不同於C語言中的char、int、float等基本數據類型,說它"復雜",是因為它不僅可以包含各種基本類型的數據,而且還可以包含處理這些數據的函數。
MFC使用"類"來編寫Windows應用程序,例如下面的過程:
(1) 單擊"開始"頁面中的"新建項目",或者打開"文件"菜單中的"新建",選擇"項目"命令,都將彈出"新建項目"對話框。
(2) 在左側的"項目類型"窗格中,選中"Visual C++項目"。在右側的"模板"窗格中,拖動窗格右側的滾動條顯示其他模板,然後選中"Win32 項目"。
(3) 在"名稱"文本框中,輸入項目名稱"Ex_1_SimpMFC",單擊"確定"按鈕,彈出"Win32 應用程序向導"對話框。
(4) 單擊左側的"應用程序設置"。選中"應用程序類型"中的"Windows 應用程序",在"附加選項"中選中"空項目",結果如圖1所示,單擊"完成"按鈕。
圖1 Win32 應用程序設置
(5) 在"解決方案資源管理器"中,右擊項目名稱Ex_1_SimpMFC,從彈出的快捷菜單中選擇"添加",然後選擇"添加新項",彈出"添加新項"對話框。
(6) 在右側的"模板"窗格中選中"C++文件",在"名稱"文本框中輸入SimpMFC,單擊"打開"按鈕。
(7) 鍵入如圖2所示的代碼。
圖2 SimpMFC.cpp文件內容
(8) 在"解決方案資源管理器"標簽中,右擊頂層的項目名"Ex_1_SimpMFC",從彈出的快捷菜單中選擇"屬性"菜單項,彈出如圖3所示的"Ex_1_SimpMFC 屬性頁"對話框。
圖3 Ex_1_SimpMFC的屬性頁對話框
(9) 單擊"MFC的使用",然後單擊右邊的下拉按鈕,從彈出的下拉選擇列表選擇"在共享DLL中使用MFC",單擊"確定"按鈕。
(10) 打開"調試"菜單,選擇"開始執行(不調試)",或按Ctrl + F5,運行程序,結果如圖4所示。
圖4 項目Ex_1_SimpMFC運行的結果
運行機制及MFC類結構
1.代碼分析
在圖2中,包含文件afxwin.h是使用MFC類庫的頭文件。class是定義類的關鍵字,class的後面是用戶定義的類名,即CSimpApp。需要說明和是:通常用大寫的C字母開始的標識符作為類名,C用來表示類(Class),以與函數及其他數據類型相區別。
類體中定義的函數或變量,都稱為該類的"成員",其中變量稱為"成員變量",函數稱為"成員函數"。成員可被聲明成public、private。對於public類成員來說,它們是公有的,能被類外面的程序訪問;對於private類成員來說,它們是私有的,只能由類中的函數所使用,而不能被外面的程序所訪問。
在"public:"或"private:"後面定義的所有成員都是公有或私有的,直到下一個"public:"或"private:"出現為止。若成員前面沒有類似"public:"或"private:"的聲明,則所定義的成員是private(私有),這是類的默認處理。關鍵字public和private可以在類中出現多次,且前後的順序沒有關系。
類名冒號後面的是用來定義類的繼承,其格式如下:
其中,被繼承的類稱為基類(base class),在基類上建立的新類稱為派生類(derived class)。繼承方式有三種:public(公有)、private(私有)及protected(保護),若繼承方式沒有指定,則被指定為缺省的public方式。繼承方式決定了派生類的繼承基類屬性的使用權限,public繼承方式能夠使用基類的所有共有成員。
從代碼中可以看出,類CSimpApp是從應用程序類CWinApp派生而來。而類CMainFrame是從框架窗口類CFrameWnd派生而來。
在面向對象的程序設計中,類有函數重載、運算符重載和虛函數等,這些稱為類的多樣性。
所謂"函數重載",是指在類中或同一個作用域中,允許有多個同名的函數存在,但同名的各個函數的形參必須有區別:形參的個數不同,或者形參的個數相同,但參數類型有所不同。
所謂"運算符重載",就是賦予已有的運算符多重含義。
所謂"虛函數",它是指在函數名前面加上virtual關鍵字的成員函數,如成員函數InitInstance就是被聲明成了虛函數。虛函數也是能使一個函數具有多種不同的版本,只不過虛函數的不同版本是在基類和派生類中進行定義的。這樣系統就會根據相應的類對象來決定調用的是派生類CSimpApp的InitInstance()函數中的代碼,還是基類InitInstance()函數中的代碼。
在CMainFrame類中,我們還看到了與該類名相同的成員函數CMainFrame(),這個函數稱為該類的"構造函數"。每個類都有一個構造函數,如果我們沒有指定,系統就會自動使用默認的構造函數。構造函數的最大特點是在對象建立時它會被自動執行,因此用於變量、對象的初始化代碼一般放在構造函數中。在定義構造函數時,不能指定函數返回值的類型,也不能指定為void類型。
在CMainFrame()構造函數中的Create函數是用來創建窗口,它的參數依次用來指定類名、窗口標題、窗口樣式和窗口大小。其中,預定義樣式WS_OVERLAPPEDWINDOW用來創建一個常規窗口,CRect是一個矩形的數據類,用來確定窗口的大小和位置。
與構造函數相對應的是析構函數。析構函數是另一種特殊的C++成員函數,它只是在類名稱前面加上一個"~"符號。每一個類只有一個析構函數,沒有任何參數,也不返回任何值。
在類定義時,成員函數既可以在類中定義,也可以在類外定義。但在類外定義時,必須用作用域運算符"::"來通知編譯系統該函數所屬的類。例如,InitInstance函數就是在類CSimpApp外面定義的。
代碼中,m_pMainWnd是MFC中的一個全局指針變量。MessageBox()是窗口基類CWnd的一個成員函數,用來彈出一個對話框窗口,顯示參數指定的短信息,這裡是"你好,歡迎進入MFC世界!"。
2.運行機制
在程序中,當定義一個類對象時,它會自動調用相應的構造函數。所謂"類對象",就是用該類定義的"變量",這個"變量"又稱為類的一個實例。例如,theApp就是類CSimpApp的一個對象。
MFC正是利用類的這種"自動調用相應的構造函數"特性,使得WinMain()函數的調用變成了應用程序框架內部的調用,所以我們在代碼中看不到每個Windows程序所必須有的WinMain()函數。
當應用程序運行到"CSimpApp theApp;"時,系統就會先調用基類CWinApp構造函數,進行一系列的內部初始化操作,然後自動調用CSimpApp的虛函數InitInstance(),該函數會進一步調用相應的函數來完成主窗口的構造和顯示工作。下面來看看上述程序中InitInstance的執行過程。
首先執行的是:
該語句用來創建從CFrameWnd類派生而來的用戶框架窗口CMainFrame類對象,繼而調用該類的構造函數,使得Create函數被調用,完成了窗口創建工作。
然後執行後面兩句:
用作窗口的顯示和更新。接下來調用:
最後返回TRUE,表示窗口創建成功。
由於應用程序類CWinApp是用來調用WinMain以及實例的初始化,因此每一個MFC應用程序有且只能一個這樣的應用程序類,且需要一個全局的對象實例,如上述程序中的theApp,當然也可換一個對象名。
InitInstance()完成初始化工作之後,接下來就是調用基類CWinApp的成員函數Run(),執行應用程序的消息循環,即重復執行接收消息並轉發消息的工作。當Run()檢查到消息隊列為空時,將調用基類CWinApp的成員函數OnIdle進行空閒時的後台處理工作。若消息隊列為空且又沒有後台工作要處理時,則應用程序一直處於等待狀態,一直等到有消息為止。
當程序結束後,調用基類CWinApp的成員函數ExitInstance(),完成終止應用程序的收尾工作。這就是MFC應用程序的運行機制。
3.MFC類結構
Visual C++發展至今,MFC類庫越來越強大,其基本層次結構如圖5所示,箭頭的方向是從派生類指向基類。
圖5 MFC類基本層次結構
其中,CObject類是MFC提供的絕大多數類的基類。該類完成動態空間的分配與回收,支持一般的診斷、出錯信息處理和文檔序列化等。
CCmdTarget類主要負責將系統事件(消息)和窗口事件(消息)發送給響應這些事件的對象,完成消息發送、等待和派遣(調度)等工作,實現應用程序的對象之間協調運行。
CWinApp類是應用程序的主線程類,它是從CWinThread類派生而來。CWinThread類用來完成對線程的控制,包括線程的創建、運行、終止和掛起等。
CDocument類是文檔類,包含了應用程序在運行期間所用到的數據。
CWnd類是一個通用的窗口類,用來提供Windows 中的所有通用特性。
CView 是用於讓用戶通過窗口來訪問文檔以及負責文檔內容的顯示。
CFrameWnd 類是從 CWnd 繼承來的,並實現了標准的框架應用程序。
CDialog 類用來控制對話框窗口。
CMDIFrameWnd和CMDIChildWnd類分別用來多文檔應用程序的主框架窗口和文檔子窗口的顯示和管理。
CMiniFrameWnd類是一種簡化的框架窗口,它沒有最大化和最小化窗口按鈕,也沒有窗口系統菜單,一般很少用到它。
使用MFC應用程序向導
事實上,在Visual C++ .NET中,我們不需要輸入上述程序代碼,甚至不需要輸入一句代碼就能創建所需要的應用程序,這就是MFC各種項目模板中的應用程序向導(MFC AppWizard)的功能,如下面的過程。
(1) 單擊"開始"頁面中的"新建項目",或者打開"文件"菜單中的"新建",選擇"項目"命令,都將彈出"新建項目"對話框。
(2) 在左側的"項目類型"窗格中,選中"Visual C++ 項目"。在右側的"模板"窗格中,拖動窗格右側的滾動條顯示其他模板,然後選中"MFC應用程序"。
(3) 在"名稱"文本框中,輸入項目名稱TextViewer。
(4) 單擊"確定"按鈕 ,彈出"MFC應用程序向導"對話框。
(5) 單擊左側的"應用程序類型",出現如圖6所示的頁面。在這裡,我們可以選擇不同的應用程序類型、項目樣式以及MFC使用的是靜態還是共享DLL(Dynamic Link Library,動態鏈接庫)。需要說明的是,一定要選中"文檔/視圖結構支持",否則文檔程序中常用的磁盤文件的打開、保存以及文檔和視圖的相互作用等功能都需要用戶來實現。
圖6 應用程序類型
需要說明的是:在MFC應用程序框架中,最基本的四種應用程序類型有:單文檔、多文檔、多頂級文檔和基於對話框的應用程序。
單文檔應用程序是類似於Windows記事本的程序,它的功能比較簡單,每次只能打開和處理一個文檔。它的復雜程度適中,雖然每次只能處理一個文檔,但已能滿足一般工程上的需要。因此,大多數Windows桌面應用程序的編制都是從單文檔程序框架開始的。
基於對話框的程序最簡單,也最緊湊的。它沒有菜單、工具欄及狀態欄,也不能處理文檔,但它的好處是速度快,代碼少,程序員所花費的開發和調試時間短。
多文檔應用程序,顧名思義,能允許同時打開和處理多個文檔。它增加了許多功能,因而需要大量額外的編程工作。
多頂級文檔應用程序與多文檔應用程序功能相似。所不同的是,多文檔應用程序打開的多個文檔出現在同一個窗口的客戶區內,而多頂級文檔應用程序打開的多個文檔出現桌面上,每個文檔都會在任務欄上有其相應的工具條,這與Microsoft Office 2000/XP的文檔操作相同。
(6) 選中"單文檔",單擊左側的"用戶界面功能",彈出如圖7所示的頁面。在這裡我們可以改變對浮動工具條、主框架和子框架窗口的樣式等特性的支持。
圖7 用戶界面功能
(7) 單擊左側的"高級功能",彈出如圖8所示的頁面。在這裡我們可以改變對添加對上下文幫助、自動化、打印與預覽、通信等特性的支持,以及設置最近文件列表中的文件數。
圖8 高級功能
(8) 單擊左側的"生成的類",彈出如圖9所示的頁面。在這裡我們可以改變對對MFC 應用程序向導提供的默認類名、基類、各個源文件名進行修改。
圖9 生成的類
(9) 單擊"完成"按鈕,一個單文檔應用程序項目TextViewer就創建好了。運行程序,結果如圖10所示。
圖10 項目TextViewer運行的結果
結束語
在向導中,除了前面到的特性外,還對"數據庫"以及資源模板字符串和復合文檔的支持等。總之,使用項目模板的MFC應用程序向導可以創建最常用的應用程序類型。當然,向導創建的應用程序中的各個類之間還存在著緊密聯系,在下一講中,我們將根據各個類的關聯機制,討論文檔數據是如何讀取並顯示的。