轉載地址:http://www.cnblogs.com/wb-DarkHorse/archive/2013/07/08/3178201.html
一:關於座標
MFC中繪圖時經常涉及到座標計算,GetWindowRect和GetClientRect這兩個函數,是獲取邏輯座標系中窗口或控件(其實也是窗口)大小和座標的常用函數了,有什麼不一樣的?
先說說什麼叫邏輯座標?講到邏輯座標,它相對的一個概念是設備座標,是爲了屏蔽掉不同設備屬性差別而設置的抽象座標系,說白了,就是獨立於設備座標的統一接口,程序員不需要去在具體的設備上進行繪圖操作,而只需要在虛擬的環境下進行繪圖,就是CDC。
然後由設備驅動去負責虛擬座標到實際設備座標之間的轉換。通常邏輯座標與設備座標之間有不同的映射轉換關係,缺省模式下的映射方式是MM_TEXT,這種方式下的邏輯座標的方向和單位與設備座標的相同,也是以像素爲單位來表示,X軸向右爲正,Y軸向下爲正,座標原點位於窗口的左上角
然後再說上面的兩個函數之間的差別:
GetWindowRect得到的是相對於當前界面的整個窗口左上角的座標,比如一個對話框程序,那就是相對於對話框左上角的座標,從左往右是X方向,從上往下是Y方向。
注意:這個函數的相對座標原點分兩種情況:
1 窗口還沒有初始化完成時:原點是整個窗口的左上角
2 初始化完成後,原點是設備屏幕左上角
GetClientRect得到的是相對於窗口客戶區左上角的座標。
二:驗證
下面通過一段代碼來理解:
新建一個MFC對話框程序,在Dialog資源中,把一個靜態框加入進來。OnInitDialog中添加如下代碼:
BOOL CmfcdialogtestDlg::OnInitDialog() { /*.............其它代碼.............*/ /*****************for testing***************/ CRect wndRect1; CRect wndRect2; /****首先看對話框的******/ this->GetWindowRect(&wndRect1); //PrintRect("Dialog:GetWindowRect", wndRectScreen1); this->ScreenToClient(&wndRect1); //PrintRect("Dialog:ScreenToClient", wndRectClient1); this->GetClientRect(&wndRect2); //PrintRect("Dialog:GetClientRect", wndRectClient2); this->ClientToScreen(&wndRect2); //PrintRect("Dialog:ClientToScreen", wndRectScreen2); /****再看控件的**********/ CRect ctrlRect1; CRect ctrlRect2; CStatic *pCtrl = (CStatic*)GetDlgItem(IDC_STC_TEST); pCtrl->GetClientRect(&ctrlRect1); //PrintRect("static:GetClientRect", ctrlRectClient1); pCtrl->ClientToScreen(&ctrlRect1); //PrintRect("static:ClientToScreen", ctrlRectScreen1); pCtrl->GetWindowRect(&ctrlRect2); //PrintRect("static:GetWindowRect", ctrlRectScreen2); pCtrl->ScreenToClient(&ctrlRect2); //PrintRect("static:ScreenToClient", ctrlRectClient2); /*****************ending********************/ /*.............其它代碼.............*/ }
三:分析
我們分別觀察對整個對話框和靜態控件,分別調用這兩個函數的效果。首先看看對話框的:
(1)對話框部分的程序運行結果:
對話框: GetWindowRect: + &wndRect1 0x0017f410 {top=0 bottom=378 left=0 right=566} CRect * ScreenToClient:+ &wndRect1 0x0017f410 {top=-25 bottom=353 left=-3 right=563} CRect * GetClientRect: + &wndRect2 0x0017f3f8 {top=0 bottom=350 left=0 right=560} CRect * ClientToScreen:+ &wndRect2 0x0017f3f8 {top=25 bottom=375 left=3 right=563} CRect *
我們給出一份圖片分析:
第一個GetWindowRect得到的是整個窗口相對於窗口左上角的座標,實際上就是這個對話框的大小。
然後ScreenToClient,注意了,我們發現top和left都變成了負值?爲什麼呢,因爲這個時候的轉換是基於Client的原點進行的,即客戶區的左上角。因爲原來的窗口左上角位於Client原點的左上方,所以是負值。
第二個GetClientRect得到的是客戶區的大小,因爲不包含窗口周邊的藍色區域,所以比第一個的窗口大小要小。
然後ClientToScreen,這個就很好解釋了,計算相對於窗口左上角的座標。你可以自己動手算一下。
(2)控件的程序運行結果:
控件: GetClientRect: + &ctrlRect1 0x0017f3e0 {top=0 bottom=170 left=0 right=285} CRect * ClientToScreen: + &ctrlRect1 0x0017f3e0 {top=127 bottom=297 left=73 right=358} CRect * GetWindowRect: + &ctrlRect2 0x0017f3c8 {top=127 bottom=297 left=73 right=358} CRect * ScreenToClient: + &ctrlRect2 0x0017f3c8 {top=0 bottom=170 left=0 right=285} CRect *
還是圖片分析:
同理,第一個GetClientRect得到是控件的大小。
然後ClientToScreen,可以看到這個時候,控件相對於對話框窗口左上角的位移是(127,73)。
第二個GetWindowRect,得到的值與上面的值相同,這個很好理解了,他們的含義是一樣的,就是控件在窗口中的座標。
然後ScreenToClient,得到的值與第一個GetClientRect的值一樣。不多說了
爲什麼對話框和控件的轉換之間略有差別(兩次轉換結果不太一樣),主要是對話框包含了非客戶區,使得相對座標不一致。