1. 程式人生 > >MFC單文件及其簡介

MFC單文件及其簡介

                                                MFC 是一個程式設計框架

MFC 中的各種類結合起來構成了一個應用程式框架,它的目的就是讓程式設計師在此基礎上來
建立Windows 下的應用程式。MFC 框架定義了應用程式的輪廓,並提供了使用者介面的標準
實現方法。AppWizard 可以用來生成初步的框架檔案。資源編輯器用於幫助直觀的設計使用者
介面。ClassWizard 用來協助新增程式碼到框架檔案,最後,通過類庫實現了應用程式特定的
邏輯。
MFC 提供了一個Windows 應用程式開發模式,對程式的控制主要是由MFC 框架完成的。
而且MFC 也完成了大部分的功能,預定義或實現了許多事件和訊息處理。框架或者由其本
身處理事件,不依賴程式設計師的程式碼,或者呼叫程式設計師的程式碼來處理應用程式特定的事件。
1.SDI 生成
1.步驟dxq2009
首先,開啟VC++6.0 開發環境,然後,選擇”File”選單中的“New”子選單,在彈出的對話
框中選擇“MFC AppWizard(exe)”項並在“Progect name”編輯框中輸入合適的工程名字
Simple1,如圖,它的意思是建立一個基於MFC 的應用,接著進入正式的建立過程,MFC
應用程式的建立過程有6 步(基於對話方塊)或者6 步(SDI 或者MDI),下面首先介紹SDI
應用的建立過程。
(1) 第一步用於選擇應用的結構以及語言等。如圖1,首先確定應用是否需要Doc/View
Architecture Support 支援,因為不使用該結構的應用不支援從磁碟檔案開啟文件,
也沒有派生於類CWnd 的視窗客戶區。上面3 個單選按鈕用於確定建立的應用型別,
包括單文件,多文件,對話方塊,這裡選擇第一個。然後從資源列表框選擇應用所使
用的語言種類,單擊“Next”。
圖 1
(2)第二步為用用程式選擇4 項資料庫支援選項之一:如圖2.如果選擇了資料庫支援,那
麼單擊“Data Source”按鈕,選擇外部的資料庫表項,一般按預設即可,單擊“Next”。
圖 2
(3)第三步選擇希望包含在應用中的複合文件支援項,同時判定是否啟用標準的ActiveX
資源,以及是否為應用的選單條新增額外的自動化命令等,如圖4,一般安預設,單擊“Next”
圖4
(4)第四步用於選擇應用所需的基本使用者介面特徵,以及所想使用的工具欄型別,如圖5,
如果想要修改應用所使用的檔名和副檔名,或者想要調整應用的使用者介面和框架風格,就
單擊“Advanced”,然後修改,一般預設,單擊“Next”。
圖 5
(5)第五步設定工程的風格,Explorer 風格的應用類似於資源管理器,標準MFC 風格帶有
檔案檢視區域,還要判定是否希望應用嚮導在原始檔中生成註釋,最後選擇MFC 庫時動態
連結還是靜態連結,如圖6 單擊“Next”。
圖6
(6)第六步可以更改由應用嚮導提供的預設型別,基類,標頭檔案和實現檔名,對於檢視,
還可以更改它的基類,如圖7,一般預設,單擊”Finish”,在彈出的工程資訊對話方塊中點選
“OK”即結束應用的建立過程。
圖 7
2.MFC 工程的成員類及全域性物件
應用嚮導可以自動地生成 MFC 應用的各個C++類,另外,還能自動的生成一個類APP 的全
局物件theApp,如圖8 下面做簡要說明。
圖8
1.應用類及全域性物件(CCExcmpleApp)
應用類封裝了 Windows 應用的初始化,執行以及終止的全過程。對於每一個基於框架的應
用,它必須有一個且只能有一個派生於CWinApp 的類物件。這個物件是全域性物件,因此它
在建立任何視窗前首先被構造。類CWinApp 提供了幾個關鍵的可過載的虛成員函式,他們
是InitInstance,Run,ExitInstance 以及OnIdle 等。而且,在程式中可以隨時呼叫全域性函式
AfxGetApp,以便獲得CWinApp 類物件的指標。
2.文件類(CCExcmpleDoc)
文件類實際上是一種資料結構,該類實現了對這種結構的封裝以利於管理,通常,它不但包
含應用中所需的資料,而且也包含了處理這些資料的方法,另外,文件類還可以為應用提供
與其儲存的資料相關的服務。
3.檢視類(CCExcmpleView)
該類佔有框架視窗的客戶區,主要負責顯示文件資料,也為文件物件和使用者之間提供了用以
互動的可視介面,另外,也完成了與文件列印相關的操作,通常,一般的繪製操作都是在該
類中完成,因此有時也稱檢視類視窗為“繪製視窗”。
4.框架類(CMainFrame)
框架類表示應用程式的主框架視窗,其主要作用是響應標準的視窗訊息,不過,它通常先將
訊息按照一定的次序傳遞給檢視類以及文件類等其他命令處理類,另外,它還為檢視類提供
視覺化的邊框,同時也包括標題欄,一些標準的視窗元件等。
5.“關於”對話方塊類(CAboutDlg)
該類封裝了用於顯示軟體版本,版權等相關資訊的“關於”對話方塊,通常不需要對它進行任
何的程式設計。而只需要使用對話方塊資源編輯器對對話方塊模板進行簡單的編輯即可。
3.原始檔結構:
應用嚮導生成的應用程式具有很多原始的功能,例如:開啟檔案對話方塊等,而且還可以使用
類嚮導向某個類新增成員函式或者成員變數,而且類嚮導可以將新增的成員安排在何時得位
置。應用嚮導和類嚮導時怎麼樣實現這些自動功能呢?下面先瀏覽一下CCExcmpleView 的
標頭檔案:
// CExcmpleView.h : interface of the CCExcmpleView class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_CEXCMPLEVIEW_H__4FEB3544_9956_4E4C_93C9_35D40796D187__INCLUDED_)
#define AFX_CEXCMPLEVIEW_H__4FEB3544_9956_4E4C_93C9_35D40796D187__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CCExcmpleView : public CView
{
//Constructors
protected: // create from serialization only
CCExcmpleView();
DECLARE_DYNCREATE(CCExcmpleView)
// Attributes
public:
CCExcmpleDoc* GetDocument();
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CCExcmpleView)
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
該程式碼的作用是宣告CCExcmpleView 類,但是這個宣告包含在一個“#iif…#define…#endif”
結構內,其目的時保證編譯時此檔案只被包含一次。下面介紹下標頭檔案的組成部分。主要由
註釋塊,訪問型別以及分界符。
1.註釋塊:用“//”引導的綠色部分
Constructors 塊:構造塊,用於宣告該類的C++建構函式,以及所需的各種初始化函式。
Attributes 塊 : 共性或屬性快,用於包含物件的共性或屬性,
Operations 塊:操作塊,用於包含成員函式,可以通過物件呼叫這些函式,以使該物件執行
需要的任務或操作,
Overridables 塊:過載塊,該塊用於包含虛擬函式,當需要更改基類的行為時,可以在派生類
中過載這些函式。
Implementation 塊;實現塊,是MFC 類宣告中最重要的部分。實現塊包括所有的實現資訊,
包括成員變數和成員函式。
2.訪問型別。
Public ,protected,private
3.分界符:
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CCExcmpleView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CCExcmpleView)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#ifndef _DEBUG // debug version in CExcmpleView.cpp
inline CCExcmpleDoc* CCExcmpleView::GetDocument()
{ return (CCExcmpleDoc*)m_pDocument; }
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif
// !defined(AFX_CEXCMPLEVIEW_H__4FEB3544_9956_4E4C_93C9_35D40796D187__INCLUDED_)
從上面的程式碼可以看到如“//{{AFX_MSG(CCExcmpleView)”等的識別符號,類嚮導使用幾種
特殊的分界符,用以區分嚮導生成的程式碼和使用者輸入的程式碼,這些格式化的分界符以註釋的
形式出現在程式碼中。如下所示:
分界符 簡要描述
通用定界符
AFX_MSG 在標頭檔案中標誌與訊息對映相關的ClassWizard 實體
AFX_MSG_MAP 在實現檔案的類的訊息對映中標誌訊息對映的起止
AFX_VIRTUAL 在標頭檔案中標誌虛擬函式過載宣告的起止
對話方塊定界符
AFX_DATA 在標頭檔案中標誌用於對話方塊資料交換(DDX)的成員變數宣告的起止
AFX_DATA_INIT 在對話方塊類的建構函式中標誌DDX 的成員變數初始化的起止
AFX_DATA_MAP 在對話方塊類的DoDataExchange 函式中標誌DDX 函式呼叫的起止
記錄集定界符
AFX_FIELD 在標頭檔案中標誌用於資料庫記錄欄位交換的成員變數宣告的起止
AFX_FIELD_INIT 在記錄集類的建構函式中標誌RFX 的成員變數初始化的起止
AFX_FIELD_MAP 在記錄集類的DoFieldExchange 函式中標誌RFX 函式呼叫的起止
OLE 定界符
AFX_DISP 在標頭檔案中標誌OLE 自動化宣告的起止
AFX_DISP_MAP 在實現檔案中標誌OLE 自動化對映的起止
AFX_EVENT 在標頭檔案中標誌OLE 事件宣告的起止
AFX_EVENT_MAP 在實現檔案中標誌OLE 事件的起止
“DECLARE_DYNCREATE(CCExcmpleView)”是MFC 為支援該類的動態建立而提供的巨集。
4.應用程式類:MFC 程式的啟動過程:終止過程
1.全域性物件的產生:
全域性物件在名為 Global 的資料夾中,此時只有一個theApp,從C++的學習中可以瞭解到,
當作業系統將程式載入並激活時,全域性物件將首先獲得配置,因此其建構函式將首先被執行,
也即時說它比WinMain 更早,下來看這個建構函式到底做了什麼。
CCExcmpleApp theApp;
從程式中看到,它自己的建構函式只是完成使用者自定義的變數的初始化,而執行環境的初始
化是在它的基類中完成的,它的基類時CWinApp,它的建構函式定義如下:
CWinApp::CWinApp(LPCTSTR lpszAppName)
{//引數時Windows 使用的應用名稱
if (lpszAppName != NULL)
m_pszAppName = _tcsdup(lpszAppName);
else
m_pszAppName = NULL;
// initialize CWinThread state 初始化CWinThread state 狀態
AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
ASSERT(AfxGetThread() == NULL);
pThreadState->m_pCurrentWinThread = this;
ASSERT(AfxGetThread() == this);
m_hThread = ::GetCurrentThread();
m_nThreadID = ::GetCurrentThreadId();
// initialize CWinApp state 初始化CWinApp 狀態
ASSERT(afxCurrentWinApp == NULL);
// only one CWinApp object please 儲存theApp 物件的指標
pModuleState->m_pCurrentWinApp = this;
ASSERT(AfxGetApp() == this);
// in non-running state until WinMain 直到執行WinMain 時,才是真正意義上的執行狀態
m_hInstance = NULL;
m_pszHelpFilePath = NULL;// 應用程式幫助檔案的路徑
m_pszProfileName = NULL;
m_pszRegistryKey = NULL;
m_pszExeName = NULL;
m_pRecentFileList = NULL;
m_pDocManager = NULL;
m_atomApp = m_atomSystemTopic = NULL;
m_lpCmdLine = NULL;
m_pCmdInfo = NULL;
// initialize wait cursor state
m_nWaitCursorCount = 0;
m_hcurWaitCursorRestore = NULL;
// initialize current printer state
m_hDevMode = NULL;
m_hDevNames = NULL;
m_nNumPreviewPages = 0; // not specified (defaults to 1)
// initialize DAO state
m_lpfnDaoTerm = NULL; // will be set if AfxDaoInit called
// other initialization
m_bHelpMode = FALSE;
m_nSafetyPoolSize = 512; // default size
}
CWinApp 的基類時CWinThread,CWinThread 表示具有一個或多個執行緒的應用程式的主執
行執行緒。
從上面程式碼可以看到,此函式主要時用來對執行緒和全域性物件的初始化,同時儲存 theApp 對
象的指標,這樣WinMain 可以通過該指標呼叫它的成員函式,用以初始化和執行該應用.
2.應用程式入口-WinMain 函式以及主框架建立
全域性物件生成後,系統根據配置的 CRT DLL(C-Runtime DLL,C 執行時動態連結庫)對
WinMain 函式進行呼叫,這些工作是由系統自動完成的,WinMain 函式的定義如下:
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
_tWinMain 中的_t 是為了支援Unicode 而定義的對映巨集。
從程式碼裡面看到,WinMain 只是對另外一個函式AfxWinMain 的簡單呼叫,下面看
AfxWinMain 函式的實現過程。如下:
int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
ASSERT(hPrevInstance == NULL);
int nReturnCode = -1;
CWinThread* pThread = AfxGetThread();
CWinApp* pApp = AfxGetApp();
// AFX internal initialization AFX 內部初始化 dxq
if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
goto InitFailure;
// App global initializations (rare) APP 全域性初始化 dxq
if (pApp != NULL && !pApp->InitApplication())
goto InitFailure;
// Perform specific initializations
if (!pThread->InitInstance())
{
if (pThread->m_pMainWnd != NULL)
{
TRACE0("Warning: Destroying non-NULL m_pMainWnd\n");
pThread->m_pMainWnd->DestroyWindow();
}
nReturnCode = pThread->ExitInstance();
goto InitFailure;
}
nReturnCode = pThread->Run(); //dxq 進入Run 狀態
InitFailure:
#ifdef _DEBUG
// Check for missing AfxLockTempMap calls
if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
{
TRACE1("Warning: Temp map lock count non-zero (%ld).\n",
AfxGetModuleThreadState()->m_nTempMapLock);
}
AfxLockTempMaps();
AfxUnlockTempMaps(-1);
#endif
AfxWinTerm(); //dxq 終止應用執行並登出環境
return nReturnCode;
}
從程式碼看出,該函式主要呼叫了 4 個關鍵的函式:AfxWinInit(),InitApplication(),
InitInstance(),Run(),
在此就不詳細的介紹這幾個函式,有興趣的學生可以自己區看看。
AfxWinInit():-初始化MFC 環境,
主要完成兩個任務:其 1:初始化全域性物件的資料成員,其2,初始化執行緒指定的資料。
InitApplication():內部管理
InitInstance():應用的初始化
講解:每當應用程式啟動一個新的例項時,WinMain 就呼叫InitInstance,從概念上講,應用
的初始化過程可分為兩個部分,程式第一次執行時,將進行應用級的初始化,當程式的一個
副本或“例項”執行時,它將進行例項的初始化。此函式時虛擬函式,而且在CWinApp 中是
一個空函式,因此,在派生類中必須對此函式進行過載,應用嚮導會完成這個任務。下面是
它的函式體:
BOOL CCExcmpleApp::InitInstance()
{
。。。。。。。
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CCExcmpleDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CCExcmpleView));
AddDocTemplate(pDocTemplate);
//dxq 解析命令列為標準的外殼命令
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// 傳送指定的命令
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// 惟一的視窗已經被初始化,顯示並更新
m_pMainWnd->ShowWindow(SW_SHOW);
//更新視窗傳送WM_PAINT 訊息
m_pMainWnd->UpdateWindow();
return TRUE;
}
主框架建立
此函式完成了 MFC 程式的大部分任務,如命令解析,框架,檢視乃至文件的生成等,但是,
這些過程對開發人員來說時不透明的,他們被MFC 封裝起來。
在應用程式開始執行時,由 APP 類輔助解析命令列,執行下面兩行程式碼,接著執行
ProcessShellCommand 函式,,在這個函式裡面呼叫了一系列封裝的函式,主要完成建立一個
主框架視窗,學員可以進入函數了解一下。再次略去。至此,主框架就建立好了,主框架的
顯示以及更新也在InitInstance 函式中。在主框架產生之際會發出WM_CREATE 訊息,因此
CMainFrame::OnCreate 會被執行,哪裡將進行工具欄和狀態列的建立,及如下程式碼:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE |
CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
工具欄和狀態列分別由CToolBar 和CStatusBar 建立,兩個物件屬於主視窗。為了攔截
WM_CREATE,首先需要在MessageMap 中設定“對映專案”;
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code !
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
ON_WM_CREATE 這個巨集表示,只要WM_CREATE 發生,OnCreate 就會呼叫,就會建立工
具欄和狀態列。
至此,程式就已經啟動起來了,啟動完畢後,程式進入掛起狀態。
3.物件的建立
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CCExcmpleDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CCExcmpleView));
AddDocTemplate(pDocTemplate);
//dxq 解析命令列為標準的外殼命令
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// 傳送指定的命令
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// 惟一的視窗已經被初始化,顯示並更新
m_pMainWnd->ShowWindow(SW_SHOW);
//更新視窗傳送WM_PAINT 訊息
m_pMainWnd->UpdateWindow();
此段程式碼顯示了物件的建立
SDI 應用通常包括幾個重要的物件:文件模板,文件,框架視窗以及檢視等。應用物件負責
建立文件模板,而文件模板負責建立文件和框架視窗,框架視窗負責建立檢視物件,其先後
順序為:文件模板->文件->框架視窗->檢視。
物件建立完成之後,
4.程式的掛起:
Run():程式掛起。
Run()函式通過訊息迴圈,檢查訊息佇列中是否有需要處理的訊息,如果有訊息需要處理,
則Run()就獲取-翻譯—分發它,如果沒有任何訊息需要處理,則Run 呼叫OnIdle 以便執
行使用者或框架需要完成的空閒時間處理如果沒有任何訊息,也沒有任何可執行的空閒處理,
則應用程式一直等待訊息產生,應用也就被掛起。
下面時函式定義:
int CWinApp::Run()
{
if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
{
// Not launched /Embedding or /Automation, but has no main window!
TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting
application.\n");
AfxPostQuitMessage(0);
}
return CWinThread::Run();
}
該函式沒有做處理,主要呼叫基類的 CWinThread::Run();
int CWinThread::Run()
{
ASSERT_VALID(this);
// for tracking the idle time state
BOOL bIdle = TRUE;
LONG lIdleCount = 0;
// dxq 獲取並分發訊息直到收到一個WM_QUIT 訊息
for (;;)
{
// dxq 第一階段:檢查是否可以在空閒做一些工作
while (bIdle &&
!::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
{
// 當為空閒時呼叫OnIdle
if (!OnIdle(lIdleCount++))
bIdle = FALSE; // assume "no idle" state
}
// 第二階段:當可以從佇列中得到訊息時提取訊息
do
{
// 提取訊息當為WM_QUIT 時退出
if (!PumpMessage())
return ExitInstance();
// 提取正常訊息,重置空閒狀態
if (IsIdleMessage(&m_msgCur))
{
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
}
ASSERT(FALSE); // not reachable
}
通過該函式的實現,可以理解訊息迴圈的過程,和 SCK 不太一樣,它是封裝在MFC 下的,
實際上,它在PumpMessage 函式的定義中,學員下去可以自己看看CWinThread 中的
PumpMessage 函式。這個函式需哎喲首先從訊息佇列中提取訊息, 接著呼叫
PreTranslateMessage 虛擬函式過濾視窗訊息。此處不詳細講解啦。
5.MFC 的終止過程
應用處掛起狀態時,如果不小心單擊了“關閉”按鈕,或者用鍵盤或滑鼠從系選單中選擇關
閉,這時,系統都會給視窗過程傳送一個WM_SYSCOMMAND 訊息,視窗過程將這個訊息
傳給預設的視窗過程,而預設的視窗過程會給視窗過程傳送一個WM_CLOSE 訊息來響應,
視窗過程再次將它傳給預設的視窗過程,預設視窗過程呼叫DestroyWindow 來響應這個
WM_CLOSE 訊息, 此後, DestroyWindow 將導致Windows 給視窗過程傳送一個
WM_DESTROY 訊息,此訊息導致視窗過程再呼叫PostQuitMessage,將一個WM_QUIT 消
息置入訊息佇列中,以此來響應此訊息,Run 函式收到WM_QUIT 訊息後,會結束內部的
訊息迴圈,然後呼叫ExitInstance()函式,最後回到AfxWinMain(),執行AfxWinTerm,
以此來終止程式的執行。
6.MFC 程式流程小結
1. Windows 將使用者程式裝入記憶體。
2. 構造全域性物件theApp,在程式被裝入時,所有全域性物件都會立刻被建立。
3. Windows 呼叫全域性函式WinMain,它是類庫的惟一例項
4. WinMain 裡面只調用函式AfxWinMain,
5. AfxWinMain 執行AfxWininit,呼叫AfxinitThred,接著
6. AfxWinMain 執行InitApplication,然後執行Initinstance,Initinstance 是CWinApp 的虛函
數,在此改寫。
7. InitInstance 函式裡面啟動文件的裝入以及主要框架和檢視顯示處理過程。
8 .在這裡new 一個CMyFrameWnd ,CMyFrameWnd 建構函式呼叫Create 產生主視窗
9. InitInstance 執行ShowWindow,UpdateWindow,發出WM_PAINT
10. WinMain 呼叫theApp 的Run 函式,它啟動視窗訊息和命令訊息的傳遞處理過程。
11:單擊file/close,則發出WM_CLOSE
12:CMainFrame 交預設處理
13:呼叫::DestroyWindow 發出WM_DESTROY
14 :預設處理呼叫::postQuitMessage 發出WM_QUIT
15: CWinapp::Run 收到WM_QUIT 結束內部迴圈,呼叫ExitInsance(若CCExcmpleApp 改寫
Exitinstance,則呼叫CCExcmpleApp::ExitInstance;
16. ExitInstance 函式負責完成應用程式結束之前的清除工作。
17 . ExitInstance 函式返回時,Run 函式也返回了,MFC 完成了一些清除工作,Windows
終止應用程式
18. 回到AfxWinMain,執行AfxWinTerm,程式結束!!
5.文件/檢視類
文件檢視類以及主框架之間的關係
文件檢視較好的實現了資料顯示和資料操作的分離,具體的說,使用者對資料所做的任何改變
的都是由文件類負責管理的,而檢視通過呼叫此介面,以實現對資料的訪問和更新。
框架視窗,文件,檢視他們之間的關係如下圖所示:
從上圖可以看到,檢視佔據了框架視窗的客戶區,框架視窗只是相當於檢視的容器。這樣,
即使直接在框架視窗的客戶區內執行繪製操作,在螢幕上也不會由任何的輸出資訊,輸出被
檢視所覆蓋。必須通過檢視顯示應用輸出。
注意:文件至少應有一個相關的檢視,相反,檢視只能與一個文件向關聯。
CCExcmpleDoc 類的基類為CDocument 類,CDocument 類為使用者定義的文件類提供了基本
的功能,框架通過使用CDocument 提供的介面來操作文件,使用者通過與文件相關聯的CView
物件來與之互動。
CCExcmpleView 類的基類為CView,CView 類為使用者定義的檢視類CCExcmpleView 提供了
基本功能,檢視是資料的使用者視窗,為使用者提供了文件資料的可視顯示,它在視窗中顯示文
檔的內容,檢視還給使用者提供了一個與文件中的資料互動的介面,它把使用者的輸入轉換為對
文件中的資料的操作。每個文件都會與一個或多個檢視相關聯,甚至可以與多個不同的檢視
相關聯。
檢視類裡面的幾個重要函式:
CCExcmpleDoc* CCExcmpleView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCExcmpleDoc)));
return (CCExcmpleDoc*)m_pDocument;
}
解析:每個檢視物件只有一個文件與其相關聯,使用者可以通過該檢視物件的成員函式
GetDocument 獲取與其關聯的文件,然後,就可以在檢視類中對文件類的公有成員函式及成
員變數進行訪問。
void CCExcmpleView::OnInitialUpdate()
{
CView::OnInitialUpdate();
}
解析:在檢視與文件關聯後,在檢視顯示之前,或者當用戶選擇了“File|New”或“File|Open”
時,框架就會呼叫此虛擬函式,它呼叫基類的OnInitialUpdate();函式。
void CView::OnInitialUpdate()
{
OnUpdate(NULL, 0, NULL); // initial update
}
在基類裡面又呼叫了 OnUpdate 函式
void CView::OnUpdate(CView* pSender, LPARAM /*lHint*/, CObject* /*pHint*/)
{
ASSERT(pSender != this);
UNUSED(pSender); // unused in release builds
// dxq 使整個面板無效,同時擦除背景
Invalidate(TRUE);
}
它的功能主要包括:讀取文件資料,然後對檢視物件的資料成員或控制進行更新,以便反映
文件的便哈,還可以使檢視的部分客戶區無效,就有WM_PAINT 訊息產生,從而觸發對函
數OnDraw 的呼叫,利用更新後的文件資料對視窗進行重繪。
OnDraw 函式:此函式為虛擬函式,必須在派生類中過載此函式,它主要由框架來呼叫,以呈
現文件資料,依據其引數不同,可以分別完成螢幕顯示,列印以及列印預覽等任務,在MFC
應用程式中,幾乎所有的繪製操作都是在OnDraw 中完成的(滑鼠繪製除外)。