友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
一世书城 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

深入浅出MFC第2版(PDF格式)-第162章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




                  IMPLEMENT_DYNCREATE(CScribbleView; CScrollView) 



                  BEGIN_MESSAGE_MAP(CScribbleView; CScrollView) 

                      。。。 

                  END_MESSAGE_MAP() 



                  3 改写OnInitialUpdate,在其中设定滚动条范围。这个函数的被调用时机是在View 第 



                   一次附着到Document 但尚未显现时,由Framework 调用之。它会调用OnUpdate,不 



                   带任何Hint 参数(于是lHint 是0 而pHint  是NULL )。如果你需要做任何「只做一 



                   次」的初始化动作,而且初始化时需要Document  的资料,那么在这里做就最合适了: 



                  // in SCRIBVW。CPP 

                  void CScribbleView::OnInitialUpdate() 

                  { 

                      SetScrollSizes(MM_TEXT; GetDocument()…》GetDocSize()); 

                      //这是CScrollView 的成员函数。 

                  } 



                    SetScrollSizes 总共有四个参数: 



                    int nMapMode :代表映射模式(Mapping Mode) 



                    SIZE sizeTotal:代表文件大小 



                    const SIZE& sizePage :代表一页大小(预设是文件大小的1/10) 



                    const SIZE& sizeLine :代表一行大小(预设是文件大小的1/100) 



                  本例的文件大小是固定的。另一种比较复杂的情况是可变大小,那么你就必须在文件大 



                  小改变之后立刻调用SetScrollSizes 。 



                  窗口上增加滚动条并不会使View  的OnDraw 负担加重。我们并不因为滚动条把观察镜头移 



                  动到Document  的中段或尾段,而就必须在OnDraw 中重新计算绘图原点与平移向量, 



                  原因是绘图坐标与我们所使用的DC 有关。当滚动条移动了DC 原点,CScrollView  自动 



644 


…………………………………………………………Page 707……………………………………………………………

                                  第 11 章    View 功能之加強與重繪效率之提昇 



会做调整,让资料的某一部份显示而某一部份隐藏。 



让我做更详细的说明。「GDI 原点」是DC         (注)的重要特征,许许多多CDC 成员函 



式的绘图结果都会受它的影响。如果我们想在绘图之前(也就是进入OnDraw 之前)调 



整DC  , 我们可以改写虚拟函数OnPrepareDC , 因为Framework 是先调用 



OnPrepareDC,然后才调用OnDraw 并把DC 传进去。好,窗口由无滚动条到增设滚动条的 



过程中,之所以不必修改OnDraw 函数内容,就是因为CScrollView  已经改写了CView 



的OnPrepareDC 虚拟函数。Framework 先调用CScrollView::OnPrepareDC 再调用 



CScribbleView::OnDraw,所有因为滚动条而必须做的特别处理都已经在进入OnDraw 之前 



完成了。 



注意上面的叙述,别把CScrollView 和CSribbleView 混淆了。下图是个整理。 



                        CWnd 

                         CWnd 



                        CView 

                         CView 



                    x    CScrollView  此类别的OnPrepareDC 虚拟函数 

                          CScrollView 

                                      会因滚动条的位置而调整DC 原点。 



                  CScribbleView 此类别原针对「无滚动条窗口」而设计,;所以Step4 之前 

                   CScribbleView 



                                的View 类别是直接衍生自CView。彼时所写的OnDraw 



                                函数内容在如今改变了继承关系后(改继承自 



                                CScrollView),依然完全适用,原因是所有的差异性早 



                                都在进入OnDraw 之前便由更早被Framework 调用的 



                                CScrollView::OnPrepare 处理掉了。 



 DC 就是Device Context ,在Windows  中凡绘图动作之前一定要先获得一个DC ,它可 



  能代表屏幕,也可能代表一个窗口,或一块内存,或打印机。。。。DC  中有许多绘图所需 



  的元素,包括坐标系统(映射模式)、原点、绘图工具(笔、刷、颜色。。。)等等。它还 



 连接到低阶的输出装置驱动程序。由于DC ,我们在程序中对屏幕作画和对打印机作画 



  的动作才有可能完全相同。 



                                                                   645 


