MFC常見問題解惑[轉]

來源:互聯網
上載者:User

標籤:des   blog   http   color   使用   os   io   strong   

MFC類的分類

1 Root: CObject :  CObject
2 Application Architecture Classes: CWinApp/CFrameWnd/...

3 Window, Dialog, and Control Classes:CWnd/CDialog/...
4 Drawing and Printing Classes : CGdiObject/CPrintInfo/...
5 Simple Data Type Classes :CString/CRect/...
6 Array, List, and Map Classes :CTypedPtrArray/...
7 File and Database Classes : CStdioFile/CDatabase/...
8 Internet and Networking Classes : CSocket/...
9 OLE Classes...
10 Debugging and Exception Classes: CMemoryState/CException/...

OnCreate InitDialog區別:

WM_CREATE的時候視窗還沒有建立,你可以給成員變數賦值,也可以修改視窗的基本內容比如風格,但是不能對視窗控制項操作,因為視窗還沒有建立。 
INITDIALOG時候視窗已經建立,你可以移動視窗,修改風格等等,也可以給成員變數賦值,

通常你要先建立(OnCreate)一個表單,然後再對他進行初始化(OninitDialog).

WM_INITDIALOG 
The   WM_INITDIALOG   message   is   sent   to   the   dialog   box   procedure   immediately   before   a   dialog   box   is   displayed. 
WM_CREATE 
The   WM_CREATE   message   is   sent   when   an   application   requests   that   a   window   be   created   by   calling   the   CreateWindowEx   or   CreateWindow   function.

 

Create與OnCreate的區別:

      OnCreate是一個訊息響應函數,是響應WM_CREATE訊息的一個函數,而WM_CREATE訊息是由Create函數調用(#add 發生?)的。

 

  在view類中,Create 是虛函數由架構調用,是用來“產生一個視窗的子視窗”。 而OnCreate 函數是用來“表示一個視窗正在產生”。

 

  一個視窗建立(Create)之後,會向作業系統發送WM_CREATE訊息,OnCreate()函數主要是用來響應此訊息的。因為在MFC裡面用一種訊息映射的機制來響應訊息,也就是可以用函數來響應相應的訊息。就拿CMainFrame類來說,當視窗建立後會產生WM_CREATE訊息,我們可以在OnCreate函數裡實現我們要在視窗裡面增加的東西,例如按扭,狀態列,工具列等。這些子視窗一般是定義成類中的一個成員變數,因為要保證生命週期。一般以m_開頭來表示成員(member)。

 

  OnCreate()不產生視窗,只是在視窗顯示前設定視窗的屬性如風格、位置等,Create()負責註冊併產生視窗

 

  Create()不是對應於訊息WM_CREATE的,OnCreate()才是。Create()只用於產生視窗,像動態建立控制項中的Create()一樣。

 MSDN:

The CWnd object receives this call after the window is created but before it becomes visible. OnCreate is called before the Create or CreateEx member function returns.

Override this member function to perform any needed initialization of a derived class.

 

OnDraw和OnPaint區別:

OnPaint是WM_PAINT訊息的訊息處理函數,在OnPaint中調用OnDraw,一般來說,使用者自己的繪圖代碼應放在OnDraw中。

OnPaint()是CWnd的類成員,負責響應WM_PAINT訊息。OnDraw()是CVIEW的成員函數,沒有響應訊息的功能.當視圖變得無效時(包括大小的改變,移動,被遮蓋等等),Windows發送WM_PAINT訊息。該視圖的OnPaint 處理函數通過建立CPaintDC類的DC對象來響應該訊息並調用視圖的OnDraw成員函數.OnPaint最後也要調用OnDraw,因此一般在OnDraw函數中進行繪製。


The WM_PAINT message is sent when the UpdateWindow or RedrawWindow member function is called.


在OnPaint中,將調用BeginPaint,用來獲得客戶區的顯示裝置環境,並以此調用GDI函數執行繪圖操作。在繪圖操作完成後,將調用EndPaint以釋放顯示裝置環境。而OnDraw在BeginPaint與EndPaint間被調用。

1) 在mfc結構裡OnPaint是CWnd的成員函數. OnDraw是CView的成員函數.(#add 當然CView 是CWnd的子類)
2) OnPaint()調用OnDraw(),OnPrint也會調用OnDraw(),所以OnDraw()是顯示和列印的共同操作。

