如果我们想制作一个拥有滚动条的应用程序,那就只需要让你的view类派生自CScrollView类即可,CScrollView类派生自CView类!
在初始化view的时候,函数会调用CXXView类的OnInitialUpdate()函数(XX表示你的工程名)!函数如下:
- void CMyScrollView::OnInitialUpdate()
- {
- CScrollView::OnInitialUpdate();
-
- CSize sizeTotal;
-
-
- 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()
- {
-
- 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);
- 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 (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)
- {
-
-
- CString pos;
- pos.Format("Position(%d, %d)", point.x, point.y);
- MessageBox(pos);
-
- CScrollView::OnLButtonDown(nFlags, point);
- }
处理很简单,就是输出传入的坐标点的值!看一看运行结果:
我没有移动滚动条:
我移动了滚动条,结果又如下:
这就很明显了,我们在窗口点击鼠标左键的时候,得到的是设备坐标!
我们现在更近一步地探讨,我们先在CXXView类里面加上两个CPoint变量,一个叫做m_ptOr记录起点,一个叫做m_ptDe记录终点!我们要从起点到终点绘制一条直线!
当然,我这只是简化版的示例操作!
鼠标左键按下时,执行:
- void CMyScrollView::OnLButtonDown(UINT nFlags, CPoint point)
- {
-
-
-
-
-
-
- CClientDC dc(this);
- m_ptOr = point;
- dc.SetPixel(point, RGB(255, 0, 0));
-
- CScrollView::OnLButtonDown(nFlags, point);
- }
鼠标左键弹起时,我们执行:
- void CMyScrollView::OnLButtonUp(UINT nFlags, CPoint point)
- {
-
- m_ptDe = point;
- CClientDC dc(this);
-
- dc.MoveTo(m_ptOr);
- dc.LineTo(m_ptDe);
- CScrollView::OnLButtonUp(nFlags, point);
- }
然后窗口重绘时,我们仍然画出这条直线!
- void CMyScrollView::OnDraw(CDC* pDC)
- {
- CScrollDoc* pDoc = GetDocument();
- ASSERT_VALID(pDoc);
-
- pDC->MoveTo(m_ptOr);
- pDC->LineTo(m_ptDe);
- }
看一下执行结果:
先将滚动条拉下来,在下方绘制一条直线!
然后切换一下窗口!结果很有趣!
看见没有,直线移上去了,我来解释解释这种现象!不过在这之前,先吃一个饭,然后再来说明吧!
当我们切换窗口时,程序发出WM_PAINT消息,这个消息由CXXView::OnPaint()函数处理!具体看文件前面的说明!调用顺序如下:
CView::OnPaint() -> CScrollView::OnPrePareDC() -> CXXView::OnDraw()
在CScrollView::OnPrePareDC()中:
所谓视口原点,也可以说是设备坐标系的原点!
然后执行OnDraw函数:
怎么处理?
利用函数CDC的函数DPtiLP将设备坐标变换成逻辑坐标即可!只需要更改OnLButtonDown和OnLButtonUp两个函数即可!
- void CMyScrollView::OnLButtonDown(UINT nFlags, CPoint point)
- {
-
-
- CClientDC dc(this);
- OnPrepareDC(&dc);
- dc.DPtoLP(&point);
- m_ptOr = point;
-
-
- CScrollView::OnLButtonDown(nFlags, point);
- }
-
- void CMyScrollView::OnLButtonUp(UINT nFlags, CPoint point)
- {
-
- CClientDC dc(this);
- OnPrepareDC(&dc);
- dc.DPtoLP(&point);
- m_ptDe = point;
-
- dc.MoveTo(m_ptOr);
- dc.LineTo(m_ptDe);
- CScrollView::OnLButtonUp(nFlags, point);
- }
本文转载自:
http://blog.csdn.net/lishuhuakai/article/details/18362349