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);