MFC中存在两个坐标系,一个是屏幕坐标系,以显示器左上角为原点,另一个是窗口坐标系,以MFC包含边界的客户端的左上角为原点,我们在涉及MFC坐标操作时常常对获取的坐标是哪个坐标系下的坐标感到非常困扰,于是这篇博客将详细解析MFC中的各种坐标以及其转换关系,希望能有帮助。
我们先来分析一个鼠标点击事件的响应函数:
void CWtvView::OnLButtonDown(UINT nFlags, CPoint point)
{
//====================== Point的转换 ======================//
//客户区的点
CPoint pt = point;
CPoint pt1 = point;
CPoint pt2 = point;
CPoint pt3 = point;
//这组语句把点pt从客户区转换成屏幕坐标系下的坐标;
//再从屏幕坐标系映射回客户区坐标系,结果是:pt == point
ClientToScreen(&pt);
GetDesktopWindow()->MapWindowPoints(this,&pt,1);
//下面两组语句得到的结果一样 pt1 == pt2;
//把pt1转换到屏幕坐标系下;
ClientToScreen(&pt1);
//把pt2映射到窗口坐标系下,再从窗口坐标系转换到屏幕坐标系;
MapWindowPoints(GetParentFrame(),&pt2,1);
GetParentFrame()->ClientToScreen(&pt2);
GetCursorPos(&pt3); //得到鼠标在屏幕坐标系中的坐标;
ScreenToClient(&pt3); //转换到客户区;
//下边这两句等效;
GetParentFrame()->ScreenToClient(&pt); //转换到窗口坐标系下;
MapWindowPoints(GetParentFrame(), &pt3, 1); //转换到窗口坐标系下;
//====================== Rect的转换 =======================//
CRect rect00, rect01, rect0, rect1, rect2, rect3;
GetWindowRect(&rect00); // 窗口在屏幕坐标系下的 rect;
GetClientRect(&rect01); // 窗口在客户区坐标系下的 rect;
GetWindowRect(&rect0);
ScreenToClient(&rect0); // 窗口在屏幕坐标系下的rect 映射到窗口工作区(客户区)坐标系下;
GetClientRect(&rect1); // 客户区(工作区)rect;
MapWindowPoints(GetParentFrame(), &rect1); //把客户区(工作区)rect 映射到窗口坐标系下;
GetWindowRect(&rect2);
GetParentFrame()->ScreenToClient(&rect2);//窗口在屏幕坐标系下的rect转换成自己客户区(这个客户区包含非工作区和客户区)下的rect
GetParentFrame()->GetClientRect(&rect3);//窗口在自己客户区(这个客户区包含非工作区和客户区)坐标系下的rect
}
鼠标点击获取的坐标是客户区的坐标
- GetWindowRect获取的是窗口在屏幕坐标系下的坐标
- GetClientRect获取的是窗口在客户坐标系下坐标
- ScreenToClient将屏幕坐标系坐标转化为客户坐标系下坐标
- ClientToScreen将客户坐标系坐标转化为屏幕坐标系下坐标
- MoveWindow接受客户区坐标,来改变窗口或控件大小
对于窗口和空间可能由所不同,具体的,我们再来看几个例子:
固定窗口大小
void CRVAFGUIDlg::OnSize(UINT nType, int cx, int cy)
{
CDialogEx::OnSize(nType, cx, cy);
// TODO: Add your message handler code here
CRect rc;
GetWindowRect(rc);
rc.right = 393;
rc.left = 0;
rc.bottom = 697;
rc.top = 0;
ScreenToClient(rc);
MoveWindow(rc);
}
点击按钮改变窗口大小
void CRVAFGUIDlg::OnShowMoreClicked()
{
// TODO: Add your control notification handler code here
CRect rc;
GetWindowRect(rc);
if (rc.right - rc.left == 393){
rc.right += 200;
} else{
rc.right -= 200;
}
MoveWindow(rc);
}
改变控件大小
pWnd = GetDlgItem(IDC_BTN_LABEL1); pWnd->GetWindowRect(&rect1); ScreenToClient(&rect1); rect1.top -= 300; rect1.bottom -= 300; pWnd->MoveWindow(&rect1, 1);