程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> Visual C++ MFC簡明教程(2)

Visual C++ MFC簡明教程(2)

編輯:關於VC++

第二部分:一個簡單的MFC程序

在本將中,我們將一段一段地來研究上一將中提到的 MFC 應用程序,以便能理解它的結構和概念框架。我們將先介紹 MFC,然後在介紹如何用 MFC 來建立應用程序。

MFC簡介

MFC 是一個很大的、擴展了的 C++ 類層次結構,它能使開發 Windows 應用程序變得更加容易。MFC 是在整個 Windows 家族中都是兼容的,也就是說,無論是 Windows3.x、Windows95 還是 Windows NT,所使用的 MFC 是兼容的。每當新的 Windows 版本出現時,MFC 也會得到修改以便使舊的編譯器和代碼能在新的系統中工作。MFC 也回得到擴展,添加新的特性、變得更加容易建立應用程序。

與傳統上使用 C 語言直接訪問 Windows API相反,使用 MFC 和 C++ 的優點是 MFC 已經包含和壓縮了所有標准的“樣板文件”代碼,這些代碼是所有用 C 編寫的 Windows 程序所必需的。因此用 MFC 編寫的程序要比用C語言編寫的程序小得多。另外,MFC 所編寫的程序的性能也毫無損失。必要時,你也可以直接調用標准 C 函數,因為 MFC 不修改也不隱藏 Windows 程序的基本結構。

使用 MFC 的最大優點是它為你做了所有最難做的事。MFC 中包含了上成千上萬行正確、優化和功能強大的 Windows 代碼。你所調用的很多成員函數完成了你自己可能很難完成的工作。從這點上將,MFC 極大地加快了你的程序開發速度。

MFC 是很龐大的。例如,版本4.0中包含了大約200個不同的類。萬幸的是,你在典型的程序中不需要使用所有的函數。事實上,你可能只需要使用其中的十多個 MFC 中的不同類就可以建立一個非常漂亮的程序。該層次結構大約可分為幾種不同的類型的類:

應用程序框架

圖形繪制的繪制對象

文件服務

異常處理

結構 - List、Array 和 Map

Internet 服務

OLE 2

數據庫

通用類

在本教程中,我們將集中討論可視對象。下面的列表給出了部分類:

CObject
CCmdTarget
CWinThread
CWinApp
CWnd
CFrameWnd
CDialog
CView
CStatic
CButton
CListBox
CComboBox
CEdit
CscrollBar

在上面的列表中,有幾點需要注意。第一,MFC 中的大部分類都是從基類 CObject 中繼承下來的。該類包含有大部分MFC類所通用的數據成員和成員函數。第二,是該列表的簡單性。CWinApp 類是在你建立應用程序是要用到的,並且任何程序中都只用一次。CWnd 類匯集了 Windows 中的所有通用特性、對話框和控制。CFrameWnd 類是從 CWnd 繼承來的,並實現了標准的框架應用程序。CDialog 可分別處理無模式和有模式兩種類型的對話框。CView 是用於讓用戶通過窗口來訪問文檔。最後,Windows 支持六種控制類型: 靜態文本框、可編輯文本框、按鈕、滾動條、列表框和組合框(一種擴展的列表框)。一旦你理解了這些,你也就能更好的理解 MFC 了。MFC 中的其它類實現了其它特性,如內存管理、文檔控制等。

為了建立一個MFC應用程序,你既要會直接使用這些類,而通常你需要從這些類中繼承新的類。在繼承的類中,你可以建立新的成員函數,這能更適用你自己的需要。你在第一講中的簡單例子中已經看到了這種繼承過程,下面會詳細介紹。CHelloApp 和 CHelloWindow 都是從已有的 MFC 類中繼承的。

設計一個程序

在討論代碼本身之前,我們需要花些工夫來簡單介紹以下 MFC 中程序設計的過程。例如,假如你要編一個程序來向用戶顯示“Hello World”信息。這當然是很簡單的,但仍需要一些考慮。

“hello world”應用程序首先需要在屏幕上建立一個窗口來顯示“hello world”。然後需要實際把“hello world”放到窗口上。我們需要但個對象來完成這項任務:

一個應用程序對象,用來初始化應用程序並把它掛到 Windows 上。該應用程序對象處理所有的低級事件。

一個窗口對象來作為主窗口。

一個靜態文本對象,用來顯示“hello world”。

你用 MFC 所建立的每個程序都會包含頭兩個對象。第三個對象是針對該應用程序的。每個應用程序都會定義它自己的一組用戶界面對象,以顯示應用程序的輸出和收集應用的輸入信息。

一旦你完成了界面的設計,並決定實現該界面所需要的控制,你就需要編寫代碼來在屏幕上建立這些控制。你還會編寫代碼來處理用戶操作這些控制所產生的信息。在“hello world”應用程序中,只有一個控制。它用來輸出“hello world”。復雜的程序可能在其主窗口和對話框中需要上百個控制。

