標籤:
Windows-訊息映射機制原理和簡單的繪圖技術
1.MFC訊息映射機制
眾所周知,Windows程式是基於訊息編程的,但是在MFC中已經為我們封裝好了這個架構的訊息機制,我們需要瞭解它的實現原理,才能深入的學習和精通Visual C++。
**(1).訊息映射機制的原理:
MFC訊息映射機制的具體實現方法是,在每個能接收和處理訊息的類中,定義一個訊息和訊息函數靜態對照表,即訊息映射表。在訊息映射表中,訊息與對應的訊息處理函數指標是成對出現的。某個類能處理的所有訊息及其對應的訊息處理函數的地址都列在這個類所對應的靜態表中。當有訊息需要處理的時候,程式只要搜尋該訊息靜態表,查看錶中是否含有該訊息,就可知道該類能否處理此訊息。如果能處理該訊息,則同樣依照靜態表能很容易找到並調用對應的訊息處理函數。**
(2).在Visual C++中增加一個訊息所需要的三處代碼
標頭檔中第一處:
這裡在標頭檔中定義了該類能夠處理的訊息
源檔案中第二處:
源檔案的開頭定義該類的訊息映射表
源檔案中第三處:
這裡源檔案中訊息的具體邏輯代碼實現
(3).訊息映射機制的底層實現過程
MFC在後台維護了一個視窗控制代碼與對應的C++對象指標的對照表,當視窗收到某個訊息時,訊息的第一個參數就指定了該訊息和哪個視窗控制代碼相關,通過對照表,就可以找到與之相關的C++對象指標,然後把這個指標傳遞給應用程式架構視窗類別的基類,後者會調用一個名為WindowProc的視窗過程函數,該函數的定義位於WinCore.cpp檔案中,這個函數又會調用OnWndMsg函數在完成真正的訊息路由,訊息映射就是由此函數完成的。
WindProc
OnWndMsg代碼過長,這裡給出聲明和檔案路徑,大家可以自己去分析,這裡面的代碼和用平台SDK編寫一個視窗的回呼函數是差不多的,就是對訊息的判斷和處理。
路徑:C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\atlmfc\src\mfc\wincore.cpp
圖解底層實現機制:
2.MFC繪製線條的幾種方法
(1).利用Platform SDK全域函數繪製
//平台的SDK,HDC是裝置上下文 HDC hdc = ::GetDC(m_hWnd);//擷取DC MoveToEx(hdc, m_ptOrigin.x, m_ptOrigin.y, nullptr); LineTo(hdc, point.x, point.y); ::ReleaseDC(m_hWnd, hdc);//記得釋放DC
(2).利用MFC的CDC類繪製
CDC類是MFC中一個專門用於繪圖的類
//需要手動管理CDC對象的建立和釋放 CDC* pDC = GetDC();//得到DC pDC->MoveTo(m_ptOrigin); pDC->LineTo(point);//畫線的API ReleaseDC(pDC);//釋放DC
(3).利用CClientDC
繼承CDC,可以自動擷取和釋放DC
//自動建立和釋放CDC對象 CClientDC dc(this);//畫到視圖視窗上 dc.MoveTo(m_ptOrigin); dc.LineTo(point);
畫在主視窗上
//自動建立和釋放CDC對象 CClientDC dc(GetParent());//畫到主視窗上 dc.MoveTo(m_ptOrigin); dc.LineTo(point);
(4).利用CWindowDC
//Windows螢幕的DC,畫出的線條支援直接出現在螢幕上 //CWindowDC dc(this);//畫在視圖上 //CWindowDC dc(GetParent());//畫在主架構視窗上 dc.MoveTo(m_ptOrigin); dc.LineTo(point);
(5).在桌面視窗中畫線
CWindowDC dc(GetDesktopWindow());//直接畫在螢幕上 dc.MoveTo(m_ptOrigin); dc.LineTo(point);
(6).繪製彩色線條
CPen pen(PS_DOT, 1, RGB(255, 1, 1));//畫紅色的點線 CClientDC dc(this); CPen* pOldPen = dc.SelectObject(&pen);//儲存先前的畫筆,必要的一步 dc.MoveTo(m_ptOrigin); dc.LineTo(point); dc.SelectObject(pOldPen);//恢複先前的畫筆
(7).利用畫刷CBrush繪圖
//畫出圖片bitmap CBitmap bitmap; //載入位元影像資源 bitmap.LoadBitmap(IDR_MAINFRAME);//位元影像的資源ID CBrush brush(&bitmap); CClientDC dc(this); //填充矩形 dc.FillRect(CRect(m_ptOrigin, point), &brush);
(8).繪製連續的線條
CClientDC dc(this); if (m_bDraw)//m_bDraw是滑鼠左鍵是否按下的BOOL成員變數,這裡必須為TRUE { dc.MoveTo(m_ptOrigin); dc.LineTo(point); m_ptOrigin = point;//這次的終點作為下一次繪製線段的起點 }
(9).繪製連續的帶顏色的線條
CClientDC dc(this); //改變畫筆的顏色 CPen pen(PS_SOLID, 1, RGB(255, 0, 0)); CPen* pOldPen = dc.SelectObject(&pen); //將畫筆選入裝置描述表 if (m_bDraw)//m_bDraw是滑鼠左鍵是否按下的BOOL成員變數,這裡必須為TRUE { dc.MoveTo(m_ptOrigin); dc.LineTo(point); m_ptOrigin = point; } dc.SelectObject(pOldPen);//恢複之前的畫筆
(10).畫扇形
CClientDC dc(this); CPen pen(PS_SOLID, 1, RGB(255, 0, 0)); CPen* pOldPen = dc.SelectObject(&pen); if (m_bDraw) { dc.MoveTo(m_ptOrigin);//起點不變,畫出來的是扇形 dc.LineTo(point); } dc.SelectObject(pOldPen);
(11).畫出帶邊界的扇形
CClientDC dc(this); CPen pen(PS_SOLID, 1, RGB(255, 0, 0)); CPen* pOldPen = dc.SelectObject(&pen); if (m_bDraw) { dc.MoveTo(m_ptOrigin); dc.LineTo(point); dc.LineTo(m_ptOld);//這次的線段終點畫到上一條線段的終點就可以形成邊界 m_ptOld = point;//儲存上一條線段的終點 } dc.SelectObject(pOldPen);
(12).畫矩形
//畫出矩形並且使用畫刷來填充顏色 CClientDC dc(this); CBrush brush(RGB(255, 0, 0)); dc.FillRect(CRect(m_ptOrigin, point), &brush);
畫透明的矩形
CClientDC dc(this); //建立透明的畫刷,GetStockObject返回的是HGDIOBJ,需要強制轉換成HBRUSH,而且還需要將控制代碼轉換成對象指標,要使用FromHandle //這個靜態函數 CBrush* pBrush = CBrush::FromHandle(static_cast<HBRUSH>(GetStockObject(NULL_BRUSH))); //儲存舊的畫刷 CBrush* pOldBrush = dc.SelectObject(pBrush); //畫出矩形 dc.Rectangle(CRect(m_ptOrigin, point)); //恢複舊的畫刷 dc.SelectObject(pOldBrush);
(13).設定繪圖模式
CClientDC dc(this); dc.SetROP2(R2_BLACK);//設定繪圖的模式, 查看MSDN的詳細介紹
3.MFCBuild
Build命令可以直接用F7來運行
4.總結
在使用MFC的時候,我們需要瞭解它的底層實現機制,這樣我們在遇到問題的時候就知道是哪個環節出了問題,這是我們必經之路,另外在繪圖的時候,需要清除我們畫的的父視圖是哪個。
下面是我總結的思維導圖,方便大家形成良好的思維,一種有兩個,是不同的時間做的。
(1).
(2).
圖片的資源分享:https://yunpan.cn/cPczaZE4HU5c4 訪問密碼 f09a
Windows-訊息映射機制原理和簡單的繪圖技術