OnPaint是WM_PAINT訊息引發的重繪訊息處理函數,在OnPaint中會調用OnDraw來進行繪圖。OnPaint中首先構造一個CPaintDC類得執行個體,然後一這個執行個體為參數來調用虛函數OnPrepareDC來進行一些繪製前的一些處理,比設定映射模式,最後調用OnDraw。而OnDraw和OnPrepareDC不是訊息處理函數。所以在不是因為重繪訊息所引發的OnPaint導致OnDraw被調用時,比如在OnLButtonDown等訊息處理函數中繪圖時,要先自己調用OnPrepareDC。 
至於CPaintDC和CClientDC根本是兩回事情 CPaintDC是一個裝置環境類,在OnPaint中作為參數傳遞給OnPrepareDC來作裝置環境的設定。真正和CClientDC具有可比性的是CWindowDC,他們一個是描述用戶端區域,一個是描述整個螢幕。
如果是對CVIEW或從CVIEW類派生的視窗繪圖時應該用OnDraw。


OnDraw()和OnPaint()有什麼區別呢?
首先:我們先要明確CView類派生自CWnd類。而OnPaint()是CWnd的類成員,同時負責響應WM_PAINT訊息。OnDraw()是CVIEW的成員函數,並且沒有響應訊息的功能。這就是為什麼你用VC成的程式碼時,在視圖類只有OnDraw沒有OnPaint的原因。而在基於對話方塊的程式中,只有OnPaint(#add,因為沒有VIEW類)。
其次:我們在第《每天跟我學MFC》3的開始部分已經說到了。要想在螢幕上繪圖或顯示圖形,首先需要建立裝置環境DC。其實DC是一個資料結構,它包含輸出裝置(不單指你17寸的純屏顯示器,還包括印表機之類的輸出裝置)的繪圖屬性的描述。MFC提供了CPaintDC類和CWindwoDC類來即時的響應,而CPaintDC支援重畫。當視圖變得無效時(包括大小的改變,移動,被遮蓋等等),Windows 將 WM_PAINT 訊息發送給它。該視圖的OnPaint 處理函數通過建立 CPaintDC 類的DC對象來響應該訊息並調用視圖的 OnDraw 成員函數。通常我們不必編寫重寫的 OnPaint 處理成員函數。
///CView預設的標準的重畫函數 
void CView::OnPaint() //見VIEWCORE.CPP,這是源碼
{

CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);    //調用了OnDraw
}
///CView預設的標準的OnPrint函數
void CView::OnPrint(CDC* pDC, CPrintInfo*)
{
ASSERT_VALID(pDC);
OnDraw(pDC);   // Call Draw
}

既然OnPaint最後也要調用OnDraw,因此我們一般會在OnDraw函數中進行繪製。下面是一個典型的程式。
///視圖中的繪圖代碼首先檢索指向文檔的指標,然後通過DC進行繪圖調用。
void CMyView::OnDraw( CDC* pDC )
{

CMyDoc* pDoc = GetDocument();
CString s = pDoc->GetData();
GetClientRect( &rect ); // Returns a CString CRect rect;
pDC->SetTextAlign( TA_BASELINE | TA_CENTER );
pDC->TextOut( rect.right / 2, rect.bottom / 2, s, s.GetLength() );
}
最後:現在大家明白這哥倆之間的關係了吧。因此我們一般用OnPaint維護視窗的客戶區(例如我們的視窗客戶區加一個背景圖片),用OnDraw維護視圖的客戶區(例如我們通過滑鼠在視圖中畫圖)。當然你也可以不按照上面規律來,只要達到目的並且沒有問題,怎麼幹都成。補充:我們還可以利用Invalidate(),ValidateRgn(),ValidateRect()函數強制的重畫視窗,具體的請參考MSDN吧。


