MFC view類dc的獲得

第三章 MFC消息映射機制和繪圖DC的獲取

我們假設您已經:

      1,知道如何創建一個單文檔的App Wizard

      2,知道C++ 類、函數重載等簡單知識

      3,知道如何給View類或者Doc文檔添加成員變量

      4,會用MFCIDE調試工具最好,那麼本文的程序您可以copy去調試

      我們在上一節講了MFC框架App類、View類、MainFrame類和Doc類的關係,那麼,基於消息的windows MFC程序設計是如何進行消息映射的呢?

 

      在進行下一節之前,我們來複習一下。

 

      對於一個MFC APPWizard運用程序,CMainFrameView是窗口類,並且是父子關係,Doc一般用於數據的加載和存儲,View用於圖像的顯示,App中是包括一些(窗口)初始化之類的東西。

    我們開始這一節的內容。

 

一、       消息映射機制

windows程序設計是種事件驅動方式的程序設計,主要基於消息的。當用戶需要完成某種功能時,需要調用OS某種支持,然後OS將用戶的需要包裝成消息,並投入到消息隊列中,最後應用程序從消息隊列中取走消息並進行響應。

在左邊View類處點右鍵,在出現的菜單裏點擊“Add Windows Message Handler”,在出現的對話框裏選擇“WM_LBUTTONDOWN”,添加消息映射函數。

回到原文件,我們將看到三處進行了修改:

 

1,    在頭文件(View.h)中聲明消息響應函數原型。

 

//{{AFX_MSG(CDrawView)   //註釋宏

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

//}}AFX_MSG   //註釋宏

afx_msg宏表示聲明的是一個消息響應函數。

 

2 在源文件(View.cpp)中進行消息映射。

 

BEGIN_MESSAGE_MAP(CDrawView, CView)

 //{{AFX_MSG_MAP(CDrawView)

 ON_WM_LBUTTONDOWN()

 //}}AFX_MSG_MAP

 

在宏BEGIN_MESSAGE_MAP()END_MESSAGE_MAP()之間進行消息映射。

ON_WM_LBUTTONDOWN()把消息WM_LBUTTONDOWN與它的響應函數OnLButtonDown()相關聯。這樣一旦有消息的產生,就會自動調用相關聯的消息響應函數去處理。

 

ON_WM_LBUTTONDOWN()定義如下:

 

 #define ON_WM_LBUTTONDOWN() 

 

{ WM_LBUTTONDOWN, 0, 0, 0,

 

AfxSig_vwp,  (AFX_PMSG)(AFX_PMSGW)(void

 

(AFX_MSG_CALL CWnd::*)(UINT, CPoint))&OnLButtonDown },

 

3 源文件中進行消息響應函數處理。

 

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)

 

{

 

 // TODO: Add your message handler code here and/or call default

 

 CView::OnLButtonDown(nFlags, point);

 

}

 

說明:

可見當增加一個消息響應處理,在以上三處進行了修改。可在消息響應函數裏添加消息處理代碼完成對消息的響應、處理。

 

 

 

消息響應的可能方式:

 

1)在基類中針對每種消息做一個虛函數,當子類對消息響應時候,只要在子類中重寫這個虛函數即可。缺點:MFC類派生層次很多,如果在基類對每個消息進行虛函數處理,那麼從基類派生的每個子類都將揹負一個龐大的虛表,這樣浪費內存,故MFC沒有采取這中方式而採取消息映射方式。

 