…………………………………………………………Page 708……………………………………………………………

                   第篇    深入  MFC  程式設計 



                   4 修正鼠标坐标。虽说OnDraw 不必因为坐标原点的变化而有任何改变,但是幕后出 



                   力的CScrollView::OnPrepareDC 却不知道什么是Windows 消息!这话看似牛头和马 



                   嘴,但我一点你就明白了。CScrollView::OnPrepareDC 虽然能够因着滚动条行为而改变GDI 



                   原点,但「改变GDI 原点」这个动作却不会影响你所接收的WM_LBUTTONDOWN 或 



                   WM_LBUTTONUP  或WM_MOUSEMOVE  的坐标值,原因是Windows 消息并非DC  的 



                   一个成份。因此,我们作画的基础,也就是鼠标移动产生的轨迹点坐标,必须由「以视 



                   窗绘图区左上角为原点」的窗口坐标系统,改变为「以文件左上角为原点」的逻辑坐标 



                   系统。文件中储存的,也应该是逻辑坐标。 



                   下面是修改坐标的程序动作。其中调用的OnPrepareDC 是哪一个类别的成员函数?想 



                   想看,CScribbleView 衍生自CScrollView,而我们并未在CScribbleView 中改写此一函 



                   式,所以程序中调用的是CScrollView::OnPrepareDC。 



                   // in SCRIBVW。CPP 

                   void CScribbleView::OnLButtonDown(UINT; CPoint point) 

                   { 

                           //由于CScrollView 改变了DC 原点和映射模式,所以我们必须先把 

                           //装置坐标转换为逻辑坐标,再储存到Document 中。 

                           CClientDC dc(this); 

                           OnPrepareDC(&dc); 

                           dc。DPtoLP(&point); 



                           m_pStrokeCur = GetDocument()…》NewStroke(); 

                           m_pStrokeCur…》m_pointArray。Add(point); 



                           SetCapture();       // 抓住鼠标 

                           m_ptPrev = point;   //做为直线绘图的第一个点 



                           return; 

                   } 

                   void CScribbleView::OnLButtonUp(UINT; CPoint point) 

                   { 

                           。。。 

                           if (GetCapture() != this) 

                                   return; 



                           CScribbleDoc* pDoc = GetDocument(); 



                           CClientDC dc(this); 



646 


…………………………………………………………Page 709……………………………………………………………

                                              第 11 章    View 功能之加強與重繪效率之提昇 



        OnPrepareDC(&dc);  // 设定映射模式和DC 原点 

        dc。DPtoLP(&point); 

        。。。 

 } 

void CScribbleView::OnMouseMove(UINT; CPoint point) 

 { 

        。。。 

        if (GetCapture() != this) 

                return; 



        CClientDC dc(this); 

        OnPrepareDC(&dc); 

        dc。DPtoLP(&point); 



        m_pStrokeCur…》m_pointArray。Add(point); 

        。。。 

 } 



除了上面三个函数,还有什么函数牵扯到坐标?是的,线条四周有一个外围四方形,那 



将在OnUpdate 中出现,也必须做坐标系统转换: 



void CScribbleView::OnUpdate(CView* /* pSender */; LPARAM /* lHint */; 

        CObject* pHint) 

 { 

    if (pHint != NULL) 

    { 

        if  (pHint…》IsKindOf(RUNTIME_CLASS(CStroke))) 

        { 

            // hint 的确是一个CStroke 对象。现在将其外围四方形设为重绘区 

            CStroke* pStroke =  (CStroke*)pHint; 

            CClientDC dc(this); 

            OnPrepareDC(&dc); 

            CRect rectInvalid = pStroke…》GetBoundingRect(); 

            dc。LPtoDP(&rectInvalid); 

            InvalidateRect(&rectInvalid); 

            return; 

        } 

    } 

    //无法识别hint;只好假设整个画面都需重绘。 

    Invalidate(TRUE); 

    return; 

 } 



                                                                                           647 


…………………………………………………………Page 710……………………………………………………………

                   第篇    深入  MFC  程式設計 



                   注意,上面的LPtoDP 所受参数竟然不是CPoint*,而是CRect*,那是因为LPtoDP 有 



                   多载函数(overloaded function ),既可接受点,也可接受四方形。DPtoLP  也有类似的多 



                   载能力。 



                   线
返回目录 上一页 下一页 回到顶部 0 1
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!