GetWindowRect和GetClientRect的区别详解
一:关于坐标
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
GetWindowRect和GetClientRect的区别详解的更多相关文章
- 基于Java的打包jar、war、ear包的作用与区别详解
本篇文章,小编为大家介绍,基于Java的打包jar.war.ear包的作用与区别详解.需要的朋友参考下 以最终客户的角度来看,JAR文件就是一种封装,他们不需要知道jar文件中有多少个.cla ...
- Android中Intent传值与Bundle传值的区别详解
Android中Intent传值与Bundle传值的区别详解 举个例子我现在要从A界面跳转到B界面或者C界面 这样的话 我就需要写2个Intent如果你还要涉及的传值的话 你的Intent就要写两 ...
- php 去除html标记--strip_tags与htmlspecialchars的区别详解
php 去除html标记--strip_tags与htmlspecialchars的区别详解 作者: 字体:[增加 减小] 类型:转载 时间:2013-06-26 本篇文章是对php中去除html ...
- HTTP POST GET 本质区别详解
HTTP POST GET 本质区别详解 一 原理区别 一般在浏览器中输入网址访问资源都是通过GET方式:在FORM提交中,可以通过Method指定提交方式为GET或者POST,默认为GET提交 Ht ...
- javascript中=、==、===区别详解
javascript中=.==.===区别详解今天在项目开发过中发现在一个小问题.在判断n==""结果当n=0时 n==""结果也返回了true.虽然是个小问题 ...
- [转]ESCAPE()、ENCODEURI()、ENCODEURICOMPONENT()区别详解
escape().encodeURI().encodeURIComponent()区别详解 JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encode ...
- phpcms加载系统类与加载应用类之区别详解
<?php 1. 加载系统类方法load_sys_class($classname, $path = ''", $initialize = 1)系统类文件所在的文件路径:/phpcms ...
- Bind和Eval的区别详解
原文:Bind和Eval的区别详解 1.简单描述Eval和Bind的区别 绑定表达式 <%# Eval("字段名") %> <%# Bind("字段名& ...
- 转-HTTP POST GET SOAP本质区别详解
原文链接:HTTP POST GET SOAP本质区别详解 一 原理区别 一般在浏览器中输入网址访问资源都是通过GET方式:在FORM提交中,可以通过Method指定提交方式为GET或者POST,默认 ...
随机推荐
- 浙江大学PAT考试1009~1012(1010上帝是冠军。。)
哎,pat1010即使java书面,只有java书面,还增加了两个点,,.啊,智商捉佳,主要pat有些不给明确的范围.造成遐想空间.. 还是按顺序介绍.. 题目地址:http://pat.zju.ed ...
- java设计模式之九外观模式(Facade)
外观模式是为了解决类与类之家的依赖关系的,像spring一样,可以将类和类之间的关系配置到配置文件中,而外观模式就是将他们的关系放在一个Facade类中,降低了类类之间的耦合度,该模式中没有涉及到接口 ...
- SQL Server中存储过程比直接运行SQL语句慢的原因
原文:SQL Server中存储过程比直接运行SQL语句慢的原因 在很多的资料中都描述说SQLSERVER的存储过程较普通的SQL语句有以下优点: 1. 存储过程只在创造时进行编译即可,以 ...
- Objective-C系列
我的Objective-C系列文章和坚持写博客的感想 做iOS开发有一段时间了,也有自己上线的App产品,也在坚持着发表技术博客总结自己所学的东西.在写博客的时候虽然博文中不免有错别字,但每句话都 ...
- JDK动态代理机制
JDK Proxy OverView jdk的动态代理是基于接口的.必须实现了某一个或多个随意接口才干够被代理.并且仅仅有这些接口中的方法会被代理. 看了一下jdk带的动态代理api,发现没有样例实在 ...
- AutoMapper 创建嵌套对象映射(原创)
之前在做DTO转换时,用到AutoMapper.但DTO的层次太深了,无奈官方没针对嵌套类型提供好的解决方案,于是自己实现了一下: 思路:采用递归和反射很好的避免手工创建嵌套对象的映射. 第一个版本, ...
- 删除Python UserWarning[已解决]
在使用MySQLdb包后,导入测试时发现一个警告. /usr/lib/python2.6/site-packages/setuptools-0.8-py2.6.egg/pkg_resources.py ...
- 间支付系统,DataGridView
我们通常看到很多的学习使用控制数据库和接口连接--DataGridView,在我们的房间,当我们敲开使用第一遍阶段似该控件--MSHFlexGrid,随着学习的深入,发现我们用到的平台越来越人性化了, ...
- Linux Shell脚本入门--awk命令详解
简单使用: awk :对于文件中一行行的独处来执行操作 . awk -F :'{print $1,$4}' :使用‘:’来分割这一行,把这一行的第一第四个域打印出来 . 详细介绍: AWK命令介绍 ...
- svn搭建
原文:svn搭建 二.Subversion的安装与测试 Subversion的配置方式有很多种,同时也可以配置不同的操作系统之上,本文我讲解的是Subversion 1.5.4 for Apache2 ...