Invalidate使整個窗口客戶區無效。
窗口的客戶區無效意味著需要重繪。Windows會在應用程序的消息隊列里放置WM_PAINT消息。UpdateWindow()的作用是使窗口立即重繪,可使WM_PAINT消息被直接發送到目標窗口,從而導致窗口立即重繪。
坐標空間和轉換
Win32應用程序編程接口(API)使用四種坐標空間:世界坐標系空間、頁面空間、設備空間、和物理設備空間。應用程序運用世界坐標系空間對圖形輸出進行旋轉、斜切或者反射。
Win32 API把世界坐標系空間和頁面空間稱為邏輯空間;最后一種坐標空間(即物理設備空間)通常指應用程序窗口的客戶區;但是它也包括整個桌面、完整的窗口(包括框架、標題欄和菜單欄)或打印機的一頁或繪圖儀的一頁紙。物理設備的尺寸隨顯示器、打印機或繪圖儀所設置的尺寸而變化。如果該應用程序調用了SetWorldTransform函數,那么映射就從應用程序的世界坐標系空間開始;否則,映射在頁面空間中進行。實際編程中,主要處理的是從頁面空間到設備空間的轉換。
邏輯坐標和設備坐標
幾乎在所有的GDI函數中使用的坐標值都是采用的邏輯單位。Windows必須將邏輯單位轉換為“設備單位”,即像素。這種轉換是由映射方式、窗口和視口的原點以及窗口和視口的范圍所控制的。
Windows對所有的消息(如WM_SIZE、WM_MOUSEMOVE、WM_LBUTTONDOWN、WM_LBUTTONUP),所有的非GDI函數和一些GDI函數(例如GetDeviceCaps函數),永遠使用設備坐標。窗口和視口
窗口是基于邏輯坐標的,邏輯坐標以cm mm為單位
視口是基于設備坐標的,設備坐標以像素為單位兩個原則:
1.總是由窗口原點映射為視口原點。即無論你窗口的原點和視口的原點怎么變,窗口的原點總是映射到視口的原點。(記住:映射方向是窗口到視口,而不是視口向窗口映射)
2.不管利用函數(如:SetViewportOrgExt和SetWindowOrgEx)對窗口和視口的原點做怎么改變,設備點(0,0)始終是客戶區的左上角。移動窗口和視口的原點
SetWindowOrg(100, -300)則邏輯點(100,-300)映射為設備點(0,0)
SetViewportOrg(100, -300)則邏輯點(0,00)映射為設備點(100,-300)
不管原點怎么變化,永遠都是原點映射到原點。CPtrArray對象存儲多個對象的地址。
OnPaint 和 OnDraw
窗口重繪時會發送一個WM_PAINT消息:消息響應函數OnPaint().
CView類派生自CWnd類。
OnPaint()是CWnd的類成員,同時負責響應WM_PAINT消息。
OnDraw()是CVIEW的成員函數,并且沒有響應消息的功能。這就是為什么你用VC成的程序代碼時,在視圖類只有 OnDraw沒有OnPaint的原因。要想在屏幕上繪圖或顯示圖形,首先需要建立設備環境DC。其實DC是一個數據結構,它包含輸出設備的繪圖屬性的描述。MFC提供了CPaintDC類和CWindwoDC類來實時的響應,而CPaintDC支持重畫。
當視圖變得無效時(包括大小的改變,移動,被遮蓋等等),Windows 將 WM_PAINT 消息發送給它。該視圖的 OnPaint 處理函數通過創建 CPaintDC 類的DC對象來響應該消息并調用視圖的 OnDraw 成員函數。通常我們不必編寫重寫的 OnPaint 處理成員函數。
//CView默認的標準的重畫函數
void CView::OnPaint()
{
CPaintDC dc(this);
OnPreparDC(&dc);
OnDraw(&dc); //調用了OnDraw
}
既然OnPaint最后也要調用OnDraw,因此我們一般會在OnDraw函數中進行繪制。下面是一個典型的程序
///視圖中的繪圖代碼首先檢索指向文檔的指針,然后通過DC進行繪圖調用。
void CMyView::OnDraw( CDC* pDC )
{
CMyDoc* pDoc = GetDocument();
CString s = pDoc->GetData(); // Returns a CString
CRect rect;
GetClientRect( &rect );
pDC->SetTextAlign( TA_BASELINE | TA_CENTER );
pDC->TextOut( rect.right / 2, rect.bottom / 2, s, s.GetLength() );
}
設備環境(Device Context)(設備上下文)
設備上下文DC是一個Windows數據結構,它包含了某個設備的繪制屬性。通常,繪制調用都是借助于上下文對象,而這些設備上下文對象封裝了用于畫線、形狀、文本等的Windows API。設備上下文是設備無關的,所以它既可以用于繪制屏幕,也可以用于繪制打印機甚至元文件。設備上下文在內存中創建,而內存經常受到擾動,所以它的地址是不固定的。因此,一個設備上下文句柄不是直接指向設備上下文對象,而是指向另外一個跟蹤設備上下文地址的指針。
我個人認為設備上下文相當于畫圖過程中的畫布(畫紙),在VC中,這個畫布可以是顯示器,也可以使打印機,設備上下文決定了畫布的屬性,而且封裝了在畫布上畫畫的方法,比如畫線,畫點,等等,例如: pDc->LineTo(512,0); //從左下角到右上角的一條紅色直線 。我們在VC中畫圖時,首先要得到這塊畫布才可以畫畫,所以要進行獲取設備環境。
常見設備上下文及區別:
CClientDC,CPaintDC,CWindowDC
CClientDC:(客戶區設備上下文)用于客戶區的輸出,與特定窗口關聯,可以讓開發者訪問目標窗口中客戶區,其構造函數中包含了GetDC,析構函數中包含了ReleaseDC。只能在客戶區繪制圖形。
CPaintDC:只能在客戶區繪制圖形。
(1)CPaintDC類是CDC類的一個派生類,該類一般用在響應WM_PAINT消息的函數OnPaint()中。
(2)WM_PAINT消息是當窗口的某個區域需要重畫時激發的窗口消息。當程序中的消息循環接到WM_PAINT消息時就自動調用消息處理函數OnPaint(),如果在OnPaint函數內定義了CPaintDC類的對象,通過這個類對象就可以使用CDC類的成員函數完成視圖客戶區中的圖形繪制操作。
(3)CPaintDC用于響應窗口重繪消息(WM_PAINT)時的繪圖輸出。CPaintDC在構造函數中調用BeginPaint()取得設備上下文,在析構函數中調用EndPaint()釋放設備上下文。EndPaint()除了釋放設備上下文外,還負責從消息隊列中清除WM_PAINT消息。因此,在處理窗口重畫時,必須使用CPaintDC,否則WM_PAINT消息無法從消息隊列中清除,將引起不斷的窗口重畫。CPaintDC也只能用在WM_PAINT消息處理之中。CWindowsDC:
(1)可在非客戶區繪制圖形,而CClientDC,CPaintDC只能在窗口的客戶區繪制圖形。
(2)坐標原點是在窗口的左上角,CClientDC,CPaintDC下坐標原點是在客戶區的左上角。
CDC:GetDC,ReleaseDC
CClientDC:GetDC,ReleaseDC封裝起來,只能訪問客戶區
CWindowDC:GetDC,ReleaseDC封裝起來,不僅僅可以訪問客戶區
CPaintDC:窗口重繪時會發送一個WM_PAINT消息:消息響應函數OnPaint,調用CPaintDC
下面介紹一下獲得這塊畫布的方法,即獲取設備上下文的方法:
1、通過OnDraw()函數獲得CPaintDC:在OnDraw()函數中入口參數CDC *pDC,傳入操作的設備上下文,這個上下文是CPaintDC。
他是通過OnPaint()構建,并傳入OnDraw(),View類如果沒有重載OnPaint(),則窗口刷新時自動調用MFC底層代碼的OnPaint()函數,
從而調用OnDraw()。我們就可以通過OnDraw()在客戶區進行初始化的繪制。
2、通過CClientDC,CPaintDC,CWindowDC定義一個DC。
例如:CClientDC dc(this);創建一個dc,
在當前對象的客戶區。創建一個CWindowDC類的對象:CWindowDC dc(this);
3、通過HDC GetDC(HWND hWnd);hWnd:設備上下文環境被檢索的窗口的句柄,如果該值為NULL,
GetDC則檢索整個屏幕的設備上下文環境,返回值是hdc,
即一個DC描述符,入口參數是一個窗口類型的句柄。
例如: pWnd=GetDlgItem(IDC_STATIC_PIC); //IDC_STATIC_PIC是對話框圖片空間的一個標識號
pWnd->SetWindowPos(NULL,0,0,512,120,SWP_NOZORDER|SWP_NOMOVE); //調整長寬為(512,120)
pDc=pWnd->GetDC();
GDI及GDI函數
GDI對象就是繪畫時用的工具,比如畫筆,畫刷,字體,位圖,調色板。
如果繪圖的時候,需要先把相應的GDI設備選入設備環境,就是為畫圖選個畫筆,工具。
注意MFC中,GDI和CDC是兩個獨立的類
- 窗口滾動功能的實現
OnInitialUpdate
視圖窗口完全建立后第一個被框架調用的函數。框架在第一次調用OnDraw前會調用OnInitialUpdate,因此OnInitialUpdate是設置滾動視圖的邏輯尺寸和映射模式的最合適的地方。
OnCreate()后窗口產生, 然后才是視圖的OnInitialUpDate,一般在這里對視圖的顯示做初始化。
一、OnCreate和OnInitialUpDate
OnCreate()只是產生VIEW的基本結構和變量.OnCreate()不產生窗口,只是在窗口顯示前設置窗口的屬性如風格位置等。create負責注冊并產生窗口。
OnInitialUpDate()中,主要初始化視圖中控件等。對各個變量進行初始化操作。OnCreate()是生成結構的
OnInitialUpDate()是對結構進行初始化。
兩個一個相當于硬件一個相當于軟件,功能和作用完全不同。OnCreate
oncreate 消息響應函數,是用來“表示一個窗口正在生成”。
在CWnd::Create中,又會調用OnCreate函數,但是實際上這個時候Create函數還沒有退出,CWnd的某些部分還沒有創建好。create()不是對應于消息wm_create的,oncreate()才是。
create()只用于產生窗口,像動態創建控件中的create()一樣。設備坐標(0,0)點始終位于窗口客戶區的左上角。
兩種保存圖形和重繪圖形的方式:元文件和兼容設備描述表
元文件
元文件設備上下文類:CMetaFileDC
元文件并沒有包含所繪圖形的圖形數據,它包含的是圖形的繪制命令。