天天看點

圖像處理程式架構—MFC相關知識點

CDC:Windows使用與裝置無關的圖形裝置環境(DC :Device Context) 進行顯示 。

MFC基礎類庫定義了裝置環境對象類----CDC類。

CDC與CGdiObject的關系

說道CDC類就不能不提一下GdiObject---圖形對象類。 在Windows應用程式中,裝置環境與圖形對象共同工作,協同完成繪圖顯示工作。就像畫家繪畫一樣,裝置環境好比是畫家的畫布,圖形對象好比是畫家的畫筆。用畫筆在畫布上繪畫,不同的畫筆将畫出不同的畫來。選擇合适的圖形對象和繪圖對象,才能按照要求完成繪圖任務。

有關CDC類的繼承

父類:從 CObject 直接繼承而來。繼承了CObject類的各種特性,如動态建立等等。

子類:CClientDC-------代表操作視窗的DC ,是比較常用的一個子類

CMetaFileDC ------響應Meta File的DC ,Meta File是一些GDI消息。

CPaintDC-------響應WM_PAINT消息的DC。

CWindowDC ------代表整個螢幕的DC

CDC類的資料成員

資料成員隻有兩個:

HDC m_hDC : CDC對象使用的輸出裝置上下文

HDC m_hAttribDC : CDC對象使用的屬性裝置上下文

二者在CDC對象建立時指向相同的裝置上下文。

CDC類:定義裝置環境對象類 

CDC::BitBlt 從源裝置環境拷貝一個位圖到目前裝置環境中

BOOL BitBlt(int x,int y,int nWidth,int nHeight,CDC* pSrcDC,int xSrc,int ySrc,DWORD dwRop);

參數:x,y為目的矩形的左上角坐标;nWidth,nHeight為目的矩形的寬度和高度;pSrcDC是指向源裝置環境的指針;xSrc,ySrc源位圖左上角的坐标;dwRop為光栅操作碼。

CDC::CreateCompatibleDC 建立一個與pDC指定的裝置相相容的記憶體裝置環境

virtual BOOL CreateCompatibleDC(CDC* pDC);

參數:pDC 裝置環境指針

傳回值:若成功,傳回非0;否則傳回0

CDC::Detach 将裝置環境從CDC對象中分離開來

HDC Detach()

傳回值:分離的裝置環境

CDC::DrawEdge 繪制矩形邊框或邊框的一部分

BOOL DrawEdge(LPRECT lpRect,UINT nEdge,UINT nFlags);

參數lpRect指向矩形的RECT結構的指針;nEdge指定矩形内外邊界的風格,必須是一個内邊界标志和外邊界标志的組合,取值為:

BDR_RAISEDINNER:内邊界凸出;

BDR_SUNKENINNER:内邊界凹下;

BDR_RAISEDOUTER:外邊界凸出;

BDR_SUNKENOUTER:外邊界凹下;

nFlags指定邊界的類型,取值為:

BF_RECT:矩形的所有四邊;

BF_LEFT:矩形的左邊;

BF_BOTTOM:矩形的底邊;

BF_RIGHT:矩形的右邊;

BF_TOP:矩形的上邊;

BF_TOPLEFT:矩形的上邊和左邊;

BF_TOPRIGHT:矩形的上邊和右邊;

BF_BOTTOMLEFT:矩形的下邊和左邊;

BF_BOTTOMRIGHT:矩形的下邊和右邊。

傳回值:若成功,傳回非0;否則傳回0。

CDC::DrawFocusRect 畫一個說明輸入焦點的矩形

void DrawFocusRect(LPCRECT lpRect);

參數:lpRect 指向繪制矩形的邏輯坐标的RECT結構或CRect對象。 

CDC::FillSolidRect 用指定單顔色填充矩形 

void FillSolidRect(LPCRECT lpRect,COLORREF clr);

void FillSolidRect(int x,int y,int cx,int cy,COLORREF clr);

