標籤:style blog http color strong os
一:關於座標
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的值一樣。不多說了
為什麼對話方塊和控制項的轉換之間略有差別(兩次轉換結果不太一樣),主要是對話方塊包含了非客戶區,使得相對座標不一致。
四:小結
算是把這個小問題給弄清楚了,適合和我一樣的新手學習。網上太多資料,很多都是錯的,還是自己動手,豐衣足食~!有錯誤,請指正!
可以看看這篇博文:http://www.cnblogs.com/flying-roc/articles/1970298.html