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的区别详解,布布扣,bubuko.com

时间: 2024-11-08 22:22:21

GetWindowRect和GetClientRect的区别详解的相关文章

【转】escape()、encodeURI()、encodeURIComponent()区别详解

escape().encodeURI().encodeURIComponent()区别详解 原文链接:http://www.cnblogs.com/tylerdonet/p/3483836.html JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decodeURIComponent . 下面简单介绍一下它们的区别 1 escape()函数 定义和用法 e

cookie 和session 的区别详解 《转》

二者的定义: 当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文字或是一些选择, 都纪录下来.当下次你再光临同一个网站,WEB 服务器会先看看有没有它上次留下的 Cookie 资料,有的话,就会依据 Cookie 里的内容来判断使用者,送出特定的网页内容给你. Cookie 的使用很普遍,许多有提供个人化服务的网站,都是利用 Cookie 来辨认使用者,以方便送出使用者量身定做的内容,像是 Web 接口的免费 email 网站,都要用到 C

escape()、encodeURI()、encodeURIComponent()区别详解

JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decodeURIComponent . 下面简单介绍一下它们的区别 1 escape()函数 定义和用法 escape() 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串. 语法 escape(string) 参数  描述  string  必需.要被转义或编码的字符串. 返回值 已编码的

【转】Cookie和Session的区别详解

转载地址:http://www.phperzone.cn/portal.php?aid=541&mod=view 一.cookie机制和session机制的区别 具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案. 同时我们也看到,由于才服务器端保持状态的方案在客户端也需要保存一个标识,所以session 机制可能需要借助于cookie机制来达到保存标识的目的,但实际上还有其他选择 二.会话cookie和持久cookie的区别 如果不设置

Bind和Eval的区别详解

原文:Bind和Eval的区别详解 1.简单描述Eval和Bind的区别 绑定表达式 <%# Eval("字段名") %> <%# Bind("字段名") %> 区别 1.eval是只读数据,bind是可更新的. 2.当对次表达式操作时候,必须用Eval 如<%# Eval("字段名").ToString().Trim() %> 2.若GridView中绑定列里面 设置 内容格式 DataFormateStri

PHP中include和require的区别详解

1.概要  require()语句的性能与include()相类似,都是包括并运行指定文件.不同之处在于:对include()语句来说,在执行文件时每次都要进行读取和评估:而对于require()来说,文件只处理一次(实际上,文件内容替换require()语句).这就意味着如果可能执行多次的代码,则使用require()效率比较高.另外一方面,如果每次执行代码时是读取不同的文件,或者有通过一组文件迭代的循环,就使用include()语句. require的使用方法如:require("myfil

jQuery height()、innerHeight()、outerHeight()函数的区别详解

jQuery height().innerHeight().outerHeight()函数的区别详解 在jQuery中,获取元素高度的函数有3个,它们分别是height(). innerHeight().outerHeight(). 与此相对应的是,获取元素宽度的函数也有3个,它们分别是width(). innerWidth().outerWidth(). 在这里,我们以height().innerHeight().outerHeight()3个函数为例,来详细介绍它们之间的区别. 下面我们以元

GetWindowRect与GetClientRect 的区别[转]

GetWindowRect 函数功能:该函数返回指定窗口的边框矩形的尺寸.该尺寸以相对于屏幕坐标左上角的屏幕坐标给出. 函数原型:BOOL GetWindowRect(HWND hWnd,LPRECTlpRect): 在Visual Studio 2005中,函数原型为void GetWindowRect(LPRECT lpRect) const; 是属于CWnd类的函数. 参数: hWnd:窗口句柄. lpRect:指向一个RECT结构的指针,该结构接收窗口的左上角和右下角的屏幕坐标. 返回值

jsp中的@include与jsp:include区别详解

1 前言 搞java开发的人也许都知道在jsp中引入项目中其他文件有如下两种方式 <%@include file="xxx.jsp"%> <jsp:include page="xxx.jsp"></jsp:include> 我们也许会使用这两种方式,但是也许很多人不名称这两种方式的区别.下面我们来看看下面的两个例子 2 开门见山引出问题 (1) /include/include.jsp <%@ page language=&