要用到两个函数:
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
分享到:
相关推荐
设备坐标和逻辑坐标是两个相关的概念。设备坐标直接关联到特定设备的物理像素,而逻辑坐标是一种与设备无关的坐标系统,通常用于在不同分辨率的设备之间保持图形比例的一致性。GDI提供映射模式(如MM_TEXT)来转换...
在Windows编程中,尤其是在使用Microsoft Visual C++(VC)进行开发时,理解设备坐标和逻辑坐标对于创建自定义的用户界面至关重要。本篇文章将深入探讨“状态条中显示鼠标的设备坐标与逻辑坐标”的概念及其在VC矢量...
在MFC中,`CDC`(设备上下文)类提供了用于设备坐标和逻辑坐标转换的方法。`DPtoLP`函数用于将设备坐标转换为逻辑坐标,而`LPtoDP`则执行相反的操作。在绘制图形或处理鼠标事件时,这些转换非常重要,因为输入和绘图...
在VC++环境中,我们经常需要处理逻辑坐标系(World Coordinate System)和设备坐标系(Device Coordinate System)之间的转换,以便正确地在屏幕上绘制图形。这篇教程将深入探讨如何在VC++中建立坐标系并实现这两种...
本资源为Qt绘图基础,世界坐标系转换为逻辑坐标系。世界坐标系原点在视图左上角,本例子通过世界坐标转换,将坐标原点定位在视图中央,Y轴向上,X轴向右,并绘制坐标轴,基于逻辑坐标系下的绘图,可将转换关系函数...
WINDOWS操作系统中,存在多种坐标系,包括逻辑坐标系、设备坐标系、屏幕坐标系、窗口坐标系和客户区坐标系。这五种坐标系之间存在着紧密的关系,了解它们之间的关系对编程和图形输出非常重要。 1. 逻辑坐标系 逻辑...
设备坐标、客户坐标和逻辑坐标的区别和应用 在 Windows 编程中,坐标系是一个非常重要的概念,设备坐标、客户坐标和逻辑坐标是三个相关的概念,它们之间的区别和应用非常重要。 逻辑坐标(LP)是一种独立于设备的...
可在窗体的状态栏内显示设备坐标和逻辑坐标的X/Y信息,变量ID_SEPARATOR用来显示设备坐标系下的鼠标位置,ID_SEPARATOR用来显示逻辑坐标系下的鼠标位置。return m_bkBrush; 作为约定,返回背景色对应的刷子句柄。
在非滚动窗口或滚动窗口处于特定位置时(垂直滚动条位于最上端,水平滚动条位于最左端),逻辑坐标和设备坐标可能一致。一旦窗口滚动,这种一致性就会被打破。 #### 二、坐标转换 在VC开发中,经常需要处理鼠标...
映射模式是Windows GDI(Graphics Device Interface)中处理逻辑坐标和设备坐标转换的方式。常见的映射模式有MM_TEXT、MM_LOMETRIC、MM_HIMETRIC等。例如,MM_TEXT模式将逻辑坐标直接映射到像素,而MM_LOMETRIC和MM_...
在Windows图形设备接口(GDI)中,逻辑坐标和设备坐标是两个重要的概念。逻辑坐标是程序员在编写代码时使用的坐标系统,而设备坐标则是实际显示在屏幕上的坐标系统。理解这两者的区别和相互作用是进行图形绘制的关键...
它们分别对应于编程中的抽象坐标和物理设备上的像素坐标,通过`Graphics`类提供的转换方法,我们可以实现两者的无缝对接,从而在屏幕上精确地绘制出我们所需的图形。在实际项目开发中,熟练掌握这些知识将使你的程序...
下面是一个简单的示例,展示了如何在MFC中使用逻辑坐标和映射模式绘制图形: ```cpp void CMyView::OnDraw(CDC* pDC) { // 设置映射模式为MM_ISOTROPIC pDC->SetMapMode(MM_ISOTROPIC); // 定义逻辑坐标范围 ...
逻辑坐标与设备坐标 viewport 视口 窗口 GDI 坐标 映射方式定义了Windows如何将GDI函数中指定的逻辑坐标映射为设备坐标。 Windows有关映射模式的一些术语:逻辑坐标所在的坐标系称为"窗口",将设备坐标所在的坐标...
本文将深入探讨TeeChart屏幕坐标到实际坐标的转换,这对于理解和操作TeeChart图形控件至关重要。 TeeChart是一个跨平台的图表组件,支持多种编程语言,如Delphi, C++, .NET等,其功能强大,可以创建出专业级别的...
在GDI中,存在设备坐标和逻辑坐标两种坐标系统。设备坐标是相对于特定设备的,如屏幕的像素坐标,而逻辑坐标是设备无关的,可以通过映射模式进行转换。 7. OpenGL绘图实验 虽然本课件主要关注GDI,但提到了OpenGL,...
在GDI中,坐标系统分为设备坐标和逻辑坐标。设备坐标直接对应于设备的物理单位,如像素,而逻辑坐标则独立于设备,方便在不同分辨率的设备间进行一致的绘图。通过`SetMapMode`函数可以设置映射模式,从而转换这两种...
在VC中,坐标转换主要涉及到设备坐标系(Device Coordinate System, DCS)与逻辑坐标系(Logical Coordinate System, LCS)之间的转换。设备坐标系是基于屏幕物理像素的坐标系统,而逻辑坐标系则是开发者自定义的一套...
在编程领域,尤其是在图形用户界面(GUI)的设计与开发中,获取用户区坐标和屏幕坐标是常见的需求。易语言作为一款中国本土的编程语言,以其简单易学的特点深受初学者和开发者喜爱。本文将深入探讨易语言中如何实现...