參數:lpRect指定要填充的矩形;clr填充的顔色

x,y矩形的左上角坐标,cx、cy為矩形寬度和高度

CDC::FromHandle 在給予一個裝置環境句柄時傳回一個CDC對象指針 

static CDC* PASCAL FromHandle(HDC hDC);

參數:hDC 裝置環境句柄

傳回值:CDC對象指針

CDC::PaintRgn 用目前畫刷填充一個CRgn對象的區域 

BOOL PaintRgn(CRgn* pRgn);

參數:指向一個CRgn對象的指針

傳回值:若成功,傳回非0;否則傳回0

CDC::Rectangle 用目前畫筆畫一個矩形,并用目前畫刷填充為實心矩形 

BOOL Rectangle(int x1,int y1,int x2,int y2);

BOOL Rectangle(LPCRECT lpRect);

參數:x1、y1為矩形左上角坐标,x2、y2為矩形右下角坐标

lpRect為RECT結構或CRect對象

傳回值:若成功,傳回非0;否則傳回0

CDC::RestoreDC 将裝置環境恢複成先前的狀态 

virtual BOOL RestoreDC(int nSaveDC);

參數:nSaveDC裝置環境先前狀态的整數辨別

傳回值:若成功,傳回非0;否則傳回0

CDC::RoundRect 用目前畫筆畫一個圓角矩形,并用目前畫刷填充 

BOOL RoundRect(int x1,int y1,int x2,int y2,int x3,int y3);

BOOL RoundRect(LPCRECT lpRect,POINT point);

參數:x1、y1為左上角坐标,x2、y2為右下角坐标,x3、y3為畫圓角的橢圓的邏輯寬度和高度

lpRect為RECT結構或CRect對象,point中的x、y為畫圓角的橢圓的邏輯寬度和高度

傳回值:若成功,傳回非0;否則傳回0

CDC::SaveDC 儲存裝置環境的目前狀态 

virtual int SaveDC();

傳回值:若成功,傳回辨別儲存裝置環境的整數;若錯誤傳回0

CDC::SelectStockObject 将一個預定義的庫存對象裝入裝置環境 

virtual CGdiObject* SelectStockObject(int nIndex);

參數:nIndex庫存對象的索引值,常用取值:

BLACK_BRUSH 黑色畫刷; DKGRAY_BRUSH 深灰色畫刷;

GRAY_BRUSH 灰色畫刷; LTGRAY_BRUSH 淺灰色畫刷;

WHITE_BRUSH 白色畫刷; HOLLOW_BRUSH 中空畫刷;

NULL_BRUSH 空畫刷;

BLACK_PEN 黑色畫筆; WHITE_PEN 白色畫筆;

NULL_PEN 空畫筆;

SYSTEM_FONT 系統字型;

傳回值:被替換的CGdiObject對象的指針,若調用失敗,傳回NULL

圖像處理程式架構—MFC相關知識點

CDC::SetMapMode設定映射模式,映射模式定義了将邏輯機關轉換為裝置機關的機關量,并定義了X和Y的方向

virtual int SetMapMode(int nMapMode);

傳回值:上一個映射模式。

CDC::SelectObject 将一個對象選入裝置環境,替代同一類型的先前對象 

CPen* SelectObject(CPen* pPen);

CBrush* SelectObject(CBrush* pBrush);

virtual CFont* SelectObject(CFont* pFont);

CBitmap* SelectObject(CBitmap* pBitmap);

int SelectObject(CRgn* pRgn);

參數:要選入的新對象的指針

傳回值:先前的舊對象的指針

CDC::SetBkMode 設定背景模式 

int SetBkMode(int nBkMode);

參數:nBkMode為要設定的背景模式,取值可以為:

OPAQUE 在繪制文本前用目前背景色填充背景,這是預設的背景模式

TRANSPARENT 繪制前不改變背景(即文字背景透明)