應該注意,在應用程序中有兩種不同的方法來建立用戶控制。這裡所介紹的是用 C++ 代碼方式來建立控制。但是,在比較大的應用程序中,這種方法是不可行的。因此,在通常情況下要使用資源文件的圖形編輯器來建立控制。這種方法要方便得多。

理解“hello world”的代碼

下面列出了你在上一講中已經輸入、編譯和運行的“hello world”程序的代碼。添加行號是為了討論方便。我們來一行行地研究它,你會更好的理解 MFC 建立應用程序的方式。

如果你還沒有編譯和運行該代碼,應該按上一講的方法去做。

1 //hello.cpp
2 #include
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 中所使用的所有的類型、類、函數和變量。它也包含了其它頭文件,如 Windows API 庫等。

第 3 至 8 行從 MFC 說明的標准應用程序類 CWinApp 繼承出了新的應用程序類 CHelloApp。該新類是為了要重載 CWinApp 中的 InitInstance 成員函數。InitInstance 是一個應用程序開始執行時要調用的可重載函數。

在第10行中,說明了應用程序作為全局變量的一個事例。該實例是很重要的,因為它要影響到程序的執行。當應用程序被裝入內存並開始執行時,全局變量的建立會執行 CWinApp 類的缺省構造函數。該構造函數會自動調用在18至26行定義的 InitInstance 函數。

在第11至17中,CHelloWindow 類是從 MFC 中的 CFrameWnd 類繼承來的。CHelloWindow 是作為應用程序在屏幕上的窗口。建立新的類以便實現構造函數、析構函數和數據成員。

第18至26行實現了 InitInstance 函數。該函數產生一個 CHelloWindow 類的事例,因此會執行第27行至41行中類的構造函數。它也會把新窗口放到屏幕上。

第27至41實現了窗口的構造函數。該構造函數實際是建立了窗口,然後在其中建立一個靜態文本控制。

要注意的是,在該程序中沒有 main 或 WinMain 函數,也沒有事件循環。然而我們從上一講在執行中知道它也處理了事件。窗口可以最大或最小化、移動窗口等等。所有這些操作都隱藏在主應用程序類 CWinApp 中,並且我們不必為它的事件處理而操心,它都是自動執行、在 MFC 中不可見的。

下一節中,將詳細介紹程序的各部分。你可能不能馬上全都理解得很好: 但你最好先讀完它以獲得第一印象。在下一講中,會介紹一些特殊的例子,並偶把各片段組合在一起,有助於你能更好的理解。

程序對象

用 MFC 建立的每個應用程序都要包括一個單一從 CWinApp 類繼承來的應用程序對象。該對象必須被說明成全局的(第10行),並且在你的程序中只能出現一次。

從 CWinApp 類繼承的對象主要是處理應用程序的初始化,同時也處理應用程序主事件循環。CWinApp 類有幾個數據成員和幾個成員函數。在上面的程序中,我們只重載了一個 CWinApp 中的虛擬函數 InitInstance。

應用程序對象的目的是初始化和控制你的程序。因為 Windows 允許同一個應用程序的多個事例在同時執行,因此 MFC 把初始化過程分成兩部分並使用兩個函數 InitApplication 和 InitInstance 來處理它。此處,我們只使用了一個 InitInstance 函數,因為我們的程序很簡單。當每次調用應用程序時都會調用一個新的事例。第3至8行的代碼建立了一個稱為 CHelloApp 的類,它是從 CWinApp 繼承來的。它包含一個新的 InitInstance 函數,是從 CWinApp 中已存在的函數(不做任何事情)重載來的:

3 // Declare the application class
4 class CHelloApp : public CWinApp
5 {
6 public:
7 virtual BOOL InitInstance();
8 };

在重載的 InitInstance 函數內部,第18至26行,程序使用 CHelloApp 的數據成員 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 函數返回 TRUE 表示初始化已成功的完成。如果返回了FALSE,則表明應用程序會立即終止。在下一節中我們將會看到窗口初始化的詳細過程。

當應用程序對象在第10行建立時,它的數據成員(從 CWinApp 繼承來的) 會自動初始化。例如,m_pszAppName、m_lpCmdLine 和 m_nCmdShow 都包含有適當的初始化值。你可參見 MFC 的幫助文件來獲得更詳細的信息。我們將使用這些變量中的一個。

窗口對象

MFC 定義了兩個類型的窗口: 1) 框架窗口,它是一個全功能的窗口,可以改變大小、最小化、最大化等等; 2) 對話框窗口,它不能改變大小。框架窗口是典型的主應用程序窗口。

在下面的代碼中,從 CFrameWnd 中繼承了一個新的類 CHelloWindow:

11 // Declare the main window class
12 class CHelloWindow : public CFrameWnd
13 {
14 CStatic* cs;
15 public:
16 CHelloWindow();
17 };

它包括一個新的構造函數,同時還有一個指向程序中所使用的唯一用戶界面控制的數據成員。你多建立的每個應用程序在主窗口中都會有唯一的一組控制。因此,繼承類將有一個重載的構造函數以用來建立主窗口所需要的所有控制。典型情況下,該類會包含有一個析構函數以便在窗口關閉時來刪除他們。我們這裡沒有使用析構函數。在第四講中,我們將會看到繼承窗口類也會說明一個消息處理函數來處理這些控制在響應用戶事件所產生的消息。

