逻辑坐标和设备坐标的区别(一)

2014-11-24 03:11:25 · 作者: · 浏览: 0
如果我们想制作一个拥有滚动条的应用程序,那就只需要让你的view类派生自CScrollView类即可,CScrollView类派生自CView类!
  在初始化view的时候,函数会调用CXXView类的OnInitialUpdate()函数(XX表示你的工程名)!函数如下:
  
void CMyScrollView::OnInitialUpdate()
{
  CScrollView::OnInitialUpdate();
  
  CSize sizeTotal;
  // TODO: calculate the total size of this view
  //sizeTotal.cx = sizeTotal.cy = 100;
  SetScrollSizes(MM_TEXT, CSize(500, 400));
}

  这里面可以设置view的大小!比如我这里设置的是500*400大小。


  每次窗口最大化,最小化什么的,都会发出WM_PAINT消息,这个消息由OnPaint函数处理!假如你的CXXView类里没有写OnPaint函数的话,程序会调用父类的OnPaint函数,即CScrollView::OnPaint.来看看这个函数里写了一些什么!当然,然后我发现,CScrollView类里也没有写OnPaint函数,自然就调用他的父类的OnPaint函数,即CView::OnPaint()。
  
void CView::OnPaint()
{
  // standard paint routine
  CPaintDC dc(this);
  OnPrepareDC(&dc);
  OnDraw(&dc);
}

  我们再看一看OnPrepareDC这个函数干了一些什么!当然由于CScrollView改写了OnPrareDC这个函数,所以执行CScrollView::OnPrepareDC().

        void CScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  {

  	if (m_nMapMode == MM_NONE)
  	{
  		TRACE0("Error: must call SetScrollSizes() or SetScaleToFitSize()");
  		TRACE0("\tbefore painting scroll view.\n");
  		ASSERT(FALSE);
  		return;
  	}
  	switch (m_nMapMode)
  	{
  	case MM_SCALETOFIT:
  		pDC->SetMapMode(MM_ANISOTROPIC);
  		pDC->SetWindowExt(m_totalLog);  // window is in logical coordinates
  		pDC->SetViewportExt(m_totalDev);
  		break;
  
  	default:
  		ASSERT(m_nMapMode > 0);
  		pDC->SetMapMode(m_nMapMode);
  		break;
  	}
  
  	CPoint ptVpOrg(0, 0);      //设置一个点
  	if (!pDC->IsPrinting())      //如果没有打印的话
  	{
  		
  		ptVpOrg = -GetDeviceScrollPosition();//这个函数用来接收当前窗口的设备坐标
  
  		if (m_bCenter)
  
  		{
  			CRect rect;
  			GetClientRect(&rect);
  
  			// if client area is larger than total device size,
  			// override scroll positions to place origin such that
  			// output is centered in the window
  			if (m_totalDev.cx < rect.Width())
  				ptVpOrg.x = (rect.Width() - m_totalDev.cx) / 2;
  			if (m_totalDev.cy < rect.Height())
  				ptVpOrg.y = (rect.Height() - m_totalDev.cy) / 2;
  		}
  	}
  	pDC->SetViewportOrg(ptVpOrg);//设置视口原点,所谓视口原点,你可以理解为绘画的原点,当然这个原点是以逻辑坐标为准的!
  
  	CView::OnPrepareDC(pDC, pInfo);
  }

  这个函数执行完了以后,会执行CXXView的OnDraw函数,重绘窗口!

关于什么是逻辑坐标,以及什么是设备坐标,请看下面两张图:

\

再看一张图:

\

需要注意的是:我们点击窗口时返回的是设备坐标,看一个小小的示例:

我写了一个鼠标左键点击后的消息处理函数:

void CMyScrollView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
		
	CString pos;
	pos.Format("Position(%d, %d)", point.x, point.y);
	MessageBox(pos);
	//CPoint org = GetDeviceScrollPosition(); 
	CScrollView::OnLButtonDown(nFlags, point);
}
处理很简单,就是输出传入的坐标点的值!看一看运行结果:

我没有移动滚动条:

\

我移动了滚动条,结果又如下:

vczWo6zO0sPHz8jU2kNYWFZpZXfA4MDvw+a808nPwb249kNQb2ludLHkwb8s0ru49r3Q1/ZtX3B0T3K8x8K8xvC146Os0ru49r3Q1/ZtX3B0RGW8x8K81tW146OhztLDx9KqtNPG8LXjtb3W1bXju+bWxtK7zPXWsc/fo6E8L3N0cm9uZz48L3A+CjxwPjxzdHJvbmc+ICAgILWxyLujrM7S1eLWu8rHvPK7r7DmtcTKvsD9stnX96OhPC9zdHJvbmc+PC9wPgo8cD48c3Ryb25nPiAgICDK87Hq1/O8/LC0z8LKsaOs1rTQ0KO6PC9zdHJvbmc+PC9wPgo8cD48c3Ryb25nPjwvc3Ryb25nPjwvcD4KPHByZSBjbGFzcz0="brush:java;">void CMyScrollView::OnLButtonDown(UINT nFlags, CPoint point) { /*CString pos; *pos.Format("Position(%d, %d)", point.x, point.y); *MessageBox(pos); */ //现在来绘制一个点! CClientDC dc(this); m_ptOr = point; //现在将这个点的坐标记录下来,待会儿再重绘回来! dc.SetPixel(point, RGB(255, 0, 0)); CScrollView::OnLButtonDown(nFlags, point); }
鼠标左键弹起时,我们执行:

void CMyScrollView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	m_ptDe = point;  //先将终点坐标记录下来!
	CClie