逻辑坐标和设备坐标的区别

来源:互联网 发布:mysql h localhost 编辑:程序博客网 时间:2024/05/16 07:17

转自:http://blog.csdn.net/lishuhuakai/article/details/18362349


如果我们想制作一个拥有滚动条的应用程序,那就只需要让你的view类派生自CScrollView类即可,CScrollView类派生自CView类!
  在初始化view的时候,函数会调用CXXView类的OnInitialUpdate()函数(XX表示你的工程名)!函数如下:
  

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void CMyScrollView::OnInitialUpdate()  
  2. {  
  3.   CScrollView::OnInitialUpdate();  
  4.     
  5.   CSize sizeTotal;  
  6.   // TODO: calculate the total size of this view  
  7.   //sizeTotal.cx = sizeTotal.cy = 100;  
  8.   SetScrollSizes(MM_TEXT, CSize(500, 400));  
  9. }  

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


  每次窗口最大化,最小化什么的,都会发出WM_PAINT消息,这个消息由OnPaint函数处理!假如你的CXXView类里没有写OnPaint函数的话,程序会调用父类的OnPaint函数,即CScrollView::OnPaint.来看看这个函数里写了一些什么!当然,然后我发现,CScrollView类里也没有写OnPaint函数,自然就调用他的父类的OnPaint函数,即CView::OnPaint()。
  
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void CView::OnPaint()  
  2. {  
  3.   // standard paint routine  
  4.   CPaintDC dc(this);  
  5.   OnPrepareDC(&dc);  
  6.   OnDraw(&dc);  
  7. }  

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

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1.       void CScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)  
  2. {  
  3.   
  4.     if (m_nMapMode == MM_NONE)  
  5.     {  
  6.         TRACE0("Error: must call SetScrollSizes() or SetScaleToFitSize()");  
  7.         TRACE0("\tbefore painting scroll view.\n");  
  8.         ASSERT(FALSE);  
  9.         return;  
  10.     }  
  11.     switch (m_nMapMode)  
  12.     {  
  13.     case MM_SCALETOFIT:  
  14.         pDC->SetMapMode(MM_ANISOTROPIC);  
  15.         pDC->SetWindowExt(m_totalLog);  // window is in logical coordinates  
  16.         pDC->SetViewportExt(m_totalDev);  
  17.         break;  
  18.   
  19.     default:  
  20.         ASSERT(m_nMapMode > 0);  
  21.         pDC->SetMapMode(m_nMapMode);  
  22.         break;  
  23.     }  
  24.   
  25.     CPoint ptVpOrg(0, 0);      //设置一个点  
  26.     if (!pDC->IsPrinting())      //如果没有打印的话  
  27.     {  
  28.           
  29.         ptVpOrg = -GetDeviceScrollPosition();//这个函数用来接收当前窗口的设备坐标  
  30.   
  31.         if (m_bCenter)  
  32.   
  33.         {  
  34.             CRect rect;  
  35.             GetClientRect(&rect);  
  36.   
  37.             // if client area is larger than total device size,  
  38.             // override scroll positions to place origin such that  
  39.             // output is centered in the window  
  40.             if (m_totalDev.cx < rect.Width())  
  41.                 ptVpOrg.x = (rect.Width() - m_totalDev.cx) / 2;  
  42.             if (m_totalDev.cy < rect.Height())  
  43.                 ptVpOrg.y = (rect.Height() - m_totalDev.cy) / 2;  
  44.         }  
  45.     }  
  46.     pDC->SetViewportOrg(ptVpOrg);//设置视口原点,所谓视口原点,你可以理解为绘画的原点,当然这个原点是以逻辑坐标为准的!  
  47.   
  48.     CView::OnPrepareDC(pDC, pInfo);  
  49. }  

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

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


   再看一张图:


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

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

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void CMyScrollView::OnLButtonDown(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.           
  5.     CString pos;  
  6.     pos.Format("Position(%d, %d)", point.x, point.y);  
  7.     MessageBox(pos);  
  8.     //CPoint org = GetDeviceScrollPosition();   
  9.     CScrollView::OnLButtonDown(nFlags, point);  
  10. }  
   处理很简单,就是输出传入的坐标点的值!看一看运行结果:

   我没有移动滚动条:


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


    这就很明显了,我们在窗口点击鼠标左键的时候,得到的是设备坐标!

    我们现在更近一步地探讨,我们先在CXXView类里面加上两个CPoint变量,一个叫做m_ptOr记录起点,一个叫做m_ptDe记录终点!我们要从起点到终点绘制一条直线!

    当然,我这只是简化版的示例操作!

    鼠标左键按下时,执行:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void CMyScrollView::OnLButtonDown(UINT nFlags, CPoint point)   
  2. {  
  3.           
  4.     /*CString pos; 
  5.     *pos.Format("Position(%d, %d)", point.x, point.y); 
  6.     *MessageBox(pos); 
  7.     */  
  8.     //现在来绘制一个点!  
  9.     CClientDC dc(this);  
  10.     m_ptOr = point; //现在将这个点的坐标记录下来,待会儿再重绘回来!  
  11.     dc.SetPixel(point, RGB(255, 0, 0));  
  12.       
  13.     CScrollView::OnLButtonDown(nFlags, point);  
  14. }  

    鼠标左键弹起时,我们执行:

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void CMyScrollView::OnLButtonUp(UINT nFlags, CPoint point)   
  2. {  
  3.     // TODO: Add your message handler code here and/or call default  
  4.     m_ptDe = point;  //先将终点坐标记录下来!  
  5.     CClientDC dc(this);  
  6.     //然后绘制一条线!  
  7.     dc.MoveTo(m_ptOr);  
  8.     dc.LineTo(m_ptDe);  
  9.     CScrollView::OnLButtonUp(nFlags, point);  
  10. }  

   然后窗口重绘时,我们仍然画出这条直线!

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void CMyScrollView::OnDraw(CDC* pDC)  
  2. {  
  3.     CScrollDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     // TODO: add draw code for native data here  
  6.     pDC->MoveTo(m_ptOr);//画一条线  
  7.     pDC->LineTo(m_ptDe);  
  8. }  

      看一下执行结果:

   先将滚动条拉下来,在下方绘制一条直线!


    然后切换一下窗口!结果很有趣!

   

    看见没有,直线移上去了,我来解释解释这种现象!不过在这之前,先吃一个饭,然后再来说明吧!

            当我们切换窗口时,程序发出WM_PAINT消息,这个消息由CXXView::OnPaint()函数处理!具体看文件前面的说明!调用顺序如下:

    CView::OnPaint() -> CScrollView::OnPrePareDC() -> CXXView::OnDraw()

    在CScrollView::OnPrePareDC()中:


   所谓视口原点,也可以说是设备坐标系的原点!   

   然后执行OnDraw函数:


         怎么处理?

   利用函数CDC的函数DPtiLP将设备坐标变换成逻辑坐标即可!只需要更改OnLButtonDown和OnLButtonUp两个函数即可!

   

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. void CMyScrollView::OnLButtonDown(UINT nFlags, CPoint point)   
  2. {  
  3.   
  4.     //现在来绘制一个点!  
  5.     CClientDC dc(this);  
  6.     OnPrepareDC(&dc);  
  7.     dc.DPtoLP(&point);  
  8.     m_ptOr = point; //现在将这个点的坐标记录下来,待会儿再重绘回来!  
  9.     //dc.SetPixel(point, RGB(255, 0, 0));  
  10.       
  11.     CScrollView::OnLButtonDown(nFlags, point);  
  12. }  
  13.   
  14. void CMyScrollView::OnLButtonUp(UINT nFlags, CPoint point)   
  15. {  
  16.       
  17.     CClientDC dc(this);  
  18.     OnPrepareDC(&dc);  
  19.     dc.DPtoLP(&point);  
  20.     m_ptDe = point;  //先将终点坐标记录下来!  
  21.     //然后绘制一条线!  
  22.     dc.MoveTo(m_ptOr);  
  23.     dc.LineTo(m_ptDe);  
  24.     CScrollView::OnLButtonUp(nFlags, point);  

0 0
原创粉丝点击