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
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICMyYTMvw1dvwlMvwlM3VWaWV2Zh1Wa-cmbw5ie0MDdjNHcz52MvwlM2MTOzUTMtUGall3LcVmdhNXLwRHdo9CXt92YucWbpRWdvx2Yx5yazF2Lc9CX6MHc0RHaiojIsJye.png)
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()函數合起來完成畫線工作。
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()等。