OnDraw中可以繪製使用者地區。OnPaint中只是當視窗無效時重繪不會保留CClientDC繪製的內容。

這兩個函數有區別也有聯絡:

1、區別:OnDraw是一個純虛函數,定義為virtual void OnDraw( CDC* pDC ) = 0; 而OnPaint是一個訊息響應函數,它響應了WM_PANIT訊息,也是是視窗重繪訊息。

2、聯絡:我們一般在視類中作圖的時候,往往不直接響應WM_PANIT訊息,而是重載OnDraw純虛函數,這是因為在CVIEW類中的WM_PANIT訊息響應函數中調用了OnDraw函數,如果在CMYVIEW類中響應了WM_PAINT訊息,不顯式地調用OnDraw函數的話,是不會在視窗重繪的時候調用OnDraw函數的。

應用程式中幾乎所有的繪圖都在視圖的 OnDraw 成員函數中發生,必須在視圖類中重寫該成員函數。(滑鼠繪圖是個特例,這在通過視圖解釋使用者輸入中討論。)


OnDraw 重寫:
通過調用您提供的文檔成員函數擷取資料。
通過調用架構傳遞給 OnDraw 的裝置上下文對象的成員函數來顯示資料。
當文檔的資料以某種方式更改後,必須重繪視圖以反映該更改。預設的 OnUpdate 實現使視圖的整個工作區無效。當視圖變得無效時,Windows 將 WM_PAINT 訊息發送給它。該視圖的 OnPaint 處理函數通過建立 CPaintDC 類的裝置上下文對象來響應該訊息並調用視圖的 OnDraw 成員函數。