傳回值:先前的背景模式

CDC::MoveTo 設定畫圖的起點位置 

CPoint MoveTo(int x,int y);

CPoint MoveTo(POINT point);

參數:x、y為新位置的坐标;point為新位置坐标

傳回值:先前位置的坐标

CDC::LineTo 從目前位置到指定點畫直線 

BOOL LineTo(int x,int y);

BOOL LineTo(POINT point);

參數:x、y為直線末端的坐标;point為直線末端的坐标

傳回值:若成功,傳回非0;否則傳回0

該函數通常與MoveTo()函數合起來完成畫線工作。 

圖像處理程式架構—MFC相關知識點

CDC::SetTextColor 設定文本顔色 

virtual COLORREF SetTextColor(COLORREF crColor);

參數:crColor指定文本顔色

傳回值:先前的文本顔色

CDC::TextOut 用目前字型在指定位置寫一字元串 

virtual BOOL TextOut(int x,int y,LPCTSTR lpszString,int nCount);

BOOL TextOut(int x,int y,const CString& str);

參數:x,y文本左上角坐标;lpszString訓示要輸出的字元串;nCount為字元串中位元組數;str為要輸出的CString對象

傳回值:若成功,傳回非0;否則傳回0

CDC::SetBkColor 設定目前背景色 

virtual COLORREF SetBkColor(COLORREF crColor);

參數:crColor為新背景色

傳回值:先前背景色;若錯誤,傳回值為0x80000000

CDC::GetTextExtent 使用目前字型計算一行文本的寬度和高度 

CSize GetTextExtent(LPCTSTR lpszString,int nCount)const;

CSize GetTextExtent(const CString& str)const;

參數:lpszString指向一個字元串,nCount字元串中字元數

str 一個字元串對象

傳回值:字元串文本的寬度和高度(以邏輯機關表示)

CDC::GetTextMetrics 檢取目前字型的規格 

BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics)const;

參數:lpMetrics 指向用于接收字型規格的TEXTMETRIC結構

傳回值:若成功,傳回非0;否則傳回0

CDC::DrawText 在指定的矩形内繪制格式化的文本 

virtual int DrawText(LPCTSTR lpszString,int nCount,LPRECT lpRect,UINT nFormat);

int DrawText(const CString& str,LPRECT lpRect,UINT nFormat);

參數:lpszString訓示要輸出的字元串;nCount為字元串中位元組數;lpRect訓示文本所在的矩形;str為要輸出的CString對象;nFormat為格式化文本的方式,常用取值:

DT_BOTTOM 文本底對齊,必須和DT_SINGLELINE聯用;

DT_CENTER 居中顯示文本; DT_LEFT 文本左對齊;

DT_RIGHT 文本右對齊; DT_TOP 正文與行頂部對齊(僅指單個行);

DT_NOCLIB 繪制時不加裁減;DT_SINGLELINE 單行顯示;

DT_VCENTER 指定在垂直方向上居中顯示文本(僅隻單個行); 

DT_WORDBREAK 若單詞超過矩形邊界,行将在單詞間斷開

傳回值:若調用成功,傳回文本的高度

OnInitialUpdate概括

視圖視窗完全建立後第一個被架構調用的函數。架構在第一次調用OnDraw前會調用OnInitialUpdate,是以OnInitialUpdate是設定滾動視圖的邏輯尺寸和映射模式的最合适的地方。

時間上,兩者先後順序不同,構造函數生成本類的對象,但沒有産生視窗,OnCreate後視窗産生, 然後才是視圖的OnInitialUpDate,一般在這裡對視圖的顯示做初始化。簡單點,就是OnCreate隻是産生VIEW的基本結構和變量而在OnInitialUpDate()中,主要初始化視圖中控件等。對各個變量進行初始化操作。

例子。我們要在視圖中添加一個button和combobox控件則

2OnCreate函數中寫法如下編輯

