windows消息處理機制_第1頁
windows消息處理機制_第2頁
windows消息處理機制_第3頁
windows消息處理機制_第4頁
windows消息處理機制_第5頁
已閱讀5頁,還剩26頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

windows消息處理機制消息,就是指Windows發(fā)出的一個通知,告訴應(yīng)用程序某個事情發(fā)生了。例如,單擊鼠標(biāo)、改變窗口尺寸、按下鍵盤上的一個鍵都會使Windows發(fā)送一個消息給應(yīng)用程序。消息本身是作為一個記錄傳遞給應(yīng)用程序的,這個記錄中包含了消息的類型以及其他信息。例如,對于單擊鼠標(biāo)所產(chǎn)生的消息來說,這個記錄中包含了單擊鼠標(biāo)時的坐標(biāo)。這個記錄類型叫做TMsg,它在Windows單元中是這樣聲明的:typeTMsg=packedrecordhwnd:HWND;//窗口句柄message:UINT;//消息常量標(biāo)識符wParam:WPARAM;//32位消息的特定附加信息lParam:LPARAM;//32位消息的特定附加信息time:DWORD;//消息創(chuàng)建時的時間pt:TPoint;//消息創(chuàng)建時的鼠標(biāo)位置end;消息中有什么?是否覺得一個消息記錄中的信息像希臘語一樣?如果是這樣,那么看一看下面的解釋hwnd32位的窗口句柄。窗口可以是任何類型的屏幕對象,因為Win32能夠維護大多數(shù)可視對象的句柄(窗口、對話框、按鈕、編輯框等)。message用于區(qū)別其他消息的常量值,這些常量可以是Windows單元中預(yù)定義的常量,也可以是自定義的常量。wParam通常是一個與消息有關(guān)的常量值,也可能是窗口或控件的句柄。lParam通常是一個指向內(nèi)存中數(shù)據(jù)的指針。由于WParam、lParam和Pointer都是32位的,因此,它們之間可以相互轉(zhuǎn)換。Windows的消息系統(tǒng)是由3個部分組成的:?消息隊列。Windows能夠為所有的應(yīng)用程序維護一個消息隊列。應(yīng)用程序必須從消息隊列中獲取消息,然后分派給某個窗口。?消息循環(huán)。通過這個循環(huán)機制應(yīng)用程序從消息隊列中檢索消息,再把它分派給適當(dāng)?shù)拇翱?,然后繼續(xù)從消息隊列中檢索下一條消息,再分派給適當(dāng)?shù)拇翱?,依次進行。?窗口過程。每個窗口都有一個窗口過程來接收傳遞給窗口的消息,它的任務(wù)就是獲取消息然后響應(yīng)它。窗口過程是一個回調(diào)函數(shù);處理了一個消息后,它通常要返回一個值給Windows。注意回調(diào)函數(shù)是程序中的一種函數(shù),它是由Windows或外部模塊調(diào)用的。一個消息從產(chǎn)生到被一個窗口響應(yīng),其中有5個步驟:1) 系統(tǒng)中發(fā)生了某個事件。2) Windows把這個事件翻譯為消息,然后把它放到消息隊列中。3) 應(yīng)用程序從消息隊列中接收到這個消息,把它存放在TMsg記錄中。應(yīng)用程序把消息傳遞給一個適當(dāng)?shù)拇翱诘拇翱谶^程。窗口過程響應(yīng)這個消息并進行處理。步驟3和4構(gòu)成了應(yīng)用程序的消息循環(huán)。消息循環(huán)往往是Windows應(yīng)用程序的核心,因為消息循環(huán)使一個應(yīng)用程序能夠響應(yīng)外部的事件。消息循環(huán)的任務(wù)就是從消息隊列中檢索消息,然后把消息傳遞給適當(dāng)?shù)拇翱?。如果消息隊列中沒有消息,Windows就允許其他應(yīng)用程序處理它們的消息。Windows操作系統(tǒng)最大的特點就是其圖形化的操作界面,其圖形化界面是建立在其消息處理機制這個基礎(chǔ)之上的。如果不理解Windows消息處理機制,肯定無法深入的理解Windows編程。可惜很多程序員對Windows消息只是略有所聞,對其使用知之甚少,更不了解其內(nèi)部實現(xiàn)原理,本文試著一步一步向大家披露我理解的Windows消息機制。可以說,掌握了這一部分知識,就是掌握了Windows編程中的神兵利器,靈活運用它,將會極大的提高我們的編程能力。[編輯本段]Windows窗體是怎樣展現(xiàn)在屏幕上的呢?眾所周知,是通過API繪制實現(xiàn)的。Windows操作系統(tǒng)提供了一系列的API函數(shù)來實現(xiàn)界面的繪制功能,例如:2DrawText繪制文字2DrawEdge繪制邊框2DrawIcon繪制圖標(biāo)2BitBlt繪制位圖2Rectangle繪制矩形2…再復(fù)雜的程序界面都是通過這個函數(shù)來實現(xiàn)的。那什么時候調(diào)用這些函數(shù)呢?顯然我們需要一個控制中心,用來進行“發(fā)號施令”,我們還需要一個命令傳達機制,將命令即時的傳達到目的地。這個控制中心,就是一個動力源就像一顆心臟,源源不斷地將血液送往各處。這個命令傳達機制就是Windows消息機制,Windows消息就好比是身體中的血液,它是命令傳達的使者。Windows消息控制中心一般是三層結(jié)構(gòu),其頂端就是Windows內(nèi)核。Windows內(nèi)核維護著一個消息隊列,第二級控制中心從這個消息隊列中獲取屬于自己管轄的消息,后做出處理,有些消息直接處理掉,有些還要發(fā)送給下一級窗體(Window)或控件(Control)o第二級控制中心一般是各Windows應(yīng)用程序的Application對象。第三級控制中心就是Windows窗體對象,每一個窗體都有一個默認的窗體過程,這個過程負責(zé)處理各種接收到的消息。如下圖所示:<!--[if!vml]--><!--[endif]-->說明圖(注:windows指windows操作系統(tǒng);窗口:即windows窗口;窗體:包括窗口,以及有句柄的控件;control指控件,控件本身也可能是一個window,也可能不是;Application即應(yīng)用程序,應(yīng)用程序也可能不會用到Windows消息機制,這里我們專門討論有消息循環(huán)的應(yīng)用程序)消息是以固定的結(jié)構(gòu)傳送給應(yīng)用程序的,結(jié)構(gòu)如下:PublicTypeMSGhwndAsLongmessageAsLongwParamAsLonglParamAsLongtimeAsLongptAsPOINTAPIEndType其中hwnd是窗體的句柄,message是一個消息常量,用來表示消息的類型,wParam和IParam都是32位的附加信息,具體表示什么內(nèi)容,要視消息的類型而定,time是消息發(fā)送的時間,pt是消息發(fā)送時鼠標(biāo)所在的位置。Windows操作系統(tǒng)中包括以下幾種消息:1、 標(biāo)準Windows消息:這種消息以WM_打頭。2、 通知消息通知消息是針對標(biāo)準Windows控件的消息。這些控個包括:按鈕(Button)、組合框(ComboBox)、編輯框(TextBox)、列表框(ListBox)、ListView控件、Treeview控件、工具條(Toolbar)、菜單(Menu)等。每種消息以不同的字符串打頭。3、 自定義消息編程人員還可以自定義消息。二、 關(guān)于Windows句柄不是每個控件都能接收消息,轉(zhuǎn)發(fā)消息和繪制自身,只有具有句柄(handle)的控件才能做到。有句柄的控件本質(zhì)上都是一個窗體(window),它們可以獨立存在,可以作為其它控件的容器,而沒有句柄的控件,如Label,是不能獨立存在的,只能作為窗口控件的子控件,它不能繪制自身,只能依靠父窗體將它繪制來。句柄的本質(zhì)是一個系統(tǒng)自動維護的32位的數(shù)值,在整個操作系統(tǒng)的任一時刻,這個數(shù)值是唯一的。但該句柄代表的窗體釋放后,句柄也會被釋放,這個數(shù)值又可能被其它窗體使用。也就是說,句柄的數(shù)值是動態(tài)的,它本身只是一個唯一性標(biāo)識,操作系統(tǒng)通過句柄來識別和查找它所代表的對象。然而,并非所有的句柄都是窗體的句柄,Windows系統(tǒng)中還中很多其它類型的句柄,如畫布(hdc)句柄,畫筆句柄,畫刷句柄,應(yīng)用程序句柄hlnstance)等。這種句柄是不能接收消息的。但不管是哪種句柄,都是系統(tǒng)中對象的唯一標(biāo)識。本文只討論窗體句柄。那為什么句柄使窗口具有了如此獨特的特性呢?實際是都是由于消息的原因。由于有了句柄,窗體能夠接收消息,也就知道了該什么時候繪制自己,繪制子控件,知道了鼠標(biāo)在什么時候點擊了窗口的哪個部分,從而作出相應(yīng)的處理。句柄就好像是一個人的身份證,有了它,你就可以從事各種社會活動;否則的話,你要么是一個社會看不到的黑戶,要么跟在別人后面,通過別人來證明你的存在。三、 消息的傳送1、 從消息隊列獲取消息:可以通過PeekMessage或GetMessage函數(shù)從Windows消息隊列中獲取消息。Windows保存的消息隊列是以線程(Thread)來分組的,也就是說每個線程都有自己的消息隊列。2、 發(fā)送消息發(fā)送消息到指定窗體一般通過以下兩個函數(shù)完成:SendMessage和PostMessage。兩個函數(shù)的區(qū)別在于:PostMessage函數(shù)只是向線程消息隊列中添加消息,如果添加成功,則返回True,否則返回False,消息是否被處理,或處理的結(jié)果,就不知道了。而SendMessage則有些不同,它并不是把消息加入到隊列里,而是直接翻譯消息和調(diào)用消息處理(線程向自己發(fā)送消息才是這樣),直到消息處理完成后才返回。所以,如果我們希望發(fā)送的消息立即被執(zhí)行,就應(yīng)該調(diào)用SendMessage。還有一點,就是SendMessage發(fā)送的消息由于不會被加入到消息隊列中(錯:線程向其他線程發(fā)送消息也是追加到其他線程的發(fā)送消息隊列的,即使這兩個線程在同一個進程也是如此),所以通過PeekMessage或GetMessage是不能獲取到由SendMessage發(fā)送的消息。另外,有些消息用PostMessage不會成功,比如wm_settext。所以不是所有的消息都能夠用PostMessage的。還有一些其它的發(fā)送消息API函數(shù),如PostThreadMessage,SendMessageCallback,SendMessageTimeout,SendNotifyMessage等。四、 消息循環(huán)與窗體過程消息循環(huán)是應(yīng)用程序能夠持續(xù)存在的根本原因。如果循環(huán)退出,則應(yīng)用程序就結(jié)束了。我們來看一看Delphi中封裝的消息循環(huán)是怎樣的:第一步:程序開始運行(Run)Application.Initialize;//初始化Application.CreateForm(TForm1,Form1);//創(chuàng)建主窗體Application.Run;//開始運行,準備進行消息循環(huán)如果不創(chuàng)建主窗體,應(yīng)用程序同樣可以存在和運行。第二步:開始調(diào)用消息循環(huán)(HandleMessage)procedureTApplication.Run;beginFRunning:=True;tryAddExitProc(DoneApplication);ifFMainForm<>nilthenbegincaseCmdShowofSW_SHOWMINNOACTIVE:FMainForm.FWindowState:=wsMinimized;SW_SHOWMAXIMIZED:MainForm.WindowState:=wsMaximized;end;ifFShowMainFormthenifFMainForm.FWindowState=wsMinimizedthenMinimizeelseFMainForm.Visible:=True;Repeat//注:循環(huán)開始tryHandleMessage;exceptHandleException(Self);end;untilTerminated;//循環(huán)結(jié)束條件end;finallyFRunning:=False;end;end;第三步:消息循環(huán)中對消息的處理。procedureTApplication.HandleMessage;varMsg:TMsg;beginifnotProcessMessage(Msg)thenIdle(Msg);end;functionTApplication.ProcessMessage(varMsg:TMsg):Boolean;varHandled:Boolean;beginResult:=False;ifPeekMessage(Msg,0,0,0,PM_REMOVE)thenbeginResult:=True;ifMsg.Message<>WM_QUITthenbeginHandled:=False;ifAssigned(FOnMessage)thenFOnMessage(Msg,Handled);ifnotIsHintMsg(Msg)andnotHandledandnotIsMDIMsg(Msg)andnotIsKeyMsg(Msg)andnotIsDlgMsg(Msg)thenbeginTranslateMessage(Msg);DispatchMessage(Msg);end;endelseFTerminate:=True;end;end;窗體過程實際上是一個回調(diào)函數(shù)。所謂的回調(diào)函數(shù),實際上就是由Windows操作系統(tǒng)或外部程序調(diào)用的函數(shù)?;卣{(diào)函數(shù)一般都有規(guī)定的參數(shù)格式,以地址方式傳遞給調(diào)用者。窗口過程中是Windows操作系統(tǒng)調(diào)用了,在一個窗口創(chuàng)建的時候,在分配窗體句柄的時候就需要傳入回調(diào)函數(shù)地址。那為什么我們平時編程看不到這個回調(diào)函數(shù)呢?這是由于我們的編程工具已經(jīng)為我們生成了默認的窗體過程,這個過程的要做的事情就是判斷不同的消息類型然后做出不同的處理。例如可以為鍵盤或鼠標(biāo)輸入生成事件等。五、 消息與事件事件本質(zhì)上是對消息的封裝,是IDE編程環(huán)境為了簡化編程而提供的有用的工具。這個封裝是在窗體過程中實現(xiàn)的。每種IDE封裝了許多Windows的消息,例如:事件消息OnActivateWM_ACTIVATEOnClickWM_XBUTTONDOWNOnCreateWM_CREATEOnDblClickWM_XBUTTONDBLCLICKOnKeyDownWM_KEYDOWNOnKeyPressWM_CHAROnKeyUpWIN_KEYUPOnPaintWM_PAINTOnResizeWM_SIZEOnTimerWM_TIMERMFC框架原理以及消息運行機制收藏(1)Windows程序內(nèi)部運行機制1,windows程序設(shè)計是種事件驅(qū)動方式的程序設(shè)計,主要基于消息的。當(dāng)用戶需要完成某種功能時,需要調(diào)用OS某種支持,然后OS將用戶的需要包裝成消息,并投入到消息隊列中,最后應(yīng)用程序從消息隊列中取走消息并進行響應(yīng)。2,消息結(jié)構(gòu):typedefstructtagMSG{ //msgHWNDhwnd;//接收消息的窗口句柄。和哪個窗口相關(guān)聯(lián)。UINTmessage;//消息標(biāo)識。消息本身是什么。WPARAMwParam;//消息的附加信息。具體取決于消息本身。LPARAMlParam;DWORDtime;//消息投遞時間。POINTpt;//消息投遞時,光標(biāo)在屏幕上的位置。}MSG;3,消息隊列:每個應(yīng)用程序OS都為它建立一個消息隊列,消息隊列是個先進先出的緩沖區(qū),其中每個元素都是一個消息,OS將生成的每個消息按先后順序放進消息隊列中,應(yīng)用程序總是取走當(dāng)前消息隊列中的第一條消息,應(yīng)用程序取走消息后便知道用戶的操作和程序的狀態(tài),然后對其處理即消息響應(yīng),消息響應(yīng)通過編碼實現(xiàn)。使用VC編程除了良好的C基礎(chǔ)外還需要掌握兩方面:一,消息本身。不同消息所代表的用戶操作和應(yīng)用程序的狀態(tài)。二,對于某個特定的消息來說,要讓OS執(zhí)行某個特定的功能去響應(yīng)消息。5,Window程序入口:intWINAPIWinMain(HINSTANCEhInstance,//當(dāng)前事例句柄。HINSTANCEhPrevInstance,//先前事例句柄。LPSTRlpCmdLine,//命令行指針intnCmdShow//(窗口)顯示的狀態(tài));說明:WinMain函數(shù)是Windows程序入口點函數(shù),由OS調(diào)用,當(dāng)OS啟動應(yīng)用程序的時候,winmain函數(shù)的參數(shù)由OS傳遞的。6,創(chuàng)建一個完整的窗口需要經(jīng)過下面四個操作步驟:一,設(shè)計一個窗口類;如:WNDCLASSwndcls;二,注冊窗口類;如:RegisterClass(&wndcls);三,創(chuàng)建窗口;如:CreateWindow(),CreateWindowEX();四,顯示及更新窗口。如:ShowWindow(),UpdateWindow();說明:創(chuàng)建窗口的時候一定要基于已經(jīng)注冊的窗口類.7,Windows提供的窗口類:typedefstruct_WNDCLASS{UINTstyle; //窗口的類型WNDPROClpfnWndProc;//窗口過程函數(shù)指針(回調(diào)函數(shù))int cbClsExtra;//窗口類附加字節(jié),為該類窗口所共享。通常0。int cbWndExtra;//窗口附加字節(jié)。通常設(shè)為0。HANDLEhInstance;//當(dāng)前應(yīng)用程序事例句柄。HICONhIcon; //圖標(biāo)句柄LoadIcon();HCURSORhCursor;//光標(biāo)句柄LoadCursor();HBRUSHhbrBackground;//畫刷句柄(HBRUSH)GetStockObject();LPCTSTRlpszMenuName;//菜單名字LPCTSTRlpszClassName;//類的名字}WNDCLASS;窗口類注冊:ATOMRegisterClass(CONSTWNDCLASS*lpWndClass//addressofstructurewithclass//data);9,創(chuàng)建窗口:HWNDCreateWindow(LPCTSTRlpClassName,//pointertoregisteredclassnameLPCTSTRlpWindowName,//pointertowindownameDWORDdwStyle,//windowstyleintx, //horizontalpositionofwindowinty, //verticalpositionofwindowintnWidth, //windowwidthintnHeight, //windowheightHWNDhWndParent,//handletoparentorownerwindowHMENUhMenu, //handletomenuorchild-windowidentifierHANDLEhInstance,//handletoapplicationinstanceLPVOIDlpParam//pointertowindow-creationdata);10,顯示和更新窗口窗口:BOOLShowWindow(HWNDhWnd,//handletowindowintnCmdShow//showstateofwindow);BOOLUpdateWindow(HWNDhWnd//handleofwindow);11,消息循環(huán):MSGmsg;while(GetMessage(&msg,...))//從消息隊列中取出一條消息{TranslateMessage(&msg);//進行消息(如鍵盤消息)轉(zhuǎn)換DispatchMessage(&msg);〃分派消息到窗口的回調(diào)函數(shù)處理,(OS調(diào)用窗口回調(diào)函數(shù)進行處理)。}其中://**TheGetMessagefunctionretrievesamessagefromthecallingthread'smessagequeueandplacesitinthespecifiedstructure.//**IfthefunctionretrievesamessageotherthanWM_QUIT,thereturnvalueisnonzero.IfthefunctionretrievestheWM_QUITmessage,thereturnvalueiszero.Ifthereisanerror,thereturnvalueis-1.BOOLGetMessage(LPMSGlpMsg,//addressofstructurewithmessageHWNDhWnd,//handleofwindowUINTwMsgFilterMin,//firstmessageUINTwMsgFilterMax//lastmessage);//TheTranslateMessagefunctiontranslatesvirtual-keymessagesintocharactermessages.Thecharactermessagesarepostedtothecallingthread'smessagequeue,tobereadthenexttimethethreadcallstheGetMessageorPeekMessagefunction.BOOLTranslateMessage(CONSTMSG*lpMsg//addressofstructurewithmessage//TheDispatchMessagefunctiondispatchesamessagetoawindowprocedure.LONGDispatchMessage(CONSTMSG*lpmsg//pointertostructurewithmessage);12,窗口過程函數(shù)(回調(diào)函數(shù))原型:TheWindowProcfunctionisanapplication-definedfunctionthatprocessesmessagessenttoawindow.TheWNDPROCtypedefinesapointertothiscallbackfunction.WindowProcisaplaceholder(占位符)fortheapplication-definedfunctionname.LRESULTCALLBACKWindowProc(〃這里WindowProc是個代號名字。HWNDhwnd,//handletowindowUINTuMsg,//messageidentifierWPARAMwParam,//firstmessageparameterLPARAMlParam//secondmessageparameter);說明:兩種函數(shù)調(diào)用約定(__stdcall和__cdecl):#defineCALLBACK__stdcall〃_stdcall標(biāo)準調(diào)用預(yù)定,是PASCAL調(diào)用約定,象DELPHI使用的就是標(biāo)準調(diào)用約定#defineWINAPIV__cdecl//__cdecl是C語言形式的調(diào)用約定。主要區(qū)別:函數(shù)參數(shù)傳遞順序和對堆棧的清除上。問題:除了那些可變參數(shù)的函數(shù)調(diào)用外,其余的一般都是_stdcall約定。但C/C++編譯默然的是—cdecl約定。所以如果在VC等環(huán)境中調(diào)用—stdcall約定的函數(shù),必須要在函數(shù)聲明的時加上—stdcall修飾符,以便對這個函數(shù)的調(diào)用是使用—stdcall約定(如使用DELPHI編寫的DLL時候)。(VC中可通過這途徑修改:project|settings..|c/c++|...)在窗口過程函數(shù)中通過一組switch語句來對消息進行處理如:LRESULTCALLBACKWindowProc(HWNDhwnd,UINTuMsg,WPARAMwParam,LPARAMlParam){switch(uMsg){caseWM_PAINT:break;case...break;caseWM_CLOSE://DestroyWindow(hwnd);〃銷毀窗口,并發(fā)送WM_DESTROY消息。break;caseWM_DESTROY://PostQuitMessage(0);〃發(fā)送WM_QUIT消息到消息隊列中,請求終止。〃GetMessage()取到WM_QUIT消息后,返回0退出消息循 //環(huán),從而終止應(yīng)用程序。break;default:returnDefWindowProc(hwnd,uMsg,wParam,lParam);//用缺省的窗口過程處理我們不感興趣的消息(其它消息)。//這是必須的。}//switchreturn0;}//WindowProc13,DestroyWindow()函數(shù)和PostQuitMessage()函數(shù)原型://**TheDestroyWindowfunctiondestroysthespecifiedwindow.ThefunctionsendsWM_DESTROYandWM_NCDESTROYmessages。BOOLDestroyWindow(HWNDhWnd//handletowindowtodestroy);//**ThePostQuitMessagefunctionindicatestothesystemthatathreadhasmadearequesttoterminate(quit).ItistypicallyusedinresponsetoaWM_DESTROYmessage.//**ThePostQuitMessagefunctionpostsaWM_QUITmessagetothethread'smessagequeueandreturnsimmediately;thefunctionsimplyindicates(預(yù)示,通知)tothesystemthatthethreadisrequestingtoquitatsometimeinthefuture.WhenthethreadretrievestheWM_QUITmessagefromitsmessagequeue,itshouldexititsmessageloopandreturncontroltothesystem.VOIDPostQuitMessage(intnExitCode//exitcode14,關(guān)于DC句柄獲取:a) 使用BeginPaint(),EndPaint()對。注意只能在響應(yīng)WM_PAINT消息時使用。b) 使用GetDc(),ReleaseDC()對。注意他們不能在響應(yīng)WM_PAINT中使用。(2)C++c語言中,結(jié)構(gòu)體struct中不能包括函數(shù)的,而在C++中struct中可以包括函數(shù)。C++中結(jié)構(gòu)體和類可以通用,區(qū)別主要表現(xiàn)在訪問控制方面:struct中默認是public,而class中默認的是private。構(gòu)造函數(shù)最重要的作用是創(chuàng)建對象的本身,C++中每個類可以擁有多個構(gòu)造函數(shù),但必須至少有一個構(gòu)造函數(shù),當(dāng)一個類中沒有顯式提供任何構(gòu)造函數(shù),C++編輯器自動提供一個默認的不帶參數(shù)的構(gòu)造函數(shù),這個默認的構(gòu)造函數(shù)只負責(zé)構(gòu)造對象,不做任何初始化工作。但在一個類中只要自己定義一個構(gòu)造函數(shù),不管帶參不帶參,編輯器不再提供默認的不帶參的構(gòu)造函數(shù)了。構(gòu)造函數(shù)沒有返回值。析構(gòu)函數(shù)當(dāng)一個對象生命周期結(jié)束時候被調(diào)用來回收對象占用的內(nèi)存空間。一個類只需有一個析構(gòu)函數(shù)。析構(gòu)函數(shù)沒有返回值也不的帶參數(shù)。5,析構(gòu)函數(shù)的作用與構(gòu)造函數(shù)相反,對象超出起作用范圍對應(yīng)的內(nèi)存空間被系統(tǒng)收回,或被程序用delete刪除的時候,對象的析構(gòu)函數(shù)被調(diào)用。6,函數(shù)的重載條件:函數(shù)的參數(shù)類型、個數(shù)不同,才能構(gòu)成函數(shù)的重載。重載是發(fā)生在同一個類中。7,類是抽象的,不占用具體物理內(nèi)存,只有對象是實例化的,是占用具體物理內(nèi)存的。8,this指針是隱含指針,指向?qū)ο蟊旧恚╰his指針不是指向類的),代表了對象的地址。所有的對象調(diào)用的成員函數(shù)都是同一代碼段,但每個對象都有自己的數(shù)據(jù)成員。當(dāng)對象通過調(diào)用它的成員函數(shù)來訪問它的數(shù)據(jù)成員的時候,成員函數(shù)除了接收實參外,還接收了對象的地址,這個地址被一個隱藏的形參this所獲取,通過這個this指針可以訪問對象的數(shù)據(jù)成員和成員函數(shù)。對象中public屬性的成員在外部和子類中都可以被訪問;protected屬性的成員在外部不能被訪問,在子類中是可以訪問的;private屬性在子類中和外部都不能被訪問。類的繼承訪問特性:(public,protected,private)a) 基類中private屬性成員,子類無論采用那種繼承方式都不能訪問。b) 采用public繼承,基類中的public,protected屬性的成員訪問特性在子類中仍然保持一致。c) 采用protected繼承,基類中的public,protected屬性成員訪問特性在子類中變?yōu)閜rotected.d) 采用private繼承,基類中的public,protected屬性成員訪問特性在子類中變?yōu)閜rivate.11,子類和基類的構(gòu)造函數(shù)或析構(gòu)函數(shù)調(diào)用順序:當(dāng)調(diào)用子類的構(gòu)造函數(shù)時候先調(diào)用基類的構(gòu)造函數(shù)(如果沒有指明,則調(diào)用基類卻省那個不帶參數(shù)的構(gòu)造函數(shù);如果要指明則在子類構(gòu)造函數(shù)名后加":基類名(參數(shù))")。析構(gòu)函數(shù)則相反,先調(diào)用子類析構(gòu)函數(shù),后調(diào)用基類的析構(gòu)函數(shù)。12,函數(shù)的覆蓋:函數(shù)的覆蓋是發(fā)生在發(fā)生父類和子類之間的。(函數(shù)的重載是發(fā)生在同一個類中)當(dāng)子類中重寫了父類的某些成員函數(shù)后,子類中的成員函數(shù)覆蓋了父類的對應(yīng)同名成員函數(shù)13,用父類指針訪問子類對象成員時候,只能訪問子類從父類繼承來的那部分。(這時候外部不可以訪問父類中保護和私有的部分,子類中不可訪問父類私有部分。)14,多態(tài)性:在基類的的成員函數(shù)前加virturl變成虛函數(shù),當(dāng)用子類對象調(diào)用該功能的成員函數(shù)時候,子類有的就調(diào)用子類的,子類沒有的就調(diào)用基類的。當(dāng)C++編譯器在編譯的時候,發(fā)現(xiàn)被調(diào)用的成員函數(shù)在基類中定義的是虛函數(shù),這個時候C++就會采用遲綁定技術(shù)(latebinding),在運行的時候,依據(jù)對象的類型來確定調(diào)用的哪個函數(shù),子類有調(diào)用子類的,子類沒有的就調(diào)用基類的。如果基類中的成員函數(shù)不是虛函數(shù),則這時候的綁定是早期綁定,在編譯的時候就已經(jīng)確定該調(diào)用哪個函數(shù)。15,純虛函數(shù):在類中定義時eg:virtualvoidfunc1()=0;純虛函數(shù)沒有函數(shù)體,含有純虛函數(shù)的類叫做抽象類,抽象類不能實例化對象。當(dāng)子類從抽象類的基類中派生出來時候,如果沒有實現(xiàn)基類中的純虛函數(shù),則子類也是個抽象類,也不能實例化對象。純虛函數(shù)被標(biāo)名為不具體實現(xiàn)的虛成員函數(shù),純虛函數(shù)可以讓類只具有操作的名稱而不具有具體的操作的內(nèi)容,讓派生類在繼承的時候再給出具體的定義。如果派生類沒有給出基類的純虛函數(shù)的具體定義的時候,派生類也為一個抽象類,也不能實例化對象。16,引用:變量的別名。引用需要在定義的時候用一變量或?qū)ο蟪跏蓟约?。引用一旦在定義的時候初始化,就維系在一個特定的變量或?qū)ο笊?。引用不占用物理?nèi)存(與定義引用的目標(biāo)共用同一內(nèi)存)。指針變量需要占用物理內(nèi)存,用來存儲地址。(3)MFC程序框架的剖析1,尋找WinMain人口:在安裝目錄下找到MFC文件夾下的SRC文件夾,SRC下是MFC源代碼。路徑:MFC|SRC|APPMODUL.CPP:_tWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPTSTRlpCmdLine,intnCmdShow){//callshared/exportedWinMainreturnAfxWinMain(hInstance,hPrevInstance,lpCmdLine,nCmdShow);}注意:(#define_tWinMainWinMain)2,對于全局對象或全局變量來說,在程序運行即WINMAIN函數(shù)加載的時候,已經(jīng)為全局對象或全局變量分配了內(nèi)存和賦初值。所以:CTEApptheApp;->CTEApp::CTEApp(){}->_tWinMain(){}說明:每一個MFC程序,有且只有一個從WinApp類派生的類(應(yīng)用程序類),也只有一個從應(yīng)用程序類所事例化的對象,表示應(yīng)用程序本身。在WIN32程序當(dāng)中,表示應(yīng)用程序是通過WINMAIN入口函數(shù)來表示的(通過一個應(yīng)用程序的一個事例號這一個標(biāo)識來表示的)。在基于MFC應(yīng)用程序中,是通過產(chǎn)生一個應(yīng)用程序?qū)ο?,用它來唯一的表示了?yīng)用程序。3,通過構(gòu)造應(yīng)用程序?qū)ο筮^程中調(diào)用基類CWinApp的構(gòu)造函數(shù),在CWinApp的構(gòu)造函數(shù)中對程序包括運行時一些初始化工作完成了。CWinApp構(gòu)造函數(shù):MFC|SRC|APPCORE.CPPCWinApp::CWinApp(LPCTSTRlpszAppName){...}〃帶參數(shù),而CTEApp構(gòu)造函數(shù)沒有顯式向父類傳參,難道CWinApp()有默認參數(shù)?見下:(在CWinApp類定義中,CWinApp(LPCTSTRlpszAppName=NULL);)注意:CWinApp()函數(shù)中:pThreadState->m_pCurrentWinThread=this;pModuleState->m_pCurrentWinApp=this(this指向的是派生類CTEApp對象,即theApp)調(diào)試:CWinApp::CWinApp();->CTEApptheApp;(->CTEApp::CTEApp())->CWinApp::CWinApp()->CTEApp::CTEApp()->_tWinMain(){}_tWinMain函數(shù)中通過調(diào)用AfxWinMain()函數(shù)來完成它要完成的功能。(Afx*前綴代表這是應(yīng)用程序框架函數(shù),是一些全局函數(shù),應(yīng)用程序框架是一套輔助生成應(yīng)用程序的框架模型,把一些類做一些有機的集成,我們可根據(jù)這些類函數(shù)來設(shè)計自己的應(yīng)用程序)。AfxWinMain()函數(shù)路徑:MFC|SRC|WINMAIN.CPP:在AfxWinMain()函數(shù)中:CWinApp*pApp=AfxGetApp();說明:pApp存儲的是指向WinApp派生類對象(theApp)的指針。//_AFXWIN_INLINECWinApp*AFXAPIAfxGetApp()//{returnafxCurrentWinApp;}調(diào)用pThread->InitInstance()說明:pThread也指向theApp,由于基類中virtualBOOLInitApplication()定義為虛函數(shù),所以調(diào)用pThread->InitInstance()時候,調(diào)用的是派生類CTEApp的InitInstance()函數(shù)。nReturnCode=pThread->Run();說明:pThread->Run()完成了消息循環(huán)。注冊窗口類:AfxEndDeferRegisterClass();AfxEndDeferRegisterClass()函數(shù)所在文件:MFC|SRC|APPCORE.CPPBOOLAFXAPIAfxEndDeferRegisterClass(LONGfToRegister){...}說明:設(shè)計窗口類:在MFC中事先設(shè)計好了幾種缺省的窗口類,根據(jù)不同的應(yīng)用程序的選擇,調(diào)用AfxEndDeferRegisterClass()函數(shù)注冊所選擇的窗口類。調(diào)試:CWinApp::CWinApp();->CTEApptheApp;(->CTEApp::CTEApp())->CWinApp::CWinApp()->CTEApp::CTEApp()->_tWinMain(){}〃進入程序->AfxWinMain();->pApp->InitApplication();->pThread->InitInstance()〃父類InitInstance虛函數(shù);->CTEApp::InitInstance()〃子類實現(xiàn)函數(shù);->AfxEndDeferRegisterClass(LONGfToRegister)//注冊所選擇的窗口類(出于文檔管理,注冊提前,正常的應(yīng)在PreCreateWindow中進行注冊)//之后進入創(chuàng)建窗口階段(以下再不做調(diào)試)6,PreCreateWindow()://主要是注冊窗口類BOOLCMainFrame::PreCreateWindow(CREATESTRUCT&cs){if(!CFrameWnd::PreCreateWindow(cs))returnFALSE;returnTRUE;}說明:CFrameWnd::PreCreateWindow()函數(shù)所在文件:MFC|SRC|WINFRM.CPPBOOLCFrameWnd::PreCreateWindow(CREATESTRUCT&cs){if(cs.lpszClass==NULL){VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));//判斷AFX_WNDFRAMEORVIEW_REG型號窗口類是否注冊,如果沒有注冊則注冊cs.lpszClass=_afxWndFrameOrView;//COLOR_WINDOWbackground//把注冊后的窗口類名賦給cs.lpszClass}if((cs.style&FWS_ADDTOTITLE)&&afxData.bWin4)cs.style|=FWS_PREFIXTITLE;if(afxData.bWin4)cs.dwExStyle|=WS_EX_CLIENTEDGE;returnTRUE;}其中:virtualBOOLPreCreateWindow(CREATESTRUCT&cs);//PreCreateWindow()是個虛函數(shù),如果子類有則調(diào)用子類的。#defineVERIFY(f)ASSERT(f)#defineAfxDeferRegisterClass(fClass)AfxEndDeferRegisterClass(fClass)defineAFX_WNDFRAMEORVIEW_REG0x00008constTCHAR_afxWndFrameOrView[]=AFX_WNDFRAMEORVIEW;//WINCORE.CPP文件中,定義為全局數(shù)組。//#defineAFX_WNDFRAMEORVIEWAFX_WNDCLASS("FrameOrView")7,創(chuàng)建窗口:Create()函數(shù)路徑:MFC|SRC|WINFRM.CPP:CFrameWnd::Create(...){CreateEx(...);//從父類繼承來的,調(diào)用CWnd::CreateEx().}CWnd::CreateEx()函數(shù)路徑:MFC|SRC|WINCORE.CPPBOOLCWnd::CreateEx(...){if(!PreCreateWindow(cs))〃虛函數(shù),如果子類有調(diào)用子類的。{PostNcDestroy();returnFALSE;}HWNDhWnd=::CreateWindowEx(cs.dwExStyle,cs.lpszClass,cs.lpszName,cs.style,cs.x,cs.y,cs.cx,cs.cy,cs.hwndParent,cs.hMenu,cs.hInstance,cs.lpCreateParams);}說明:CreateWindowEx()函數(shù)與CREATESTRUCT結(jié)構(gòu)體參數(shù)的對應(yīng)關(guān)系,使我們在創(chuàng)建窗口之前通過可PreCreateWindow(cs)修改cs結(jié)構(gòu)體成員來修改所要的窗口外觀。PreCreateWindow(cs))//是虛函數(shù),如果子類有調(diào)用子類的。HWNDCreateWindowEx(DWORDdwExStyle,LPCTSTRlpClassName,LPCTSTRlpWindowName,DWORDdwStyle,intx,inty,intnWidth,intnHeight,HWNDhWndParent,HMENUhMenu,HINSTANCEhInstance,LPVOIDlpParam);typedefstructtagCREATESTRUCT{//csLPVOIDlpCreateParams;HINSTANCEhInstance;HMENUhMenu;HWNDhwndParent;intcy;intcx;inty;intx;LONGstyle;LPCTSTRlpszName;LPCTSTRlpszClass;DWORDdwExStyle;}CREATESTRUCT;8,顯示和更新窗口:CTEApp類,TEApp.cpp中m_pMainWnd->ShowWindow(SW_SHOW);〃顯示窗口,m_pMainWnd指向框架窗口m_pMainWnd->UpdateWindow();//更新窗口說明:classCTEApp:publicCWinApp{...}classCWinApp:publicCWinThread{...}classCWinThread:publicCCmdTarget{public:CWnd*m_pMainWnd;}9,消息循環(huán):intAFXAPIAfxWinMain(){...//Performspecificinitializationsif(!pThread->InitInstance()){...}//完成窗口初始化工作,完成窗口的注冊,完成窗口的創(chuàng)建,顯示和更新nReturnCode=pThread->Run();//繼承基類Run()方法,調(diào)用CWinThread::Run()來完成消息循環(huán)}////////////////////////////////////////////////////////////////CWinThread::Run()方法路徑:MFC|SRC|THRDCORE.CPPintCWinThread::Run(){...//phase2:pumpmessageswhileavailabledo//消息循環(huán){//pumpmessage,butquitonWM_QUITif(!PumpMessage())〃取消息并處理returnExitInstance();}while(::PeekMessage(&m_msgCur,NULL,NULL,NULL,PM_NOREMOVE));}說明:BOOLPeekMessage(”)函數(shù)說明ThePeekMessagefunctionchecksathreadmessagequeueforamessageandplacesthemessage(ifany)inthespecifiedstructure.Ifamessageisavailable,thereturnvalueisnonzero.Ifnomessagesareavailable,thereturnvalueiszero./////////////////////////////////////////////////////////////BOOLCWinThread::PumpMessage(){if(!::GetMessage(&m_msgCur,NULL,NULL,NULL))//取消息{...}//processthismessageif(m_msgCur.message!=WM_KICKIDLE&&!PreTranslateMessage(&m_msgCur)){::TranslateMessage(&m_msgCur);//進行消息(如鍵盤消息)轉(zhuǎn)換::DispatchMessage(&m_msgCur);〃分派消息到窗口的回調(diào)函數(shù)處理(實際上分派的消息經(jīng)過消息映射,交由消息響應(yīng)函數(shù)進行處理。)}returnTRUE;}9,文檔與視結(jié)構(gòu):可以認為View類窗口是CMainFram類窗口的子窗口。DOCument類是文檔類。DOC-VIEW結(jié)構(gòu)將數(shù)據(jù)本身與它的顯示分離開。文檔類:數(shù)據(jù)的存儲,加載視類:數(shù)據(jù)的顯示,修改10,文檔類,視類,框架類的有機結(jié)合:在CTEApp類CTEApp::lnitlnstance()函數(shù)中通過文檔模板將文檔類,視類,框架類的有機組織一起。CSingleDocTemplate*pDocTemplate;pDocTemplate=newCSingleDocTemplate(lDR_MAlNFRAME,RUNTlME_CLASS(CTEDoc),RUNTlME_CLASS(CMainFrame),//mainSDlframewindowRUNTlME_CLASS(CTEView));AddDocTemplate(pDocTemplate);//增加到模板(4)MFC消息映射機制的剖析一,消息映射機制1,消息響應(yīng)函數(shù):(例:在CDrawView類響應(yīng)鼠標(biāo)左鍵按下消息)在頭文件(DrawView.h中聲明消息響應(yīng)函數(shù)原型。//{{AFX_MSG(CDrawView)//注釋宏afx_msgvoidOnLButtonDown(UlNTnFlags,CPointpoint);//}}AFX_MSG//注釋宏說明:在注釋宏之間的聲明在VC中灰色顯示。afx_msg宏表示聲明的是一個消息響應(yīng)函數(shù)。在源文件(DrawView.cpp)中進行消息映射。BEGlN_MESSAGE_MAP(CDrawView,CView)//{{AFX_MSG_MAP(CDrawView)ON_WM_LBUTTONDOWN()//}}AFX_MSG_MAP//StandardprintingcommandsON_COMMAND(ID_FILE_PRINT,CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT,CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView::OnFilePrintPreview)END_MESSAGE_MAP()說明:在宏BEGIN_MESSAGE_MAP()與END_MESSAGE_MAP()之間進行消息映射。宏ON_WM_LBUTTONDOWN()把消息WM_LBUTTONDOWN與它的響應(yīng)函數(shù)OnLButtonDown()相關(guān)聯(lián)。這樣一旦有消息的產(chǎn)生,就會自動調(diào)用相關(guān)聯(lián)的消息響應(yīng)函數(shù)去處理。宏ON_WM_LBUTTONDOWN()定義如下:#defineON_WM_LBUTTONDOWN()\{WM_LBUTTONDOWN,0,0,0,AfxSig_vwp,\(AFX_PMSG)(AFX_PMSGW)(void(AFX_MSG_CALLCWnd::*)(UINT,CPoint))&OnLButtonDown},3)源文件中進行消息響應(yīng)函數(shù)處理。(DrawView.cpp中自動生成OnLButtonDown函數(shù)輪廓,如下)voidCDrawView::OnLButtonDown(UINTnFlags,CPointpoint){//TODO:Addyourmessagehandlercodehereand/orcalldefaultCView::OnLButtonDown(nFlags,point);}說明:可見當(dāng)增加一個消息響應(yīng)處理,在以上三處進行了修改。可在消息響應(yīng)函數(shù)里添加消息處理代碼完成對消息的響應(yīng)、處理。2,消息響應(yīng)的方式:在基類中針對每種消息做一個虛函數(shù),當(dāng)子類對消息響應(yīng)時候,只要在子類中重寫這個虛函數(shù)即可。缺點:MFC類派生層次很多,如果在基類對每個消息進行虛函數(shù)處理,那么從基類派生的每個子類都將背負一個龐大的虛表,這樣浪費內(nèi)存,故MFC沒有采取這中方式而采取消息映射方式。消息映射方式:MFC在后臺維護了一個句柄和C++對象指針對照表,當(dāng)收到一個消息后,通過消息結(jié)構(gòu)里資源句柄(查對照表)就可找到與它對應(yīng)的一個C++對象指針,然后把這個指針傳給基類,基類利用這個指針調(diào)用WindowProc()函數(shù)對消息進行處理,WindowProc()函數(shù)中調(diào)用OnWndMsg()函數(shù),真正的消息路由及處理是由OnWndMsg()函數(shù)完成的。由于WindowProc()和OnWndMsg()都是虛函數(shù),而且是用派生類對象指針調(diào)用的,由多態(tài)性知最總終調(diào)用子類的。在OnWndMsg()函數(shù)處理的時候,根據(jù)消息種類去查找消息映射,判斷所發(fā)的消息有沒有響應(yīng)函數(shù),具體方式是到相關(guān)的頭文件和源文件中尋找消息響應(yīng)函數(shù)聲明(從注釋宏〃{{AFX_MSG(CDrawView)...〃}}AFX_MSG之間尋找),消息映射(從宏BEGIN_MESSAGE_MAP(...)....END_MESSAGE_MAP(之間尋找),最終找到對應(yīng)的消息處理函數(shù)。當(dāng)然,如果子類中沒有對消息進行處理,則消息交由基類處理。說明:virtualLRESULTWindowProc(UINTmessage,WPARAMwParam,LPARAMlParam);virtualBOOLOnWndMsg(UINTmessage,WPARAMwParam,LPARAMlParam,LRESULT*pResult);二,有關(guān)繪圖使用SDK獲取DC句柄:HDChdc;hdc=::GetDc(m_hWnd);〃獲取DC句柄MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);LineTo(hdc,point.x,point.y);::ReleaseDC(m_hWnd,hdc);//釋放DC利用CDC類指針和CWin類成員函數(shù)獲取DC。CDC*pDC=GetDC();pDC->MoveTo(m_ptOrigin);pDC->LineTo(point);ReleaseDC(pDC);3利用CClientDC對象。(CClientDC類從CDC類派生來的)CClientDCdc(this);dc.MoveTo(m_ptOrigin);dc.LineTo(point);說明:TheCClientDCclassisderivedfromCDCandtakescareofcallingtheWindowsfunctionsGetDCatconstructiontimeandReleaseDCatdestructiontime.ThismeansthatthedevicecontextassociatedwithaCClientDCobjectistheclientareaofawindow.4,利用CWindowDC對象。(CWindowDC類從CDC類派生來的)CWindowDCdc(this);//dc.MoveTo(m_ptOrigin);dc.LineTo(point);說明:TheCWindowDCclassisderivedfromCDC.ItcallstheWindowsfunctionsGetWindowDCatconstructiontimeandReleaseDCatdestructiontime.ThismeansthataCWindowDCobjectaccessestheentirescreenareaofaCWnd(bothclientandnonclientareas).5,GetParent()得到父窗口指針;GetDesktopWindow()得到屏幕窗口指針。6,利用畫筆改變線條顏色和類型:CPenpen(PS_DOT,1,#OOffOO);〃構(gòu)造畫筆對象CClientDCdc(this);CPen*pOldPen=dc.SelectObject(&pen);〃將畫筆選入DCdc.MoveTo(m_ptOrigin);dc.LineTo(point);dc.SelectObject(pOldPen);//恢復(fù)先前的畫筆7,使用畫刷(通常利用畫刷去填充矩形區(qū)域)使用單色畫刷CBrushbrush(#ff0000);〃構(gòu)造畫刷對象CClientDCdc(this);dc.FillRect(CRect(m_ptOrigin,point),&brush);〃用指定的畫刷去填充矩形區(qū)域使用位圖畫刷CBitmapbitmap;//構(gòu)造位圖對象(使用前需要初試化)bitmap.LoadBitmap(IDB_BITMAP1);〃初試化位圖對象CBrushbrush(&bitmap);〃構(gòu)造位圖畫刷CClientDCdc(this);dc.FillRect(CRect(m_ptOrigin,point),&brush);〃用指定的位圖畫刷去填充矩形區(qū)域使用透明畫刷CBrush*pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));〃獲取透明畫刷對象指針CClientDCdc(this);CBrush*pOldBrush=dc.SelectObject(pBrush);〃將透明畫刷選入DCdc.Rectangle(CRect(m_ptOrigin,point));dc.SelectObject(pOldBrush);//釋放透明畫刷說明:TheGetStockObjectfunctionretrievesahandletooneofthepredefinedstockpens,brushes,fonts,orpalettes.HGDIOBJGetStockObject(intfnObject//typeofstockobject);ReturnsapointertoaCBrushobjectwhengivenahandletoaWindowsHBRUSHobject.staticCBrush*PASCALFromHandle(HBRUSHhBrush);//FromHandle是一個靜態(tài)方法,故可用CBrush::FromHandle()形式調(diào)用。靜態(tài)方法不屬于某一個具體對象,而屬于類本身,在類加載的時候就已經(jīng)為類靜態(tài)方法分配了代碼去,故可用CBrush::FromHandle()形式調(diào)用。靜態(tài)方法中,不能引用非靜態(tài)的數(shù)據(jù)成員和方法。靜態(tài)數(shù)據(jù)成員需要在類外單獨做初始化,形式如:變量類型類名::變量名=初始值;8,CDC::SetROP2方法:intSetROP2(intnDrawMode);Setsthecurrentdrawingmode.(5)文本編程1,創(chuàng)建插入符:voidCreateSolidCaret(intnWidth,intnHeight);//創(chuàng)建插入符voidCreateCaret(CBitmap*pBitmap);//創(chuàng)建位圖插入符voidShowCaret();//顯示插入符voidHideCaret();//隱藏插入符staticvoidPASCALSetCaretPos(POINTpoint);//移動插入符號說明:創(chuàng)建插入符要在窗口創(chuàng)建完成之后,CreateSolidCaret函數(shù)創(chuàng)建的插入符被初始化為隱藏,所以需要調(diào)用ShowCaret()將其顯示。使用CreateCaret函數(shù)創(chuàng)建位圖插入符的時候,不能使用局部的位圖對象關(guān)聯(lián)位圖資源(與資源相關(guān)聯(lián)的C++對象,當(dāng)它析構(gòu)的時候會同時把與它相關(guān)聯(lián)的資源銷毀。)2,獲取當(dāng)前字體信息的度量:CDC::GetTextMetricsBOOLGetTextMetrics(LPTEXTMETRIClpMetrics)const;說明:typedefstructtagTEXTMETRIC{/*tm*/inttmHeight;//字體高度。Specifiestheheight(ascent+descent)tmAscent;//基線以上的字體高度inttmDescent;//基線以下的字體高度inttmInternalLeading;inttmExternalLeading;inttmAveCharWidth;//字符平均寬度inttmMaxCharWidth;inttmWeight;BYTEtmItalic;BYTEtmUnderlined;BYTEtmStruckOut;BYTEtmFirstChar;BYTEtmLastChar;BYTEtmDefaultChar;BYTEtmBreakChar;BYTEtmPitchAndFamily;BYTEtmCharSet;inttmOverhang;inttmDigitizedAspectX;inttmDigitizedAspectY;}TEXTMETRIC;3,OnDraw函數(shù):virtualvoidOnDraw(CDC*pDC)當(dāng)窗口(從無到有或尺寸大小改變等)要求重繪的時候,會發(fā)送WM_PAIN消息,調(diào)用OnDraw函數(shù)進行重繪。4,獲取字符串的高度和寬度(區(qū)別字符串的長度):CDC::GetTextExtentCSizeGetTextExtent(LPCTSTRlpszString,intnCount)const;CSizeGetTextExtent(constCString&str)const;說明:TheCSizeclassissimilartotheWindowsSIZEstructure。typedefstructtagSIZE{intcx;//thex-extentintcy;//they-extent}SIZE;5,路徑層:BOOLBeginPath();//在這作圖定義路徑層剪切區(qū)域BOOLEndPath();BOOLSelectClipPath(intnMode);//調(diào)用這個函數(shù)來使當(dāng)前路徑層剪切區(qū)域與新剪切區(qū)域進行互操作。//在這覆蓋作圖(包含前定義的路徑層區(qū)域)定義新的剪切區(qū)域說明:1)SelectClipPathSelectsthecurrentpathasaclippingregionforthedevicecontext,combiningthenewregionwithanyexistingclippingregionbyusingthespecifiedmode.Thedevicecontextidentifiedmustcontainaclosedpath.////nMode:RGN_AND,RGN_COPY,RGN_DIFF,RGN_OR,RGN_XORRGN_ANDThenewclippingregionincludestheintersection(overlappingareas)ofthecurrentclippingregionandthecurrentpath.RGN_COPYThenewclippingregionisthecurrentpath.RGN_DIFFThenewclippingregionincludestheareasofthecurrentclippingregion,andthoseofthecurrentpathareexcluded.RGN_ORThenewclippingregionincludestheunion(combinedareas)ofthecurrentclippingregionandthecurrentpath.RGN_XORThenewclippingregionincludestheunionofthecurrentclippingregionandthecurrentpath,butwithouttheoverlappingareas.2)應(yīng)用:當(dāng)作圖的時候,如果想要在整幅圖形其中的某個部分和其它部分有所區(qū)別,我們可以把這部分圖形放到路徑層當(dāng)中,然后指定調(diào)用指定互操作模式調(diào)用SelectClipPath(intnMode)函數(shù)來使路徑層和覆蓋在其上新繪圖剪切區(qū)域進行互操作,達到特殊效果。6,關(guān)于文本字符串一些函數(shù):COLORREFGetBkColor()const;//得到背景顏色virtualCOLORREFSetBkColor(COLORREFcrColor);//設(shè)置背景顏色BOOLSetTextBkColor(COLORREFcr);//設(shè)置文本背景顏色virtualCOLORREFSetTextColor(COLORREFcrColor);//設(shè)置文本顏色virtualBOOLTextOut(intx,inty,LPCTSTRlpszString,intnCount);//輸出文本BOOLTextOut(intx,inty,constCString&str);CStringLeft(intnCount)const;//得到字符串左邊nCount個字符intGetLength()const;//得到字符串長度7,字體CFont::CFontCFont();//構(gòu)造函數(shù)//ConstructsaCFontobject.TheresultingobjectmustbeinitializedwithCreateFont,CreateFontIndirect,CreatePointFont,orCreatePointFontIndirectbeforeitcanbeused.選用字體事例代碼組:CClientDCdc(this);CFontfont;//構(gòu)造字體對象font.CreatePointFont(300,'華文行楷蔦NULL);//初始化字體對象,與字體資源相關(guān)聯(lián)CFont*pOldFont=dc.SelectObject(&font);//將新字體選入DCdc.SelectObject(pOldFont);//恢復(fù)原字體說明:構(gòu)造字體對象時候,必須初始化。(初始化是將字體對象與字體資源相關(guān)聯(lián))。初始化對象時候,選用的字體也可以是系統(tǒng)字體,但不一定都有效,據(jù)測試選用。8,在MFC中CEditView和cRichEditView類已經(jīng)完成了初步的文字處理。可以讓應(yīng)用程序的View類以CEditView和cRichEditView類為基類。9,平滑變色CDC::TextOut(是一個字母一個字母的輸出,達不到平滑效果。CDC::DrawText():將文字的輸出局限于一個矩形區(qū)域,超出矩形區(qū)域的文字都被截斷。利用這一特點,可每隔些時間增加矩形大小,從而可實現(xiàn)人眼中的平滑效果。CWnd::SetTimer():設(shè)置定時器。按設(shè)定的時間定時發(fā)送WM_TIMER消息。說明:UINTSetTi

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論