當沒有添加WM_PAINT訊息處理時,視窗重繪時,由OnDraw來進行訊息響應...當添加WM_PAINT訊息處理時,視窗重繪時,WM_PAINT訊息被投遞,由OnPaint來進行訊息響應.這時就不能隱式調用OnDraw了.必須顯式調用(   CDC *pDC=GetDC(); OnDraw(pDC);   )..(#add,在OnPaint函數中添加)
隱式調用:當由OnPaint來進行訊息響應時,系統自動調用CView::OnDraw(&pDC).


想象一下,視窗顯示的內容和列印的內容是差不多的,所以,一般情況下,統一由OnDraw來畫。視窗前景需要重新整理時,系統會會調用到OnPaint,而OnPaint一般情況下是對DC作一些初始化操作後,調用OnDraw()。


OnEraseBkGnd(),是視窗背景需要重新整理時由系統調用的。明顯的一個例子是設定視窗的背景顏色(你可以把這放在OnPaint中去做,但是會使產生閃爍的現象)。  
至於怎麼界定背景和前景,那要具體問題具體分析了,一般情況下,你還是很容易區別的吧。


的確,OnPaint()用來響應WM_PAINT訊息,視類的OnPaint()內部根據是列印還是螢幕繪製分別以不同的參數調用OnDraw()虛函數。所以在OnDraw()裡你可以區別對待列印和螢幕繪製。
其實,MFC在進行列印前後還做了很多工作,調用了很多虛函數,比如OnPreparePrint()等。


對於OnDraw() 
This method is called by the framework to render an image of the document. The framework calls this method to perform screen display, printing, and print preview, and it passes a different device context in each case. There is no default implementation.

 

OnDrawItem與DrawItem的區別:

1.OnDrawItem:  WM_DRAWITEM訊息的訊息處理函數

  子控制項有自畫屬性且控制項需重畫時,父視窗會調用該函數,在具有Owner Draw屬性的控制項需要重畫的時候,就會激發OnDrawItem

  當自畫子按鈕控制項、下拉式方塊控制項、列表框控制項或菜單的可視部分需要被畫出時調用這個函數

  OnDrawItem()-àDrawItem();

2.DrawItem: 虛函數,需要重載

  如果使用DrawItem來自畫控制項,需要給控制項加上自畫(owner draw)樣式,然後重載該控制項類的自畫函數(DrawItem)函數,如果該控制項的父視窗提供了ON_WM_DRAWITEM訊息映射宏,並重載了OnDrawItem函數,則重畫訊息會由父視窗處理,父視窗調用基類的OnDrawItem來調用派生的子控制項的DrawItem函數.

 (#add 似乎有表述錯誤,像"重載了OnDrawItem函數"這句,真他媽的sb說的話, 仍未徹底明白,待解決)

 

OnCtlColor CtlColor區別:

OnCtlColor是父視窗中的訊息響應函數,用來處理子控制項的繪製,

CtlColor是子控制項中的響應函數,這種控制項擁有自繪功能,由他自己來繪製,屬訊息反射機制.

OnCtlColor是響應子控制項發來的WM_CTLCOLOR訊息,

CtlColor是反射控制項自己發出的WM_CTLCOLOR訊息。

 

ClientToScreen和 ScreenToClient 區別:

ClientToScreen( )是把視窗座標轉換為螢幕座標

ScreenToClient( )是把螢幕座標轉換為視窗座標
螢幕座標是相對於螢幕左上方的,而視窗座標是相對於視窗使用者區左上方的
VC下,有些函數使用視窗座標,有些使用螢幕座標,使用時要分清。

一個表單分為兩部分:系統區和客戶區
象標題和菜單之類的是系統區,由系統來控制,客戶區就是你的地盤嘍!!!
Width, Height 是指整體的,ClientWidth, ClientHeight是指客戶區的,兩者相減就是
系統區的啦!!!
ClientToScreen是把座標從當前表單轉化成全螢幕的!!!
ScreenToClient是把螢幕座標轉化成相對當前表單的座標!!!!

 

WPARAM 和 LPARAM 的區別:

 wParam和lParam 這兩個是Win16系統遺留下來的產物,在Win16API中WndProc有兩個參數: 

一個是WORD類型的16位整型變數;另一個是LONG類型的32位整型變數。因此根據匈牙利命名法,16位的變數就被命名為wParam, 32位的變數就被命名為lParam。

到了Win32API中,原來的16位變數也被擴充為32位,因此此時wParam和lParam的大小完全相同。 
在Win32API的早期,為了保證和Win16API的代碼可移植性MS定義了WPARAM和LPARAM兩個宏。 
當時保留了w首碼的原因一方面是由於WPARAM宏也已W開頭,還有也因為要提醒程式員注意到可移植性,當然到了現在Win16早已退出曆史舞台,這個首碼也就約定俗成的沿用下來了。

 

Invalidate以及Invalidate(false)和Invalidate(true)的區別:

1.void Invalidate( BOOL bErase = TRUE ); 

 

  該函數的作用是使整個視窗客戶區無效。視窗的客戶區無效意味著需要重繪,例如,如果一個被其它視窗遮住的視窗變成了前台視窗,那麼原來被遮住的部分就是無效的,需要重繪。這時Windows會在應用程式的訊息佇列中放置WM_PAINT訊息。MFC為視窗類別提供了WM_PAINT的訊息處理函數OnPaint,OnPaint負責重繪視窗。視圖類有一些例外,在視圖類的OnPaint函數中調用了OnDraw函數,實際的重繪工作由OnDraw來完成。參數bErase為TRUE時,重繪地區內的背景將被擦除,否則,背景將保持不變。 

 

  它和 UpdateWindow( )區別在於: 

 

  UpdateWindow( )的作用是使視窗立即重繪。調用Invalidate等函數後視窗不會立即重繪,這是由於WM_PAINT訊息的優先順序很低,它需要等訊息佇列中的其它訊息發送完後才能被處理。調用UpdateWindow函數可使WM_PAINT被直接發送到目標視窗,從而導致視窗立即重繪。

2.Invalidate(false)和Invalidate(true)的區別

(1)Invalidate(false)正常   (2)Invalidate(true)出現刷屏      (3)如果不用,那麼每次開啟檔案將不能自動顯示,可以手動更改視窗大小,那麼就可以正常顯示了。

 

PostMessage和SendMessage以及PeekMessage和GetMessage區別:

 

PostMessage發送完訊息後立刻返回繼續執行程式.  將訊息放到訊息佇列
SendMessage發送完訊息後等待訊息處理完以後,才能返回繼續執行程式. 不將訊息放到隊列

 

更確切地說:PostMessage是給一個視窗發送了訊息.
SendMessage是直接去調用這個視窗的視窗處理函數來處理一個訊息並等其返回,

 

a。GetMessage類似於SendMessage. 有訊息才會傳回, 否則是阻塞的...,同時取出(刪除)原隊列的訊息.   
b。 PeekMessage 類似於PostMessage ,沒有訊息也立即返回, 同時可以選項選擇是否刪除原訊息...

 

1. GetMessage()只有在接收到訊息後才將控制權轉給你的程式,而PeekMessage()無論有沒有訊息都會將控制權轉給你的程式:如果有訊息,返回真,沒有訊息返回假。 
2。GetMessage()的主要功能是從訊息佇列中“取出”訊息,訊息被取出後,訊息佇列中就不再由該訊息了;而PeekMessage()的主要功能是“窺視(peek)”訊息,如果有訊息,返回真,沒有返回假。但PeekMessage()允許你從訊息佇列中“取出”訊息,這就是PeekMessage()第五個參數的用途:如果選用PM_REMOVE,則訊息從隊列中取出,如選用PM_NOREMOVE,則PeekMessage()則“文如其人”,只是“偷看”,而保留訊息。 
3。GetMessage()每次都“等待處理訊息”而PeekMessage()只是“察看有無訊息”。 
和PeekMessage()相關的代碼: 
while (TRUE) 

if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) 

if (msg.message == WM_QUIT) 
break ; 

TranslateMessage (&msg) ; 
DispatchMessage (&msg) ; 

else 

//other program lines to do some work 

}   
   

