要用到两个函数:
CDC::LPtoDP 将逻辑坐标转换为设备坐标
CDC::DPtoLP 将设备坐标转换为逻辑坐标
设备坐标( 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 像数
这就是在有卷动的情况下,逻辑坐标和设备坐标转换的详细说明。
1. void CEX05CView::OnLButtonDown(UINT nFlags, CPoint point) 中的 point 是设备坐标,而非逻辑坐标。如果要该函数中画图,就一定要将 point 转换成逻辑坐标。
2. InvalidateRect(rectOld, TRUE); 中的 rectOld 是设备坐标,而非逻辑坐标。
3. pDC->Ellipse(CRect(m_pointTopLeft, m_sizeEllipse)); m_pointTopLeft, m_sizeEllipse 皆为逻辑坐标。
画图时,皆用逻辑坐标。 InvalidateRect 时或者判断某点是否位于某个区域之中时皆用设备坐标。
void CEX05CView::OnDraw(CDC* pDC)
{
CEX05CDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CBrush brushHatch(HS_DIAGCROSS, RGB(255, 0, 0));
CPoint point(0, 0);
pDC->LPtoDP(&point);
pDC->SetBrushOrg(point);
pDC->SelectObject(&brushHatch);
TRACE("Check Point1: m_pointTopLeft = %d, m_sizeEllipse = %d/n", m_pointTopLeft, m_sizeEllipse);
// m_pointTopLeft, m_sizeEllipse 皆为逻辑坐标。画图时,皆用逻辑坐标, InvalidateRect 时皆用设备坐标。
pDC->Ellipse(CRect(m_pointTopLeft, m_sizeEllipse));
pDC->SelectStockObject(BLACK_BRUSH);
pDC->Rectangle(CRect(100, -100, 200, -200));
}
没有上面下划线语句的情况下,椭圆中的填充部分,在屏幕卷动时会不正常 ( 右边滚动条不卷动时是正常的 ) :
有上面下划线语句的情况下,不管是否卷动,椭圆中的填充部分都是正常的。如下图:
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ruixj/archive/2010/05/07/5566991.aspx
分享到:
相关推荐
Windows设备坐标与逻辑坐标之间的映射与转换关系
设备对象属性决定着绘图方式,当使用GDI函数绘图时,所绘制的图形和文本的颜色、大小和位置等由设备对象的当前属性决定,应用程序可以使用GDI函数改变设备对象的当前属性。本文档介绍设备对象的一些主要属性和用于...
状态条中显示鼠标的设备坐标与逻辑坐标,用VC矢量绘图的兄弟可以看看!!
本资源为Qt绘图基础,世界坐标系转换为逻辑坐标系。世界坐标系原点在视图左上角,本例子通过世界坐标转换,将坐标原点定位在视图中央,Y轴向上,X轴向右,并绘制坐标轴,基于逻辑坐标系下的绘图,可将转换关系函数...
可在窗体的状态栏内显示设备坐标和逻辑坐标的X/Y信息,变量ID_SEPARATOR用来显示设备坐标系下的鼠标位置,ID_SEPARATOR用来显示逻辑坐标系下的鼠标位置。return m_bkBrush; 作为约定,返回背景色对应的刷子句柄。
WINDOWS_逻辑坐标_设备坐标_屏幕坐标_客户区坐标 讲述各个坐标之间的关系
VC中坐标系的建立_逻辑坐标,物理坐标,设备坐标 是很实用的vc坐标变换。 看了他很容易理解坐标之间的关系
逻辑坐标与设备坐标 viewport 视口 窗口 GDI 坐标 映射方式定义了Windows如何将GDI函数中指定的逻辑坐标映射为设备坐标。 Windows有关映射模式的一些术语:逻辑坐标所在的坐标系称为"窗口",将设备坐标所在的坐标...
设备坐标(DP)、客户坐标(Client)、逻辑坐标(LP)在用法和含义上都有哪些区别呢?通过本教程,你可以迅速理解坐标原理
在客户区画图,根据实际坐标与逻辑坐标间的转换。
Windows 绘图映射模式,对于逻辑坐标系和设备坐标系的转换及其何时设备坐标系的变化,以帮助程序理解的方式说明设备坐标系的在不同模式下不同的情形。
teechart是一种很好、很流行的图形控件。teechart屏幕坐标转换为实际坐标.学习teechart很好的代码。
鼠标坐标 右击 捕获,屏幕坐标,设备坐标,逻辑坐标直接的关联与转换。
VC 6.0 基于MFC的绘图及... //得到设备坐标和逻辑坐标的比例 int xExt,yExt; xExt=winSize.cx*xLogPixPerInch/96; yExt=winSize.cy*yLogPixPerInch/96; //设定视口大小 pDC->SetViewportExt(xExt,yExt);
VC坐标转换和绘制曲线,文件中有坐标转换的源码。
作的逻辑坐标。为了实现更方便的坐标,QPainter还提供了视口(Viewport)和窗口(Window)坐标系,通过QPainter内部的坐标变换矩阵自动转换为绘图设备的物理坐标。视口表示绘图设备的任意一个矩形区域的物理坐标,可以...
绘图设备的物理坐标是基本的坐标系,通过QPainter的平移、旋转等变换可以得到更容易操作的逻辑坐标。为了实现更方便的坐标,QPainter还提供了视口(Viewport)和窗口(Window)坐标系,通过QPainter内部的坐标变换矩阵...
5.3.8 绘图模式 5.4 绘制填充区域 5.4.1 Polygon函数和多边形填充模式 5.4.2 用画刷填充内部 5.5 GDI映射模式 5.5.1 设备坐标和逻辑坐标 5.5.2 设备坐标系统 5.5.3 视口和窗口 5.5.4 使用MMTEXT 5.5.5 度量映射模式 ...
自己写的,参考了一些网友的文章,喜欢的下。
内容索引:VC/C++源码,系统相关,逻辑坐标,鼠标 在状态条中显示鼠标的设备坐标与逻辑坐标,可能不太实用,当初我来了灵感才做出来的,也是在学习VC,希望有用到的朋友下载,开源共享,欢迎指正。你只要窗体中移动鼠标...