VC++(十一)圖形的保存和重繪

  • 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
    元文件并沒有包含所繪圖形的圖形數據,它包含的是圖形的繪制命令。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,836評論 18 139
  • Windows 95中文輸入法編輯器(IME) 微軟 翻譯:TBsoft Software Studio ...
    returntrue閱讀 2,712評論 0 3
  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作為繪圖引擎。它提供了低...
    ShanJiJi閱讀 1,565評論 0 20
  • 5.20 正如我用卑微的姿態祈求的,結果也以卑微的姿態呈現在我面前。 只是想讓室友們幫忙分享一下我寫的東西,可笑的...
    十八歲的花邊閱讀 341評論 0 0
  • 我的孩子今年五年級了,但他的書寫總是不那么美觀。每次寫作業,我都告訴他,認真書寫。他總是時好時壞。 ...
    向小雅閱讀 742評論 0 3