DEClARE_DYNCREATE 與DECLARE_DYNAMIC區別:

IMPLEMENT_DYNAMIC是實現“運行時類型識別”宏,與之相對應的是DECLARE_DYNAMIC(聲明“運行時類型識別”宏)。也就是說你在.CPP檔案中如果看見有IMPLEMENT_DYNAMIC,則在.H檔案中必定有DECLARE_DYNAMIC的聲明。
所以DECLARE_DYNAMIC/DEClARE_DYNAMIC是為了確定運行時對象屬於哪一個類而定義的宏。你可以在運行時利用RUNTIME_CLASS宏和CObject::IsKindOf函數來確定對象所屬的類。

 
DEClARE_DYNCREATE/IMPLEMENT_DYNCREATE是為了“動態建立"類的執行個體而定義的宏。new可以用來建立對象,但不是動態。比如說,你要在程式中實現根據擁護輸入的類名來建立類的執行個體,下面的做法是通不過的:
char szClassName[60];
cin >> szClassName;
CObject* pOb=new szClassName; //通不過
所以要實現動態建立類就要用到DEClARE_DYNCREATE/IMPLEMENT_DYNCREATE定義的功能了。

 

memmove和memcpy區別:

1. 當 src 和 dest 所指記憶體區有重疊時,memmove 相對 memcpy 能提供保證:保證能將 src 所指記憶體區的前 n 個位元組正確的拷貝到 dest 所指記憶體中;
2. 當 src 地址比 dest 地址低時,兩者結果一樣。換句話說,memmove 與 memcpy 的區別僅僅體現在 dest 的頭部和 src 的尾部有重疊的情況下;
3.memcpy用彙編實現的,效率高一些。

 

PreTranslateMessage 與WndProc區別:

在MFC中,PreTranslateMessage是虛函數,我們可以重載它來處理鍵盤和滑鼠訊息。

在sdk中,這又有所不同,我們必須在回呼函數中LRESULT   CALLBACK   WndProc(HWND   hWnd,   UINT   message,   WPARAM   wParam,   LPARAM   lParam)處理訊息:它和PreTranslateMessage起的作用是類似的。只是MFC封裝的更好而已。

重載該函數可以實現視窗訊息在派發給視窗函數TrnaslateMessage和DispatchMessae()之前的過濾.預設的實現是完成加速鍵的翻譯.因為您必須在你的重載版本中調用CWinApp:PreTranslateMessage()函數.很顯然,在SDK中在TranslateMassage()函數之前來實現該功能.

 

MFC中PreTranslateMessage是GetMessage(...)函數的下一級操作,即 GetMessage(...)從訊息佇列中擷取訊息後,交由PreTranslateMessage()處理,

若其返回FALSE則再交給 TranslateMessage和DispatchMessage處理(即進入WindowProc);  

 

PreTranslateMessage 僅僅是一個類似鉤子回呼函數 (hook callback function) 的東西,給你一個在  TranslateMessage 之前優先處理訊息的機會。虛擬碼:

 

MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
PreTranslateMessage(&msg);
TranslateMessage(&msg);
DispatchMessage(&msg);
}


如果用SendMessage,   則訊息直接交到WindowProc處理,所以GetMessage不會取得SendMessage的訊息,當然PreTranslateMessage也就不會被調用。 

如果用PostMessage,則訊息進入訊息佇列,由GetMessage取得,PreTranslateMessage就有機會進行處理。

 

Invalidate() -- RedrawWindow() -- UpdateWindow()三個函數有什麼異同:

     Invalidate()是強制系統進行重畫,但是不一定就馬上進行重畫。因為Invalidate()只是通知系統,此時的視窗已經變為無效。強制系統調用WM_PAINT,而這個訊息只是Post(寄送)就是將該訊息放入訊息佇列。當執行到WM_PAINT訊息時才會對敞口進行重繪。

    UpdateWindow只向表單發送WM_PAINT訊息,在發送之前判斷GetUpdateRect(hWnd,NULL,TRUE)看有無可繪製的用戶端區域,如果沒有,則不發送WM_PAINT。發送即不經過訊息佇列,直接發送到對應視窗,因此此函數可以立即更新視窗。

    RedrawWindow()則是具有Invalidate()和UpdateWindow()的雙特性。聲明視窗的狀態為無效,並立即更新視窗,立即調用WM_PAINT訊息處理。

  

附一段垃圾,只可看一點,別當真:

在view類中,create 是虛函數由架構調用,是用來“產生一個視窗的子視窗”。 
    oncreate 訊息響應函數,是用來“表示一個視窗正在產生”。

    某個CWnd的Create函數由當前CWnd的Owner調用, 而在CWnd::Create中,又會調用OnCreate函數,但是實際上這個時候Create函數還沒有退出,CWnd的某些部分還沒有建立好。所以,在ToolBar::OnCreate中,不能調用CommandToIndex,因為CommandToIndex需要等CToolBar全部建立好之後CToolBar::Create退出)才能被調用,否則傳回值一直是-1

    oncreate()不產生視窗,只是在視窗顯示前設定視窗的屬性如風格、位置等,
    create()負責註冊併產生視窗

    create()不是對應於訊息wm_create的,oncreate()才是。create()只用於產生視窗,像動態建立控制項中的create()一樣

 

SetActiveWindow、SetFocus、  SetForegroundWindow、 BringWindowToTop區別:

SetForegroundWindow()是把一個程式帶到前台,是不是啟用的不一定。 

SetActiveWindow()是啟用一個程式。 
SetFocus()是如輸入框等可以輸入的地方得到游標。

BringWindowToTop

 

轉自:http://blog.csdn.net/weiwangchao_/article/details/6923976

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.