GetClientRect , GetWindowRect ,ClientToScreen和ScreenToClient的疑问

来源:互联网 发布:vb6.0下载mac版 编辑:程序博客网 时间:2024/05/20 06:23

GetClientRect , GetWindowRect ,ClientToScreen和ScreenToClient的疑问
作者:邵盛松 2009-10-09
按照如下步骤编写程序。
建立一个对话框控件,添加两个控件,一个Edit Control和 一个Button。ID分别为IDC_EDIT_TEST,IDC_BUTTON_TEST。
为按钮添加如下事件
void CRectTestDlg::OnBnClickedButtonTest()
{
 // TODO: 在此添加控件通知处理程序代码
 CRect rectClient;
 m_Edit_ctlTest.GetClientRect(&rectClient);
 CString strClientCoordinate;
 strClientCoordinate.Format(_T("top=%d,left=%d,right=%d,bottom=%d"),rectClient.top,rectClient.left,rectClient.right,rectClient.bottom);
 AfxMessageBox(strClientCoordinate);
 m_Edit_ctlTest.ClientToScreen(rectClient);//转换为屏幕坐标
 CString strChangeClientCoodinate;
 strChangeClientCoodinate.Format(_T("top=%d,left=%d,right=%d,bottom=%d"),rectClient.top,rectClient.left,rectClient.right,rectClient.bottom);
 AfxMessageBox(strChangeClientCoodinate);
 m_Edit_ctlTest.MoveWindow(rectClient,TRUE);
  
 CRect rectScreen;
 m_Edit_ctlTest.GetWindowRect(&rectScreen);
 CString strScreenCoordinate;
 strScreenCoordinate.Format(_T("top=%d,left=%d,right=%d,bottom=%d"),rectScreen.top,rectScreen.left,rectScreen.right,rectScreen.bottom);
 AfxMessageBox(strScreenCoordinate);
 m_Edit_ctlTest.ScreenToClient(rectScreen);//转换为客户区坐标
 CString strChangeScreenCoodinate;
 strChangeScreenCoodinate.Format(_T("top=%d,left=%d,right=%d,bottom=%d"),rectScreen.top,rectScreen.left,rectScreen.right,rectScreen.bottom);
 AfxMessageBox(strChangeScreenCoodinate);
 m_Edit_ctlTest.MoveWindow(rectScreen,TRUE);


}

运行结果
第一次
0,0,74,40
323,399,473,363

321,397,475,365
-2,-2,76,42
第二次
在对话框中移动Edit Control之后,编译生成exe,再次运行
结果如下
0,0,74,40
300,454,528,340

298,452,530,342
-2,-2,76,42

每次用GetClientRect函数,无论控件相对于窗体的位置是否发生改变还是屏幕的分辨率发生改变,客户区坐标不变,也就是它的左上角坐标永远是0,0。另外两个获取的值分别表示控件的宽度74,高度40.

问题:
ClientToScreen把客户区坐标系下的RECT坐标转换为屏幕坐标系下的RECT坐标.
ScreenToClient把屏幕坐标系下的RECT坐标转换为客户区坐标系下的RECT坐标.
经过转换之后两个坐标不相等,但坐标之间是有规律的,每一个方位之间相差2个单位。

更改一种获取坐标的写法
GetDlgItem(IDC_EDIT_TEST)->GetClientRect(&rectClient);
GetDlgItem(IDC_EDIT_TEST)->GetWindowRect(&rectScreen);
坐标还是没有改变

重新编写按钮事件
CRect rectClient;
 GetDlgItem(IDC_EDIT_TEST)->GetClientRect(&rectClient);
 CString strClientCoordinate;
 strClientCoordinate.Format(_T("top=%d,left=%d,right=%d,bottom=%d"),rectClient.top,rectClient.left,rectClient.right,rectClient.bottom);
 AfxMessageBox(strClientCoordinate);
 m_Edit_ctlTest.ClientToScreen(rectClient);//转换为屏幕坐标
 CString strChangeClientCoodinate;
 strChangeClientCoodinate.Format(_T("top=%d,left=%d,right=%d,bottom=%d"),rectClient.top,rectClient.left,rectClient.right,rectClient.bottom);
 AfxMessageBox(strChangeClientCoodinate);
 m_Edit_ctlTest.ScreenToClient(rectClient);//转换为客户区坐标
 CString strChangeScreenCoodinate;
 strChangeScreenCoodinate.Format(_T("top=%d,left=%d,right=%d,bottom=%d"),rectClient.top,rectClient.left,rectClient.right,rectClient.bottom);
 AfxMessageBox(strChangeScreenCoodinate);

输出结果是
0,0,74,40
278,394,468,318
0,0,74,40

直接转换与第一次获取的客户区坐标相同。
问题依旧存在
问题是获取客户端区坐标ClientToScreen转换到屏幕坐标与GetWindowRect获取的屏幕坐标不相同。并且相差两个单位。

问题的解决
其实解决这个很简单。原理疏忽了获取的客户区不包括边框。如果想让获取客户端区坐标ClientToScreen转换到屏幕坐标与GetWindowRect获取的屏幕坐标相同。将Edit Control的Border的属性设置为False就可以了。因为是Edit Control的边框占两个像素。