CDC,CClientDC,CPaintDC,CWindowDC 比較區別windows
MFC中的CDC,CClientDC,CPaintDC,CWindowDC的區別異步
CDC是Windows繪圖設備的基類。函數
CClientDC:
(1)(客戶區設備上下文)用於客戶區的輸出,與特定窗口關聯,可讓開發者訪問目標窗口中客戶區,其構造函數中包含了GetDC,析構函數中包含了ReleaseDC。優化
CPaintDC:
(1)用於響應窗口重繪消息(WM_PAINT)是的繪圖輸出。
(2)CPaintDC在構造函數中調用BeginPaint()取得設備上下文,在析構函數中調用EndPaint()釋放設備上下文。 EndPaint()除了釋放設備上下文外,還負責從消息隊列中清除WM_PAINT消息。所以,在處理窗口重畫時,必須使用CPaintDC,不然 WM_PAINT消息沒法從消息隊列中清除,將引發不斷的窗口重畫。
(3)CPaintDC也只能用在WM_PAINT消息處理之中。this
CWindowDC:
(1)可在非客戶區繪製圖形,而CClientDC,CPaintDC只能在客戶區繪製圖形。
(2)座標原點是在屏幕的左上角,CClientDC,CPaintDC下座標原點是在客戶區的左上角。
(3)關聯一特定窗口,容許開發者在目標窗口的任何一部分進行繪圖,包含邊界與標題,這種DC同WM_NCPAINT消息一塊兒發送。spa
===========code
CPaintDC用於響應窗口重繪消息(WM_PAINT)是的繪圖輸出。CPaintDC在構造函數中調用BeginPaint()取得設備上下文,在析構函數中調用EndPaint()釋放設備上下文。EndPaint()除了釋放設備上下文外,還負責從消息隊列中清除 WM_PAINT消息。所以,在處理窗口重畫時,必須使用CPaintDC,不然WM_PAINT消息沒法從消息隊列中清除,將引發不斷的窗口重畫。 CPaintDC也只能用在WM_PAINT消息處理之中。對象
系統什麼時候發送WM_PAINT消息?隊列
系統會在多個不一樣的時機發送WM_PAINT消息:當第一次建立一個窗口時,當改變窗口的大小時,當把窗口從另外一個窗口背後移出時,當最大化或最小 化窗口時,等等,這些動做都是由系統管理的,應用只是被動地接收該消息,在消息處理函數中進行繪製操做;大多數的時候應用也須要可以主動引起窗口中的繪製 操做,好比當窗口顯示的數據改變的時候,這通常是經過InvalidateRect和InvalidateRgn函數來完成的。 InvalidateRect和InvalidateRgn把指定的區域加到窗口的Update Region中,當應用的消息隊列沒有其餘消息時,若是窗口的Update Region不爲空時,系統就會自動產生WM_PAINT消息。ci
系統爲何不在調用Invalidate時發送WM_PAINT消息呢?又爲何非要等應用消息隊列爲空時才發送WM_PAINT消息 呢?這是由於系統把在窗口中的繪製操做看成一種低優先級的操做,因而儘量地推後作。不過這樣也有利於提升繪製的效率:兩個WM_PAINT消息之間經過 InvalidateRect和InvaliateRgn使之失效的區域就會被累加起來,而後在一個WM_PAINT消息中一次獲得更新,不只能避免屢次 重複地更新同一區域,也優化了應用的更新操做。像這種經過InvalidateRect和InvalidateRgn來使窗口區域無效,依賴於系統在合適 的時機發送WM_PAINT消息的機制其實是一種異步工做方式,也就是說,在無效化窗口區域和發送WM_PAINT消息之間是有延遲的;有時候這種延遲 並非咱們但願的,這時咱們固然能夠在無效化窗口區域後利用SendMessage 發送一條WM_PAINT消息來強制當即重畫,但不如使用Windows GDI爲咱們提供的更方便和強大的函數:UpdateWindow和RedrawWindow。UpdateWindow會檢查窗口的Update Region,當其不爲空時才發送WM_PAINT消息;RedrawWindow則給咱們更多的控制:是否重畫非客戶區和背景,是否老是發送 WM_PAINT消息而無論Update Region是否爲空等。
說明:在繪圖時推薦使用CClientDC,CPaintDC和CWindowDC對象,而不推薦直接使用CDC對象。
創建項目,採用單文檔結構
HDC:
首先在CYourClassView類中add windows message handler, 一個是LButtonDown, 另外一個是LButtonUp.添加成員變量:m_ptOrigin用來記錄初始點位置。
在view結構體中初始化m_ptOrigin變量:
CYourClassView:: CYourClassView ()
{
// TODO: add construction code here
m_ptOrigin=0;
}
在LButtonDown函數裏面添加代碼:
void CYourClassView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_ptOrigin=point;
CView::OnLButtonDown(nFlags, point);
}
在LButtonUp中添加代碼,首先使用HDC:
void CYourClassView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
HDC hdc;
hdc=::GetWindowDC(m_hWnd);
MoveToEx(hdc,m_ptOrigin.x,m_ptOrigin.y,NULL);
LineTo(hdc,point.x,point.y);
::ReleaseDC(m_hWnd,hdc);
CView::OnLButtonUp(nFlags, point);
}
使用CDC:
void CYourClassView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CDC *pdc=GetDC();
pdc->MoveTo(m_ptOrigin);
pdc->LineTo(point);
ReleaseDC(pdc);
CView::OnLButtonUp(nFlags, point);
}
使用CClientDC:
void CYourClassView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
CView::OnLButtonUp(nFlags, point);
}
使用CWindowDC:
void CYourClassView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CWindowDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
CView::OnLButtonUp(nFlags, point);