int CFormView::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CView::OnCreate(lpCreateStruct) == -1)

return -1;

// TODO: Add your specialized creation code here

CRect rect(20,20,100,50);

m_ctrlButton.Create("Button1",WS_CHILD|WS_VISIBLE,rect,this,NULL);

//建立按扭控件

CFont *pFont=CFont::FromHandle((HFONT)::GetStockObject(ANSI_VAR_FONT));

CRect rect1(150,20,350,100);

m_combobox.Create(WS_CHILD|WS_VISIBLE|CBS_SIMPLE|CBS_NOINTEGRALHEIGHT|WS_VSCROLL,rect1,this,NULL);

return 0;

}

3OnInitialUpDate中寫法編輯

void CFormView::OnInitialUpdate()

{

CView::OnInitialUpdate();

// TODO: Add your specialized code here and/or call the base class

//初始化組合框控件

m_combobox.AddString("Mondy");

m_combobox.AddString("Tuesday");

m_combobox.AddString("Wednesday");

m_combobox.AddString("Thursday");

m_combobox.AddString("Saturday");

m_combobox.AddString("Sunday");

}

在MFC程式設計中,按照傳統的設計,如果處理WM_PAINT消息,一般會派生一個OnPaint函數,映射到WM_PAINT消息上進行繪圖處理。但是很多程式中并沒有出現OnPaint,一個OnDraw函數做了更多的繪圖操作。而在消息映射的清單中,也沒有見到WM_PAINT到OnDraw的映射。

實際上,OnDraw不是OnPaint的映射,出現OnDraw,是為了實作各種不同的裝置上的繪圖一緻性。

首先,讀者需要明白的是,WM_PAINT消息是為了繪制螢幕而出現的,是以,在OnPaint中,我們隻能存取螢幕DC,進行繪制,常見的代碼是:

void MyWnd::OnPaint()

{

CPaintDC dc(this);

//draw code here

}

這裡的CPaintDC的構造函數會自動調用BeginPaint,獲得一個螢幕DC,并附加在dc對象上。當dc對象析構時,系統自動調用EndPaint并使invalidated rectangle變成validated狀态,進而結束繪制。(注意,重複建立CPaintDC執行個體會失敗也因為如此)

如果我們在OnPaint中繪制,那麼在列印機上繪制我們就需要再寫一個OnPrint函數,重新繪制。這樣,程式設計者就需要維護兩套代碼。為了簡化操作,MFC架構把大部分繪制操作都放在OnDraw中,OnPaint和OnPrint隻構造相應的DC,然後分别調用OnDraw.也就是說,OnDraw适用于所有的裝置,而OnPaint隻适用于螢幕。

大家在設計過程中必須注意:OnDraw是被基類的OnPaint主動調用的,如果你繼承了OnPaint,你應該要麼調用基類的OnPaint(此前不得建立CPaintDC執行個體,也不得調用BeginPaint),要麼自己建立CPaintDC執行個體,并調用OnDraw.

MFC中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的成員函數. 

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。 

其次:我們在第《每天跟我學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); ).. 

隐式調用:當由OnPaint來進行消息響應時,系統自動調用CView::OnDraw(&pDC). 

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

OnEraseBkGnd(),是視窗背景需要重新整理時由系統調用的。明顯的一個例子是設定視窗的背景顔色(你可以把這放在OnPaint中去做,但是會使産生閃爍的現象)。 

至于怎麼界定背景和前景,那要具體問題具體分析了,一般情況下,你還是很容易差別的吧。 

的确,OnPaint()用來響應WM_PAINT消息,視類的OnPaint()内部根據是列印還是螢幕繪制分别以不同的參數調用OnDraw()虛函數。是以在OnDraw()裡你可以差別對待列印和螢幕繪制。 

其實,MFC在進行列印前後還做了很多工作,調用了很多虛函數,比如OnPreparePrint()等。