MFC坐标转换详解

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  
}

鼠标点击获取的坐标是客户区的坐标

  1. GetWindowRect获取的是窗口在屏幕坐标系下的坐标
  2. GetClientRect获取的是窗口在客户坐标系下坐标
  3. ScreenToClient将屏幕坐标系坐标转化为客户坐标系下坐标
  4. ClientToScreen将客户坐标系坐标转化为屏幕坐标系下坐标
  5. 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);

 

 

发表评论