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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/420841.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端学习(1127):递归求数学题2

斐波那契数列 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head>…

1008 数组元素循环右移问题 (20分)

输入样例: 6 2 1 2 3 4 5 6 输出样例: 5 6 1 2 3 4 # -*- coding: utf-8 -*- import mathdef right_shift(lst, m):n len(lst)m m % nfor j in range(math.gcd(m, n)):temp lst[j]i jwhile (i - m) % n > j:lst[i] lst[(i - m) % n]i (i - m) % nlst[i] tempretur…

MVC分层开发模式

MVC 1. 什么是mvc开发模式2. 基于servlet手写mvc框架1. 什么是mvc开发模式 mvc不是一种技术&#xff0c;只是一种开发模式使用分层开发模式能在大型项目中&#xff0c;让开发人员更好的协同工作便于项目的维护和扩展 M: Model 模型层->数据库层->daoV: View 视图层->…

C#_uploadify_mvc_version

jQuery Uploadify在ASP.NET MVC3中的使用 1、Uploadify简介 Uploadify是基于jQuery的一种上传插件&#xff0c;支持多文件、带进度条显示上传&#xff0c;在项目开发中常被使用。 Uploadify官方网址&#xff1a;http://www.uploadify.com/ 2、ASP.NET MVC3中的使用Uploadify 搭…

1010 一元多项式求导 (25分)

输入样例: 3 4 -5 2 6 1 -2 0 输出样例: 12 3 -10 1 6 0 # -*- coding: utf-8 -*-def get_derivation(lst):length len(lst)idx 0while idx < length:if lst[idx 1] ! 0:lst[idx] * lst[idx 1]lst[idx 1] - 1else:lst[idx] 0idx 2return lstif __name__ __main__…

VS2012 发布网站步骤

VS2012中发布网站的方式与以往有了不同&#xff0c;前面的版本发布如图 而2012点publish的时候弹出框有所不同&#xff0c;这边需要新建一个profile名字随便起&#xff0c;发布的方式有好几种&#xff0c; 当然不同的方式配置不同&#xff0c;用的最多的就是files system了 选择…

python 生成个性二维码

1. 效果 gif 图片二维码 带背景图二维码&#xff08;修改了&#xff09; 2. 依赖库 核心库myqr pip install myqr其它依赖库安装pip install pip install pillow, numpy, imageio3. 核心代码 我这里是F盘下的joy文件夹下面代码改变路径&#xff0c;图片名称参数即可 im…

1011 A+B 和 C (15分)

输入样例&#xff1a; 4 1 2 3 2 3 4 2147483647 0 2147483646 0 -2147483648 -2147483647 输出样例&#xff1a; Case #1: false Case #2: true Case #3: true Case #4: false # -*- coding: utf-8 -*-if __name__ __main__:n eval(input())input_list []for i in range…

SharePoint 2013:解决添加域名后每次都需要登录的问题

在SharePoint 2013中&#xff0c;当我们添加一个域名给SP后&#xff08;添加域名的方法请参考此文&#xff1a;http://www.cnblogs.com/jianyus/archive/2013/08/10/3249461.html &#xff09;&#xff0c;每次用域名访问都需要输入用户名和密码&#xff0c;即使该用户已经正确…

1012 数字分类 (20分)

输入样例 1&#xff1a; 13 1 2 3 4 5 6 7 8 9 10 20 16 18 输出样例 1&#xff1a; 30 11 2 9.7 9 输入样例 2&#xff1a; 8 1 2 4 5 6 7 9 16 输出样例 2&#xff1a; N 11 2 N 9 # -*- coding: utf-8 -*-def class_numbers(nums):arr [0] * 5exists [0] * 5flag1 1…

mvc框架upgrade

upgrade...1. actionservlet核心控制器更改以上1&#xff0c;2点2. 工具类&#xff08;对反射拿到的属性对象数据转型&#xff09;3. 业务服务类使用适配器设计模式针对上一篇文字做出了改造&#xff0c;既然要写手写lowb版mvc框架&#xff0c;就得付出一定代价&#xff0c;加大…

1013 数素数 (20分)

输入样例&#xff1a; 5 27 输出样例&#xff1a; 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 # -*- encoding: utf-8 -*- import mathdef get_primes(n):prime_list [1] * (n 1)for i in range(2, int(math.sqrt(n)) 1):if prime_list[i]…

1014 福尔摩斯的约会 (20分)

输入样例&#xff1a; 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm 输出样例&#xff1a; THU 14:04 # -*- coding: utf-8 -*- import stringweek {A: MON,B: TUE,C: WED,D: THU,E: FRI,F: SAT,G: SUN}hour {0:00, 1:01, 2:02, 3:03, 4:04, 5:05, 6:0…

MSSQL如何在没有主键的表中删除重复数据

MSSQL如何在没有主键的表中删除重复数据 原文:MSSQL如何在没有主键的表中删除重复数据为了对重复数据进行实验&#xff0c;下面建一个设计不太好&#xff08;没有主键&#xff09;表并插入了一些重复数据&#xff1a; create database testdbuse testdb ; go create table Dups…

1015 德才论 (25分)

输入样例&#xff1a; 14 60 80 10000001 64 90 10000002 90 60 10000011 85 80 10000003 85 80 10000004 80 85 10000005 82 77 10000006 83 76 10000007 90 78 10000008 75 79 10000009 59 90 10000010 88 45 10000012 80 100 10000013 90 99 10000014 66 60 输出样例&#…

1016 部分A+B (15分)

输入样例 1&#xff1a; 3862767 6 13530293 3 输出样例 1&#xff1a; 399 输入样例 2&#xff1a; 3862767 1 13530293 8 输出样例 2&#xff1a; 0 # -*- coding: utf-8 -*-if __name__ __main__:input_list input().split()a, d_a, b, d_b input_list[0], input_li…

马哥学习笔记二十七——IO复用

I/O动作模式  阻塞 非阻塞 I/O复用 信号驱动 异步 转载于:https://www.cnblogs.com/wangyongbin/p/3817353.html

1017 A除以B (20分)

输入样例&#xff1a; 123456789050987654321 7 输出样例&#xff1a; 17636684150141093474 3 # -*- coding: utf-8 -*- import redef big_division(a, b):q_list, r [], 0len_a len(a)for i in range(0, len_a):dividend 10 * r eval(a[i])q_list.append(dividend // …