典型地,一個應用程序將有一個主應用程序窗口。因此,CHelloApp 應用程序類定義了一個名為 m_pMainWnd 成員變量來指向主窗口。為了建立該程序的主窗口,InitInstance 函數(第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 }

只建立一個簡單的框架窗口是不夠的。還要確保窗口能正確地出現在屏幕上。首先,代碼必須要調用窗口的 ShowWindow 函數以使窗口出現在屏幕上(第23行)。其次,程序必須要調用 UpdateWindow 函數來確保窗口中的每個控制和輸出能正確地出現在屏幕上(第24行)。

你可能奇怪,ShowWindow 和 UpdateWindow 函數是在哪兒定義的。例如,如果你要查看以便了解它們,你可能要查看 MFC 的幫助文件中的 CFrameWnd 定義部分。但是 CFrameWnd 中並不包含有這些成員函數。CFrameWnd 是從 CWnd 類繼承來的。你可以查看 MFC 文檔中的 CWnd,你會發現它包含有200多個不同的成員函數。顯然,你不能在幾分鐘內掌握這些函數,但是你可以掌握其中的幾個,如 ShowWindow 和UpdateWindow。

現在讓我們花幾分鐘來看一下 MFC 幫助文件中的 CWnd::ShowWindow 函數。為此,你你可以單擊幫助文件中的 Search 按鈕,並輸入“ShowWindow”。找到後,你會注意到,ShowWindow 只有一個參數,你可以設置不同的參數值。我們把它設置成我們程序中 CHelloApp 的數據成員變量 m_nCmdShow (第23行)。m_nCmdShow 變量是用來初始化應用程序啟動的窗口顯示方式的。例如,用戶可能在程序管理器中啟動應用程序,並可通過應用程序屬性對話框來告知程序管理器應用程序在啟動時要保持最小化狀態。m_nCmdShow 變量將被設置成 SW_SHOWMINIMIZED,並且應用程序會以圖標的形式來啟動,也就是說,程序啟動後,是一個代表該程序的圖標。m_nCmdShow 變量是一種外界與應用程序通訊的方式。如果你願意,你可以用不同的 m_nCmdShow 值來試驗 ShowWindow 的效果。但要重新編譯程序才能看到效果。

第22行是初始化窗口。它為調用 new 函數分配內存。在這一點上,程序在執行時會調用CHelloWindow的構造函數。該構造函數在每次帶類的事例被分配時都要調用。在窗口構造函數的內部,窗口必須建立它自己。它是通過調用 CFrameWnd 的 Create 成員函數來實現的(第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));

建立函數共傳遞了四個參數。通過查看 MFC 文檔,你可以了解不同類型。NULL 參數表示使用缺省的類名。第二個參數為出現在窗口標題欄上的標題。第三個參數為窗口的類型屬性。該程序使用了正常的、可覆蓋類型的窗口。在下一講中將詳細介紹類型屬性。第四個參數指出窗口應該放在屏幕上的位置和大小,左上角為(0,0), 初始化大小為 200×200個象素。如果使用了 rectDefault,則 Windows 會為你自動放置窗口及大小。

因為我們的程序太簡單了,所以它只在窗口中建立了一個靜態文本控制。見第35至40行。下面將詳細介紹。

靜態文本控制

程序在從 CFrameWnd 類中繼承 CHelloWindow 類時(第11至17行)時,說明了一個成員類型 CStatic及其構造函數。

正如在前面所見到的,CHelloWindow 構造函數主要做兩件事情。第一是通過調用Create函數(第31行)來建立應用程序的窗口。然後分配和建立屬於窗口的控制。在我們的程序中,只使用了一個控制。在 MFC 中建一個對象總要經過兩步。第一是為類的事例分配內存,然後是調用構造函數來初始化變量。下一步,調用 Create 函數來實際建立屏幕上的對象。代碼使用這兩步分配、構造和建立了一個靜態文本對象(第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 構造函數是在為其分配內存時調用的,然後就調用了 Create 函數來建立 CStatic 控制的窗口。Create 函數所使用的參數與窗口建立函數所使用的參數是類似的(第31行)。第一個參數指定了控制中所要顯示的文本內容。第二個參數指定了類型屬性。類型屬性在下一講中將詳細介紹。在次我們使用的是子窗口類型(既在別的窗口中顯示的窗口),還有它是可見的,還有文本的顯示位置是居中的。第三個參數決定了控制的大小和位置。第四參數表示該子窗口的父窗口。已經建立了一個靜態控制,它將出現在應用程序窗口上,並顯示指定的文本。

結論

第一次浏覽該代碼,也可能不是很熟悉和有些讓人煩惱。但是不要著急。從程序員的觀點來看,整個程序的主要工作就是建立了 CStatic 控制(36至40行)。在下一講中,我們詳細向你介紹36至40行代碼的含義,並可看到定制 CStatic 控制的幾個選項。

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved