<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    MFC常見問題解惑

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    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.

     

    OnDrawItemDrawItem的區別:

    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位的變量就被命名為wParam32位的變量就被命名為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/6923976RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全