標(biāo)題:
MFC相關(guān)理解
[打印本頁]
作者:
heise
時間:
2014-8-18 01:10
標(biāo)題:
MFC相關(guān)理解
為了進(jìn)行繪圖操作,必須獲得一個設(shè)備描述表(或設(shè)備上下文)DC,
當(dāng)構(gòu)造了一個GDI對象后,該對象并不會立即生效,必須選入設(shè)備描述表DC,它才會在以后的繪制操作中生效;
利用SelectObject函數(shù)可以實現(xiàn)把GDI對象選入設(shè)備描述表DC中,并且該函數(shù)會返回指向先前被選對象的指針,這個指針主要是為了在完成當(dāng)前的繪制操作后,還原設(shè)備描述表用的。
一般情況下,在完成繪圖操作后,要利
用
SelectObject函數(shù)把先前的GDI對象選入設(shè)備描述表,以便使其恢復(fù)到先前的狀態(tài);
GDI
圖形設(shè)備接口(GDI:Graphics DeviceInterface)是Windows的子系統(tǒng),它負(fù)責(zé)在視訊顯示器和打印機上顯示圖形。正如您所認(rèn)為的那樣,GDI是Windows非常重要的部分。不只您為Windows編寫的應(yīng)用系統(tǒng)在顯示視覺信息時使用GDI,就連Windows本身也使用GDI來顯示使用者接口對象,諸如菜單、滾動條、圖標(biāo)和鼠標(biāo)光標(biāo)。
GDI是C++中常用的一種圖形圖像工具,VB、Delphi等語言也移植了GDI ,.net的諸多語言甚至完全采用GDI作為繪制其界面。在Windows系統(tǒng)下,幾乎所有的API都是直接針對C語言的,除C/C++可直接使用這些API外,其它各種語言都必須移植這些API方法,而唯獨GDI,微軟提供的Gdiplus頭文件,從類型定義到方法接口,都是針對C++寫的,這就使得C語言沒法使用這些面向?qū)ο蟮姆椒,即使是GDI提供的原始API,如果不重新定義其參數(shù)中眾多的數(shù)據(jù)類型,C語言也是沒法使用的。
也許是因為C語言不適合編寫Windows界面應(yīng)用程序,所以至今沒有發(fā)現(xiàn)GDI的C版本(可能有,但沒發(fā)現(xiàn))。GDI沒C版本的一個可能的原因是:C版本中的眾多的重載函數(shù),缺省參數(shù),用C來寫卻是頭都大了,不知道用什么函數(shù)名才好(考慮GDI使用了這些年,新的函數(shù)名不應(yīng)與原函數(shù)名偏離太遠(yuǎn))。
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
CPen pen(PS_SOLID, 1, RGB(255,0,0));
CClientDC dc(this);
CPen *pOldPen = dc.
SelectObject(&pen);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
dc.
SelectObject(pOldPen);
CView::OnLButtonUp(nFlags, point);
}
void CDrawView::OnLButtonUp( UINT nFlags, CPoint point){ HDC hdc; hdc = ::GetDC(m_hWnd);//獲取該窗口的設(shè)備描述表(上下文) MoveToEx(hdc, m_ptOrigin.x, m_ptOrigin.y, NULL);//移動到線條的起點 LineTo(hdc, point.x, point.y); //通過hdc畫線 ::ReleaseDC(m_hWnd, hdc);//用后一定要釋放,因為GetDC里面是申請了資源的}
在MFC中,所有的控件類都是由CWnd類派生的,因此控件實際上也是窗口;實際上,控件通常是作為對話框的子窗口而創(chuàng)建的。
對話框的種類:
對話框可分為:1.模態(tài)(Modal)對話框 2.非模態(tài)對話框(Modeless)
模態(tài)(Modal)對話框:模態(tài)對話框是指當(dāng)其顯示時,程序會暫停執(zhí)行,直到關(guān)閉這個模態(tài)對話框后,才能繼續(xù)執(zhí)行程序中其他人;模態(tài)對話框壟斷了用戶的輸入,當(dāng)一個模態(tài)對話框打開時,用戶只能與該對話框進(jìn)行交互,而其他用戶界面對象接收不到輸入信息;我們平時所遇到的大部分對話框都是模態(tài)對話框;
非模態(tài)對話框(Modeless):當(dāng)
非模態(tài)對話框(Modeless)顯示時,允許轉(zhuǎn)而執(zhí)行程序中其他的任務(wù),而不用關(guān)閉這個對話框。典型的例子是Windows提供的記事本程序中的“查找”對話框,該對話框不會壟斷用戶的輸入,打開“查找”對話框后,仍可以與其他用戶界面對象進(jìn)行交互,用戶可以一邊查找,一邊修改文章,這樣就大大方便了使用。
MFC為我們提供一個設(shè)備描述表的封裝類CDC,該類封裝了所有與繪圖相關(guān)的操作;該類提供了一個數(shù)據(jù)成員m_hDC,用來保存與CDC類相關(guān)的DC句柄。
CDC是MFC的DC【設(shè)備上下文/設(shè)備描述表】的一個類;
CDC中所有MFC的DC的基類.常用的CClientDC dc(this);就是CDC的子類(或稱
派生類
).
CDC等設(shè)備上下分類,都含有一個類的成員變量:m_nHdc;即HDC類型的句柄.
記住下面的一句話,會有助于你的理解:
MFC的類,是在用window API語句開發(fā)出來的有一定功能的小程序.(也可稱為類).使用它的默認(rèn)方法,就是,記住它的名字與參數(shù)(可以用筆記,代替腦記).
DC(
設(shè)備上下文
):
設(shè)備上下文
是一種包含有關(guān)某個設(shè)備(如顯示器或打印機)的繪制屬性信息的 Windows數(shù)據(jù)結(jié)構(gòu)。所有繪制調(diào)用都通過設(shè)備上下文對象進(jìn)行,這些對象封裝了用于繪制線條、形狀和文本的 Windows API。設(shè)備上下文允許在Windows 中進(jìn)行與設(shè)備無關(guān)的繪制。設(shè)備上下文可用于繪制到屏幕、打印機或者圖元文件。
設(shè)備上下文
是一種包含有關(guān)某個設(shè)備(如顯示器或打印機)的繪制屬性信息的Windows 數(shù)據(jù)結(jié)構(gòu)。所有繪制調(diào)用都通過設(shè)備上下文對象進(jìn)行,這些對象封裝了用于繪制線條、形狀和文本的Windows API。設(shè)備上下文允許在 Windows 中進(jìn)行與設(shè)備無關(guān)的繪制。設(shè)備上下文可用于繪制到屏幕、打印機或者圖元文件。
CPaintDC 對象將 Windows 的常見固定用語進(jìn)行封裝,調(diào)用 BeginPaint 函數(shù),然后在設(shè)備上下文中繪制,最后調(diào)用EndPaint 函數(shù)。CPaintDC 構(gòu)造函數(shù)為您調(diào)用BeginPaint,析構(gòu)函數(shù)則調(diào)用EndPaint。該簡化過程將創(chuàng)建 CDC 對象、繪制和銷毀 CDC 對象。在框架中,甚至連這個過程的大部分也是自動的。具體說來,框架給OnDraw 函數(shù)傳遞(通過 OnPrepareDC)準(zhǔn)備好的CPaintDC,您只需繪制到 CPaintDC 中。根據(jù)調(diào)用 OnDraw 函數(shù)的返回,CPaintDC 被框架銷毀并且將基礎(chǔ)設(shè)備上下文釋放給Windows。
CClientDC對象封裝對一個只表示窗口工作區(qū)的設(shè)備上下文的處理。CClientDC 構(gòu)造函數(shù)調(diào)用GetDC 函數(shù),析構(gòu)函數(shù)調(diào)用 ReleaseDC函數(shù)。CWindowDC 對象封裝表示整個窗口(包括其框架)的設(shè)備上下文。
CMetaFileDC 對象將繪制封裝到 Windows 圖元文件中。與傳遞給OnDraw 的 CPaintDC 相反,在這種情況下您必須自己調(diào)用 OnPrepareDC。
設(shè)備上下文(Device Context)DC
DC實際上是GDI內(nèi)部保存的數(shù)據(jù)結(jié)構(gòu)。
DC與特定的顯示設(shè)備(如顯示器或打印機)相關(guān)。
對于顯示器,DC總是與顯示器上的特定視窗相關(guān)。
DC中的有些值是圖形「屬性」,這些屬性定義了GDI繪圖函數(shù)工作的細(xì)節(jié)。
例如,對於TextOut,DC的屬性確定了文字的顏色、文字的背景色、x坐標(biāo)和y坐標(biāo)映射到視窗的顯示區(qū)域的方式,以及顯示文字時Windows使用的字體。
MSDN的解釋:一個DC是一個結(jié)構(gòu),它定義了一系列圖形對象的集合以及它們相關(guān)的屬性,以及影響輸出效果的一些圖形模式。這些圖形對象包括一個畫線的筆,一個填充和painting的畫刷,一個用來向屏幕拷貝的位圖,一個定義了一系列顏色集合的調(diào)色板,一個用來剪裁等操作的區(qū)域,一個做painting和drawing操作的路徑。
一個應(yīng)用程序從不直接地訪問(access)dc,常見的取得dc的方式有以下幾種:
SDK's way:
1. BeginPaint
case WM_PAINT: HDC hdc = BeginPaint(hwnd, &ps);EndPaint(hwnd, &ps);
MSDN的解釋: BeginPaint函數(shù)自動地設(shè)置dc的剪裁區(qū)域,這個剪裁區(qū)域,剪裁的是由InvalidateRect或 InvalidateRgn 函數(shù)觸發(fā)的窗口無效區(qū)域,或者是系統(tǒng)給出的無效區(qū)域,當(dāng)窗口被sizing,moving, creating, scrolling, or any other operation that affectsthe client area.
一個應(yīng)用程序從不調(diào)用BeginPaint,除了在收到一個WM_PAINT消息的時候;每一BeginPaint調(diào)用之后,需要調(diào)用EndPaint函數(shù)。
2.GetXXXDC
GetDC取得與窗口客戶區(qū)相關(guān)的dc,GetWindowDC取得與整個窗口(包括客戶區(qū)和非客戶區(qū))相關(guān)的dc。
還有一類重要的dc,內(nèi)存DC,是一個虛擬的內(nèi)存設(shè)備上下文,我們對它進(jìn)行繪圖等操作,不會顯示在屏幕或打印機上,而我們可以在它完成之后,拷貝到屏幕上或打印機上來輸出,這樣我們可以避免因為操作而給屏幕帶來的閃爍,對于打印機而言,打印只能是從上往下打,而我們在MEMDC中,可以隨意進(jìn)行操作,這樣可以輸出直接在打印機上輸出所達(dá)不到的效果.
在窗口上貼圖一般總是要用到內(nèi)存DC,將所有的繪制工作先繪制在內(nèi)存DC上,然活一次性拷貝到屏幕DC上,就是這樣了。
這里是使用mfc進(jìn)行的說明,對hdc進(jìn)行了封裝,但是道理是一樣的。
1.創(chuàng)建內(nèi)存DC
CDC m_MenDC; //聲明內(nèi)存DC
CDC m_MenDC2; //聲明內(nèi)存DC
CBitmap m_Bitmap1; //聲明一個位圖
m_MenDC.CreateCompatibleDC(GetDC());//創(chuàng)建內(nèi)存DC
m_MenDCMap.CreateCompatibleDC(GetDC());//創(chuàng)建內(nèi)存DC
m_Bitmap1.CreateCompatibleBitmap(GetDC(),1024,768);//創(chuàng)建一個兼容位圖,這是一個空的位圖,我們可以把它想象成一個屏幕,可以在上面畫線,輸出文字等,自己制作一個簡單的位圖。
m_hbmpBK =(HBITMAP)::LoadImage(AfxGetInstanceHandle(),path+"Bk4.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
//我們也可以從硬盤導(dǎo)入一張位圖。
2,為內(nèi)存DC選入一張位圖,或兼容位圖。
m_MenDC.SelectObject(m_hbmpBK);
m_MenDC2.SelectObject(m_Bitmap1);
注意,想要在內(nèi)存dc上作圖,必須先為它選入一張位圖,或兼容位圖。想想前面,不管BeginPaint還是getDC都有一個相關(guān)的區(qū)域。這里的位圖就是相關(guān)區(qū)域。
3.接著我們就可以像在窗口上作圖一樣,使用gdi函數(shù)(drawline,textout...)在內(nèi)存dc上作圖了。同時也可以從一個內(nèi)存dc拷貝位圖到另一個內(nèi)存dc。
m_MenDC2.BitBlt(0,0,1024,768,&m_MenDC,0,0,SRCCOPY);
4,繪制結(jié)果的顯示,將這些東西拷到屏幕DC(getdc取得的dc)上
// 所謂的雙緩沖就是把所有的繪制工作都做在一個內(nèi)存DC上。
// 最后一次拷到屏幕DC上,只能有一次
dc.BitBlt(0,0,1024,768,&m_MenDC2,0,0,SRCCOPY);//這里的dc是通過getdc取得的屏幕或者某個窗口的dc。
這里所強調(diào)的“一次”;是不要連續(xù)將幾個內(nèi)存DC的內(nèi)容都拷到屏幕DC上,這樣沒有起到雙緩沖的效果。如果你搞了很多個內(nèi)存DC,想把這些東西都顯示出來,那你應(yīng)該先把這多個內(nèi)存DC的內(nèi)容同時拷到另外一個內(nèi)存DC上,再把這個內(nèi)存DC的內(nèi)容拷到屏幕DC上。
CPaintDC dc(this);MFC的CPaintDC類是從MFC的CDC類派生的,CDC類封裝了Windows設(shè)備環(huán)境,以及包含了繪制到屏幕、打印機和其他設(shè)備的幾十個成員函數(shù)
在MFC程序中,我們并不經(jīng)常直接調(diào)用Windows API,而是從MFC類創(chuàng)建對象并調(diào)用屬于這些對象的成員函數(shù).也就是說MFC封裝了Windows API 你說你喜歡C++而MFC換一種說法就是一個用C++寫的一個函數(shù)庫 然后你來調(diào)用 只不過這個類不是你寫的
MFC提供數(shù)百個類,最重要的、也是編寫任何VC++應(yīng)用程序都必不可少的兩個類CWinApp和CFrameWnd,這兩個類是編寫復(fù)雜龐大應(yīng)用程序的基石。
1>封裝特性:構(gòu)成MFC框架的是MFC類庫而MFC類庫又是C++的一個類庫。這些類封裝WIN32應(yīng)用程序編程接口,OLE(Object Link Embed 對象鏈接嵌入)特性,ODBC和DAO數(shù)據(jù)訪問的功能。
2>繼承特性:MFC抽象出了眾多類的共同特性,并設(shè)計出一些基類作為實現(xiàn)其他類的基礎(chǔ),這些類中最重要的類是CObject類和CCmdTarget類,程序員可以從適當(dāng)?shù)腗FC類中派生出自己的類,實現(xiàn)特定的功能達(dá)到編程的目的。
3>虛擬和消息映射:MFC是以C++為基礎(chǔ),當(dāng)然支持虛函數(shù),但作為一個編程框架必須要解決的是效率問題:如果MFC僅僅通過虛函數(shù)來支持動態(tài)約束必然會產(chǎn)生大量的虛函數(shù)表這樣編程框架過于臃腫而且消耗更多的內(nèi)存。但是MFC建立了消息映射機制這樣降低了內(nèi)存的使用卻大大提高了效率
消息映射是一個將消息和成員函數(shù)相互關(guān)聯(lián)的表,當(dāng)應(yīng)用程序的框架窗口接收到一個消息時,MFC將搜索該窗口的消息映射,如果存在一個處理消息的處理程序,那么就調(diào)用該處理程序.
它通過宏來實現(xiàn)消息到成員函數(shù)的映射,而且這些函數(shù)不必是虛擬的成員函數(shù),這樣不需要為消息映射函數(shù)生成一個很大的虛擬函數(shù)表(V表),節(jié)省內(nèi)存。
MFC消息映射機制:
將消息與消息處理函數(shù)聯(lián)系起來,形成一一對應(yīng)的機制。
消息映射宏
聲明: DECLARE_MESSAGE_MAP
定義:
BEGIN_MESSAGE_MAP
ON_COMMAND
ON_CONTROL
ON_MESSAGE
END_MESSAGE_MAP
MFC主要組成部分:類、宏和全局函數(shù)。
類是MFC中最主要的內(nèi)容。MFC類是以層次結(jié)構(gòu)方式組織起來的。MFC中的類分成兩部分,除了一些輔助類,大多數(shù)的MFC類是直接或間接從根類CObject派生而來。
MFC宏主要功能:消息映射、運行時對象類型服務(wù)、診斷服務(wù)、異常處理。
MFC約定:全局函數(shù)以“Afx”為前綴,全局變量以“afx”為前綴
MFC類的層次關(guān)系
CObject項目類)->CCmdTarget(消息響應(yīng)類)->
{
CWinThread(線程類)->CWinApp(Window應(yīng)用程序類)
CDocument(文檔類)
CWnd(窗體類)->[
CFrameWnd(框架類)
CView(視圖類)
]
}
CObject類由于MFC中大部分類是從CObject類繼承而來的,CObject類描述了幾乎所有的MFC類的一些公共特性,CObject類為程序員提供了對象診斷、運行時類型識別和序列化等功能。
CCmdTarget類由CObject類直接派生而來,它負(fù)責(zé)將消息發(fā)送到能夠響應(yīng)這些消息的對象。它是所有能進(jìn)行消息映射的MFC類的基類。
CWinApp類在任何MFC應(yīng)用程序中有且僅有一個CWinApp派生類的對象,它代表了程序中運行的主線程,也代表了應(yīng)用程序本身。 CWinApp類取代了WinMain()主函數(shù)在SDK應(yīng)用程序中的地位。傳統(tǒng)SDK應(yīng)用程序WinMain()函數(shù)完成的工作。現(xiàn)在由類CWinApp的InitApplication(),InitInstance()和Run()三個成員函數(shù)承擔(dān)。
CWnd類由CCmdTarget類直接派生而來,該類及其派生類的實例是一個窗口。CWnd類代表了MFC中最基本的GUI對象,它是一個功能最完善、成員函數(shù)最多的MFC類。
CFrameWnd類是CWnd類的派生類,主要用來掌管一個窗口,它取代了SDK應(yīng)用程序中窗口函數(shù)WndProc()的地位。CFrameWnd類的對象是一個框架窗口,包括邊框、標(biāo)題欄、菜單、最大化按鈕、最小化按鈕和一個激活的視圖。
CDocument類在應(yīng)用程序中作為用戶文檔類的基類,它代表了用戶存儲或打開的一個文件。
CView類是MFC中一個很基本的類,它作為其它MFC視圖類和用戶視圖派生類的基類。
從API編程到MFC編程的過渡:
WinMain()
{ 初始化WNDCLASS
注冊窗體結(jié)構(gòu)
創(chuàng)建窗口 ->>>>>>>>應(yīng)用程序類CWinApp
顯示窗口
消息循環(huán)
}
WndProc()
{ switch(…)
->>>>>>>>>框架窗口類CFrameWnd
}
MFC Object和Windows Object的對應(yīng)關(guān)系:
描述 Windows句柄 MFC Object
窗口 HWND CWnd
設(shè)備上下文 HDC CDC
菜單 HMENU CMenu
筆 HPEN CPen
刷子 HBRUSH CBrush
字體 HFONT CFont
位圖 HBITMAP CBitmap
套接字 SOCKET CSocket
三、手工創(chuàng)建一個MFC應(yīng)用程序:
注意:創(chuàng)建MFC程序,要創(chuàng)建一個Win32空項目,并要選擇項目屬性中的”在共享DLL文件中使用MFC,然后新建我們的文件
例子:在”hello.h”頭文件中添寫如下代碼:
class CMyApp:public CWinApp
{
public:
virtual BOOL InitInstance();//虛函數(shù)
};
class CMainWindow:public CFrameWnd
{
public:
CMainWindow();
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP();//聲明消息映射
};
在”hello.cpp”源文件中添寫如下代碼:
#include
#include “hello.h"
CMyApp myApp;
BOOL CMyApp::InitInstance()
{
m_pMainWnd = new CMainWindow;
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return TRUE;
}
BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)
ON_WM_PAINT()
END_MESSAGE_MAP() //消息映射
CMainWindow::CMainWindow() //構(gòu)造函數(shù)初始化
{
Create(NULL,“我的第一個MFC應(yīng)用程序”);//創(chuàng)建窗體
}
void CMainWindow::OnPaint()
{ CPaintDC dc(this);
CRect rect;
GetClientRect(&rect);
dc.DrawText("Hello MFC",-1,&rect, DT_SINGLELINE|DT_CENTER|DT_VCENTER);
}
CWinApp是應(yīng)用程序類,在MFC應(yīng)用程序中必須從這個類派生出一個類,該派生類是MFC應(yīng)用程序的入口
必須定義這個派生類的對象,并且只能有一個這個對象代表整個應(yīng)用程序。
成員函數(shù):InitInstance()
功能:初始化應(yīng)用程序?qū)嵗痛翱趯嵗?br /> 虛函數(shù)CWinApp::InitInstance必須在派生類中重寫。在InitInstance函數(shù)中,編寫初始化代碼,如:
創(chuàng)建一個窗口
顯示一個窗口
CFrameWnd類
作用:為應(yīng)用程序提供一個窗口,同時實現(xiàn)消息處理功能。
成員函數(shù): Create()
功能:創(chuàng)建窗體,將之賦于CFrameWnd對象上。
BOOL Create(窗口類型, 窗口標(biāo)題,顯示風(fēng)格,顯示區(qū)域,符窗口句柄,菜單,擴(kuò)展顯示風(fēng)格,上下文對象)共有8個參數(shù),前兩個必須給出,后6個可以默認(rèn)。
MFC應(yīng)用程序的核心就是基于CWinApp類的應(yīng)用程序?qū)ο?CWinApp提供了消息循環(huán)來檢索消息并將消息調(diào)度給應(yīng)用程序的窗口.我們在編寫MFC應(yīng)用程序時,要包含afxwin.h,
一個MFC應(yīng)用程序可以有且僅有一個應(yīng)用程序?qū)ο?對象必須聲明為在全局范圍內(nèi)有效(也就是全局對象),以便它在程序開始時即在內(nèi)存中被實例化
我們的Hello MFC的應(yīng)用程序類被命名為CMyApp,它在hello.cpp中用如下語句進(jìn)行了實例化:
CMyApp myApp;
CMyApp的類聲明在hello.h中代碼如下:
class CMyApp:public CWinApp
{
public:
virtual BOOL InitInstance();
};
CMyApp沒有聲明任何的數(shù)據(jù)成員,只是重寫了一個從CWinApp類中繼承來的函數(shù),在應(yīng)用程序的生存期內(nèi)InitInstance的調(diào)用比較早,是在應(yīng)用程序開始運行以后而窗口創(chuàng)建之前,除非InitIstance創(chuàng)建一個窗口,否則應(yīng)用程序是不會有窗口,這正是為什么即使最小的MFC應(yīng)用程序也必須從CWinApp派生出一個類并重寫CWinApp::InitIstance的原因
InitInstance函數(shù):CWinApp::InitInstance是一個虛函數(shù),其默認(rèn)操作僅包含一條語句:return TRUE;
InitInstance是用來執(zhí)行程序每次開始時都需要進(jìn)行的初始化工作最好的地方
在hello.cpp中,CMyApp的InitInstance通過實例化hello的CMainWindow類來創(chuàng)建hello窗口,語句:
m_pMainWnd = new CMainWindow;
構(gòu)造了一個CMainWindow對象指針,并將其地址復(fù)制到了應(yīng)用程序?qū)ο蟮膍_pMainWnd數(shù)據(jù)成員中,窗口創(chuàng)建以后,InitInstance就會通過CMainWindow指針調(diào)用ShowWindow和UpdateWindow函數(shù)顯示它:
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
ShowWindow和UpdateWindow是所有窗口對象共用的CWnd成員函數(shù)其中包括CFrameWnd類的對象,CMainWindow就是從CFrameWnd派生出來的.
要從MFC程序調(diào)用一個常規(guī)的Windows API函數(shù),需要在函數(shù)名稱前添加一個全局運算符:: 例如:::UpdateWindow();
通過生成窗口對象并調(diào)用其Create函數(shù),MFC應(yīng)用程序可以創(chuàng)建一個窗口,在CMyApp::InitInstance中,hello創(chuàng)建了一個CMainWindow對象,CMainWindow的構(gòu)造函數(shù)生成在屏幕上看到的窗口:
Create(NULL,”我的第一個MFC應(yīng)用程序”);
CPaintDC dc(this);
MFC的CPaintDC類是從MFC的CDC類派生的,CDC類封裝了Windows設(shè)備環(huán)境,以及包含了繪制到屏幕、打印機和其他設(shè)備的幾十個成員函數(shù)
在MFC中如何處理消息呢?
在SDK中我們利用的是消息循環(huán)和窗口過程函數(shù)對消息進(jìn)行消息處理.
在MFC中我們用的是消息映射機制.
下面是將消息映射添加到一個類中需要做的全部工作.
1>通過將DECLARE_MESSAGE_MAP語句添加到類聲明中,聲明消息映射.
2>通過放置標(biāo)識消息的宏來執(zhí)行消息映射,相應(yīng)的類將在對BEGIN_MESSAGE_MAP和END_MESSAGE_MAP的調(diào)用之間處理消息
3>添加成員函數(shù)來處理消息
1、構(gòu)造CWinApp派生類的對象
2、系統(tǒng)調(diào)用WinMain()
3、WinMain調(diào)用InitInstance,在該函數(shù)中創(chuàng)建CFrameWnd派生類對象,調(diào)用Create函數(shù)創(chuàng)建窗口、調(diào)用ShowWindow函數(shù)顯示窗口。
4、之后內(nèi)部機制調(diào)用Run,接受用戶的消息,并將消息導(dǎo)向默認(rèn)的處理函數(shù)。當(dāng)接收到WM_QUIT消息時,Run內(nèi)部調(diào)用ExitInstance,退出程序。
MFC采用消息映射(Message Map)機制取代C/C++語言中的switch-case結(jié)構(gòu)來處理消息。
消息映射:在MFC中把消息處理函數(shù)和它所要處理的特定的消息連接起來的一種機制。
它通過宏來實現(xiàn)消息到成員函數(shù)的映射,而且這些函數(shù)不必是虛擬的成員函數(shù),這樣不需要為消息映射函數(shù)生成一個很大的虛擬函數(shù)表(V表),節(jié)省內(nèi)存。
MFC消息映射機制包括一組消息映射宏。一條消息映射宏把一個Windows消息和其消息處理函數(shù)聯(lián)結(jié)起來。
MFC應(yīng)用程序框架提供了消息映射功能。
在類的實現(xiàn)源文件中用BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()宏來定義消息映射。
在類定義的結(jié)尾用DECLARE_MESSAGE_MAP()宏來聲明使用消息映射。
Hello的CmainWindow類只處理一種消息類型—WM_PAINT,因此其消息映射的實現(xiàn)如下所示:
BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd);
ON_WM_PAINT()
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP開始了消息映射,并標(biāo)識了消息映射所屬的類和該類的基類
END_MESSAGE_MAP()結(jié)束消息映射.
ON_WM_PAINT()在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP()之間,稱做消息條目,在MFC為100多種Window消息提供了宏.
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
afx_msg 醒目地暗示OnPaint是一個消息處理程序,
DECLARE_MESSAGE_MAP()聲明消息映射
MFC把消息主要分為三大類:
(1)、標(biāo)準(zhǔn)Windows消息(WM_XXX)
使用宏:ON_WM_XXX() 特點:有默認(rèn)的消息處理函數(shù)
(2)、命令消息:(WM_COMMAND)
來自于菜單、工具條、按鈕等的消息
使用宏: ON_COMMAND(命令按鈕標(biāo)識符ID,消息處理函數(shù))
特點:由用戶指定消息處理函數(shù)
3、”Notification消息” (通知消息) 由控件產(chǎn)生:
BOOL 布爾值,取值為TRUE或者FALSE
BSTR 32為字符指針
BYTE 8位整數(shù)無符號的
COLORREF 32位數(shù)值代表一個顏色值
DWORD 32位整數(shù)無符號的
LONG 32位整數(shù)帶符號的
LPCTSTR 32位指針,指向一個常字符串
LPVOID 32位指針,指向一個為指定類型的數(shù)據(jù)
MFC特有的數(shù)據(jù)類型:
1>POSITION :一個數(shù)值,代表數(shù)組或者鏈表中元素的位置,在MFC中常用于數(shù)據(jù)處理類
2>LPRECT:32位指針,指向一個不變的矩形區(qū)域結(jié)構(gòu)
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1