DPtoLP/LPtoDP 和 ScreenToClient/ClientToScreen
設備坐標(Device?Coordinate)又稱為物理坐標(Physical?Coordinate),是指輸出設備上的坐標。通常將屏幕上的設備坐標稱為屏幕坐標。設備坐標用對象距離窗口左上角的水平距離和垂直距離來指定對象的位置,是以像素為單位來表示的,設備坐標的X軸向右為正,Y軸向下為正,坐標原點位于窗口的左上角。
邏輯坐標(Logical?Coordinate)是系統用作記錄的坐標。在缺省的模式(MM_TEXT)下,邏輯坐標的方向和單位與設備坐標的方向和單位相同,也是以像素為單位來表示的,X軸向右為正,Y軸向下為正,坐標原點位于窗口的左上角。邏輯坐標和設備坐標即使在缺省模式下其數值也未必一致,除了在以下兩種情況下:
1.?窗口為非滾動窗口
2.?窗口為滾動窗口,但垂直滾動條位于滾動邊框的最上端,水平滾動條位于最左端,但如果移動了滾動條這兩種坐標就不一致了。
在VC中鼠標坐標的坐標位置用設備坐標表示,但所有GDI繪圖都用邏坐標表示,所以用鼠標繪圖時,那么必須將設備坐標轉換為邏輯坐標,可以使用CDC?函數DPtoLP()將設備坐標轉化為邏輯坐標,同樣可以用LPtoDP()將邏輯坐標轉化為設備坐標。
ScreenToClient和ClientToScreen實際上是轉換一個參照物的概念,如ie客戶區上一個button,相對于ie的坐標是(x,?y),ie客戶區相對于屏幕原點的坐標是(x0?,?y0),那么button的screen坐標就是(x+x0,?y+y0) 。ScreenToClient和ClientToScreen都假定坐標是設備坐標。
在EX05C中(EX05C是一個例子程序,只需看函數中的代碼即可):
我們現在來看看邏輯坐標和物理坐標是怎么轉換的。
void CEX05CView::OnInitialUpdate()
{
?????? CScrollView::OnInitialUpdate();
?
?????? // TODO: calculate the total size of this view
?????? CSize sizeTotal(800, 1050);
?????? CSize sizePage(sizeTotal.cx/2, sizeTotal.cy/2);
?????? CSize sizeLine(sizeTotal.cx/50, sizeTotal.cy/50);
?????? SetScrollSizes(MM_LOENGLISH, sizeTotal, sizePage, sizeLine);
}
上面程序中的SetScrollSizes(MM_LOENGLISH, sizeTotal, sizePage, sizeLine);制定了映射模式為
MM_LOENGLISH,整個客戶端邏輯區域為800 x 1050邏輯單位(sizeTotal);橫向翻頁的大小為400邏輯單位,縱向翻頁的大小為525邏輯單位(sizePage); 橫向一列的大小為800 / 50 = 16邏輯單位,縱向一行的大小為1050 / 50 = 21邏輯單位。
在MM_LOENGLISH映射模式下,每邏輯單位是0.01英寸。
void CEX05CView::OnLButtonDown(UINT nFlags, CPoint point)
{
?????? // TODO: Add your message handler code here and/or call default
?????? CRect rectEllipse(m_pointTopLeft, m_sizeEllipse);
?????? CRgn circle;
?
?????? CClientDC dc(this);
?????? OnPrepareDC(&dc);
//???? TRACE("Check Point3: HORZSIZE = %d, VERTSIZE = %d/n",dc.GetDeviceCaps(HORZSIZE), dc.GetDeviceCaps(VERTSIZE));
//???? HORZSIZE = 320mm, VERTSIZE = 240mm
?????? TRACE("/nBefore LPtoDP:/n");
?????? TRACE("rectEllipse.top = %d, rectEllipse.bottom = %d, rectEllipse.left = %d, rectEllipse.right = %d/n",
????????????? rectEllipse.top, rectEllipse.bottom, rectEllipse.left, rectEllipse.right);
?????? dc.LPtoDP(rectEllipse);
?????? TRACE("/nAfter LPtoDP:/n");
?????? TRACE("rectEllipse.top = %d, rectEllipse.bottom = %d, rectEllipse.left = %d, rectEllipse.right = %d/n",
????????????? rectEllipse.top, rectEllipse.bottom, rectEllipse.left, rectEllipse.right);
//???? LPtoDP將rectEllipse從邏輯坐標轉換成設備坐標
?????? circle.CreateEllipticRgnIndirect(rectEllipse);
//???? TRACE("Check Point2: point = (%d, %d)/n", point.x, point.y);
//? point為物理設備坐標
?????? if(circle.PtInRegion(point))
?????? {
????????????? SetCapture();
//??????????? Causes all subsequent mouse input to be sent to the current CWnd object regardless of the
//??????????? position of the cursor.
????????????? m_bCaptured = TRUE;
????????????? CPoint pointTopLeft(m_pointTopLeft);
????????????? dc.LPtoDP(&pointTopLeft);
????????????? m_sizeOffset = point - pointTopLeft;
//??????????? m_sizeOffset, point, pointTopLeft皆為設備坐標
????????????? ::SetCursor(::LoadCursor(NULL, IDC_CROSS));
?????? }
?????? CScrollView::OnLButtonDown(nFlags, point);
}
我們來看看rectEllipse在語句dc.LPtoDP(rectEllipse);前后的變化:
Before LPtoDP:
EX05C: rectEllipse.top = -219, rectEllipse.bottom = -319, rectEllipse.left = 199, rectEllipse.right = 299
After LPtoDP:
EX05C: rectEllipse.top = 178, rectEllipse.bottom = 259, rectEllipse.left = 162, rectEllipse.right = 243
?
-219(邏輯坐標)是怎樣轉換為178(設備坐標)的呢?
設備坐標:屏幕的左上方為(0, 0),屏幕的右邊為x坐標的正方向,屏幕的下邊為y軸的正方向。
邏輯坐標:屏幕的左上方為(0, 0),右邊為x坐標的正方向,對于不同的映射模式,y軸的正方向是不一樣的,對
于MM_LOENGLISH而言,向上的方向是正方向,向下的方向是負方向。
在MM_LOENGLISH映射模式下,219個邏輯單位的長度為:
219 * 0.01 = 2.19英寸 = 2.19 * 2.54 = 5.5626 厘米
在上面程序中的CheckPoint3中,我們可以得到屏幕的物理尺寸為:320毫米 x 240毫米,另外補充說明一下,本電腦的屏幕分辨率是1024 * 768。因此,
(5.5626 / 24) * 768 = 178.0032像數
以上就是-219(邏輯坐標)轉換為178(設備坐標)的詳解。其他幾個坐標也是如此轉換而來。
?
現在我們看看卷動右邊的滾動條的情況下,坐標是怎樣變化的。
先將滾動條往下滾動兩行,然后隨便將橢圓拖放到一個位置,如下圖所示:
?
?
TRACE語句的輸出結果為:
Before LPtoDP:
EX05C: rectEllipse.top = -469, rectEllipse.bottom = -569, rectEllipse.left = 801, rectEllipse.right = 901
After LPtoDP:
EX05C: rectEllipse.top = 347, rectEllipse.bottom = 428, rectEllipse.left = 651, rectEllipse.right = 732
?
邏輯坐標-469是怎樣轉換成設備坐標347的呢?
在不考慮卷動的情況下,邏輯坐標-469應該轉換成的設備坐標為:
(469 * 0.01 * 2.54 / 24) * 768 = 381.2032像數 = 381像數。
由于在垂直方向向下滾動了兩行即 (1050 / 50) * 2 = 42邏輯單位,轉換成設備坐標為:
(42 * 0.0.1 * 2.54 / 24) * 768 = 34.1736像數 = 34像數。
因此,考慮到卷動了2行的情況,邏輯坐標-469轉換成設備坐標應該是:
381 - 34 = 347像數
這就是在有卷動的情況下,邏輯坐標和設備坐標轉換的詳細說明。
轉載于:https://www.cnblogs.com/duyy/p/3796965.html
總結
以上是生活随笔為你收集整理的DPtoLP/LPtoDP 和 ScreenToClient/ClientToScreen的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ajax:如何运用updatepanle
- 下一篇: 手把手教你可复用的SSO组件设计(设计篇