2)消息映射方式:MFC在後臺維護了一個句柄和C++對象指針對照表,當收到一個消息後,通過消息結構裏資源句柄(查對照表)就可找到與它對應的一個C++對象指針,然後把這個指針傳給基類,基類利用這個指針調用WindowProc()函數對消息進行處理,WindowProc()函數中調用OnWndMsg()函數,真正的消息路由及處理是由OnWndMsg()函數完成的。由於WindowProc()OnWndMsg()都是虛函數,而且是用派生類對象指針調用的,由多態性知最總終調用子類的。在OnWndMsg()函數處理的時候,根據消息種類去查找消息映射,判斷所發的消息有沒有響應函數,具體方式是到相關的頭文件和源文件中尋找消息響應函數聲明(從註釋宏//{{AFX_MSG(CDrawView)...//}}AFX_MSG之間尋找),消息映射(從宏BEGIN_MESSAGE_MAP(...)....END_MESSAGE_MAP()之間尋找),最終找到對應的消息處理函數。當然,如果子類中沒有對消息進行處理,則消息交由基類處理。

 

說明:

 

virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

 

virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);

 

二、       繪圖DC的獲取

 

說明:在View類添加WM_LBUTTONDOWNWM_LBUTTONUP的消息處理函數,我們將用來演示各種DC的獲取,以及顯示效果。

 

View類添加全局變量CPoint m_ptOrigin用來存儲左鍵按下點座標。下面集中來關注OnLButtonUp中的繪圖程序和效果。

 

以下語句添加於OnLButtonUp函數中,可以查看不同的效果。

 

1,使用SDK獲取DC句柄:

 

HDC hdc;

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

 

2,利用CDC類指針和CWin類成員函數獲取DC

 

CDC *pDC=GetDC();

pDC->MoveTo(m_ptOrigin);

pDC->LineTo(point);

ReleaseDC(pDC);

 

3,利用CClientDC對象。(CClientDC類從CDC類派生來的)

 

CClientDC dc(this);

dc.MoveTo(m_ptOrigin);

dc.LineTo(point);

 

4,利用CWindowDC對象。(CWindowDC類從CDC類派生來的)

CWindowDC dc(this);//

dc.MoveTo(m_ptOrigin);

dc.LineTo(point);

5,父窗口(MainFrame框架)和屏幕指針。

將上面的dc(this)分別改成GetParent()GetDesktopWindow(),就可以得到父窗口指針和屏幕窗口指針。

可以分別試驗畫線效果。

 

6,利用畫筆改變線條顏色和類型:

CPen pen(PS_DOT,1,RGB(0,255,0));//構造畫筆對象

CClientDC dc(this);CPen *pOldPen=dc.SelectObject(&pen);//將畫筆選入DC

dc.MoveTo(m_ptOrigin);

dc.LineTo(point);

dc.SelectObject(pOldPen);//恢復先前的畫筆

 

7,使用畫刷(通常利用畫刷去填充矩形區域):

使用單色畫刷

CBrush brush(RGB(255,0,0));//構造畫刷對象

CClientDC dc(this);

dc.FillRect(CRect(m_ptOrigin,point),&brush);//用指定的畫刷去填充矩形區域

 

使用位圖畫刷

CBitmap bitmap;//構造位圖對象(使用前需要初試化)

bitmap.LoadBitmap(IDB_BITMAP1);//初試化位圖對象

CBrush brush(&bitmap);//構造位圖畫刷

CClientDC dc(this);

dc.FillRect(CRect(m_ptOrigin,point),&brush);//用指定的位圖畫刷去填充矩形區域

 

使用透明畫刷

CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));//獲取透明畫刷對象指針

CClientDC dc(this);

CBrush *pOldBrush=dc.SelectObject(pBrush);//將透明畫刷選入DC

dc.Rectangle(CRect(m_ptOrigin,point));

dc.SelectObject(pOldBrush);//釋放透明畫刷

8,注意點:

 

1)靜態方法不屬於某一個具體對象,而屬於類本身,在類加載的時候就已經爲類靜態方法分配了代碼去,故可用CBrush::FromHandle()形式調用。

2)靜態方法中,不能引用非靜態的數據成員和方法。

3)靜態數據成員需要在類外單獨做初始化,形式如: 變量類型 類名::變量名=初始值;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章