友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

深入浅出MFC第2版(PDF格式)-第116部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!




                算,你可得谨慎评估。 



                                 #5 



                            #1 



                         #2             #4 



                               #3 



                  图11…3 在rect。SCB:1 窗口中新增一线条#5 ,那么,只有与虚线四方形 (此 



                         四方形将#5 包起来) 有交集之其它线条, 也就是#1 和#4 , 才 



                         有必要在rectSCB:2 窗口中重画。 



                前面曾说UpdateAllViews 函数的第三个参数必须是CObject 衍生对象之指针。由于本例 



                十分单纯,与其为了Hint 特别再设计一个类别,勿宁在CStroke 中增加一个变量(事 



                实上是一个CRect 对象),用以表示前述之hint  四方形,那么每一条线条就外罩了一 



                个小小的四方壳。但是我们不能把CRect 对象指针直接当做参数来传,因为CRect 并 



                不衍生自CObject。稍后我会说明该怎么做。 



                可以预期的是,日后一定需要一一从每一线条中取出这个「外围四方形」,所以现在先 



                声明并定义一个名为GetBoundingRect 的函数。另外再声明一个FinishStroke  函数,其 



                作用主要是计算这四方形尺寸。稍后我会详细解释这些函数的行为。 



632 


…………………………………………………………Page 695……………………………………………………………

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



// in SCRIBBLEDOC。H 

class CStroke : public CObject 

 { 

 。。。 

public: 

        UINT      m_nPenWidth; 

        CDWordArray m_pointArray; 

        CRect     m_rectBounding; // smallest rect that surrounds all 

                                     // of the points in the stroke 

public: 

        CRect& GetBoundingRect() { return m_rectBounding; } 

        void FinishStroke(); 

 。。。 

 }; 



我想你早已熟悉了Scribble Document 的数据结构。为了应付Step4 的需要,现在每一 



线条必须多一个成员变量,那是一个CRect 对象,如图11…4 所示。 



  CScribble Step4 Document :: 

                             :: 



                               CObList 对象 



                                        CObList 的每个元素都是一个CObject 指针。 



                                        我们令它指向CStroke 对象。CStroke 衍生自 

 文件内含一个COblist 串行                       CObject。 



   CObList  m_strokeList 

    CObList  m_strokeList 



                                                        包围整个线条的 

                                                        “外围四方形” 



          UINT m_nPenWidth                          CArray 对象 

           (代表笔的宽度) 

                                                     (线条可以CPoint 数组表示) 



                 图11…4 CScribbleDoc 对象中的各项资料 



                                                                                        633 


…………………………………………………………Page 696……………………………………………………………

                    第篇    深入  MFC  程式設計 



                    设计观念分析完毕,现在动手吧。我们必须在SCRIBDOC。CPP 中的Document 初始化 



                    动作以及文件读写动作都加入m_rectBounding 这个新成员: 



                    // in SCRIBDOC。CPP 

                    IMPLEMENT_SERIAL(CStroke; CObject; 2)  //  

                                                                   注意schema no。 改变为2 



                    CStroke::CStroke(UINT nPenWidth) 

                     { 

                            m_nPenWidth = nPenWidth; 

                            m_rectBounding。SetRectEmpty(); 

                     } 



                    void CStroke::Serialize(CArchive& ar) 

                     { 

                            if (ar。IsStoring()) 

                            { 

                                    ar  m_rectBounding; 

                                    WORD w; 

                                    ar 》》 w; 

                                    m_nPenWidth = w; 

                                    m_pointArray。Serialize(ar); 

                            } 

                     } 



                    如果我们改变了文件读写的格式,我们就应该改变schema number  (可视为版本号码)。 



                    由于Scribble 资料文件(。SCB)格式改变了,多了一个m_rectBounding ,所以我们在 



                    IMPLEMENT_SERIAL 宏中改变Document  的Schema no。 , 以便让不同版本的 



                    Scribble 程序识得不同版本的文件档。如果你以Scribble Step3 读取Step4 所产生的文 



                    件,会因为Schema 号码的不同而得到这样的消息: 



634 


…………………………………………………………Page 697……………………………………………………………

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



     我们还需要一个函数,用以计算「线条之最小外包四方形」,这件事情当然是在线条完 



     成后进行之,所以此一函数命名为FinishStroke。每当一笔画结束(鼠标左键放开,产生 



     WM_LBUTTONUP ),OnLButtonUp 就调用FinishStroke 让它计算边界。计算方法很直 



     接,取出线条中的坐标点,比大小而已: 



     // in SCRIBDOC。CPP 

     void CStroke::FinishStroke() 

     { 



               计算外围四方形。为了灵巧而高效率的重绘动作,这是必要的。 

            //  

             if  (m_pointArray。GetSize()==0) 

             { 

                     m_rectBounding。SetRectEmpty(); 

                     return; 

             } 

             CPoint pt = m_pointArray'0'; 

             m_rectBounding = CRect(pt。x; pt。y; pt。x; pt。y); 



             for (int i=1; i 《 m_pointArray。GetSize(); i++) 

             { 



                    //  

                       如果点在四方形之外,那么就将四方形膨胀,以包含该点。 

                     pt = m_pointArray'i'; 

                     m_rectBounding。left     = min(m_rectBounding。left; pt。x); 

                     m_rectBounding。right    = max(m_rectBounding。right; pt。x); 

                     m_rectBounding。top      = min(m_rectBounding。top; pt。y); 

                     m_rectBounding。bottom   = max(m_rectBounding。bottom; pt。y); 

             } 



            // 在四方形之外再加上笔的宽度。 

             m_rectBounding。InflateRect(CSize(m_nPenWidth; m_nPenWidth)); 

             return; 

     } 



把hint 传给OnUpdate 



     下一步骤是想办法把hint 交给UpdateAllViews。让我们想想什么时候Scribble 的资料 



     开始产生改变?答案是鼠标左键按下时!或许你会以为要在OnLButtonDown 中调用 



     CDocument::UpdateAllViews。这个猜测的论点可以成立但是结果错误,因为左键按下后还 



                                                                                          635 


…………………………………………………………Page 698……………………………………………………………

                   第篇    深入  MFC  程式設計 



                   有一连串的鼠标轨迹移动,每次移动都导至资料改变,新的点不断被加上去。如果我们 



                   等左键放开,线条完成,再来调用UpdateAllViews,事情会比较单纯。因此Scribble Step4 



                   是在OnButtonUp 中调用UpdateAllViews。当然我们现在就可以预想得到,一笔画完成 



                   之前,同一Document  的其它Views 没有办法实时显示最新资料。 



                   下面是OnButtonUp 的修改内容: 



                   void CScribbleView::OnLButtonUp(UINT; CPoint point) 

                    { 

                           。。。 

                           m_pStrokeCur…》m_pointArray。Add(point); 



                           // 已完成加点的动作,现在可以计算外围四方形了 

                           m_pStrokeCur…》FinishStroke(); 



                           // 通知其它的views,使它们得以修改它们的图形。 

                           pDoc…》UpdateAllViews(this; 0L; m_pStrokeCur); 

                           。。。 

                           return; 

                    } 



                   程序逻辑至为简单,唯一需要说明的是UpdateAllViews 的第三个参数(hint ),原本我 



                   们只需设此参数为m_rectBounding ,即可满足需求,但MFC 规定,第三参数必须是一个 



                   CObject 指针,而CRect 并不衍生自CObject,所以我们干脆就把目前正作用中的整个 



                   线条(也就是m_pStrokeCur )传过去算了。CStroke 的确是衍生自CObject ! 



                   // in SCRIBBLEVIEW。H 

                   class CScribbleView : public CScrollView 

                    { 

                   protected: 

                           CStroke*    m_pStrokeCur;   // the stroke in progress 

                           。。。 

                    }; 



                   // in SCRIBBLEVIEW。CPP 

                   void CScribbleView::OnLButtonDown(UINT; CPoint point) 

                    { 

                           。。。 

                           m_pStrokeCur = GetDocument()…》NewStroke(); 

                           m_pStrokeCur…》m_pointArray。Add(point); 



636 


…………………………………………………………Page 699……………………………………………………………

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



              。。。 

      } 

      void CScribbleView::OnMouseMove(UINT; CPoint point) 

      { 

              。。。 

              m_pStrokeCur…》m_pointArray。Add(point); 

              。。。 

      } 

      void CScribbleView::OnLButtonUp(UINT; CPoint point) 

      { 

              。。。 

              m_pStrokeCur…》m_pointArray。Add(point); 

              m_pStrokeCur…》FinishStroke(); 

              pDoc…》UpdateAllViews(this; 0L; m_pStrokeCur); 

              。。。 

      } 



     UpdateAllViews 会巡访CScribbleDoc 所连接的每一个Views       (始作俑者那个View  除 



     外),调用它们的OnUpdate 函数,并把hint 做为参数之一传递过去。 



利用 hint 增加重绘效率 



     预设情况下,OnUpdate 所收到的无效区(也就是重绘区),是Document Frame 窗口的 



     整个内部。但谁都知道,原已存在而且没有变化的图形再重绘也只是浪费时间而已。上 



     一节你已看到Scribble 每加上一整个线条, 就在OnLButtonUp 函数中调用 



     UpdateAllViews 函数,并且把整个线条(内含其四方边界)传过去,因此我们可以想办法 



     在OnUpdate 中重绘这个四方形小区域就好。 



     话说回来,如何能够只重绘一个小区域就好呢?我们可以一一取出Document  中每一线 



     条的四方边界,与新线条的四方边界比较,若有交点就重绘该线条。CRect 有一个 



     IntersectRect  函数正适合用来计算四方形交集。 



     但是有一点必须注意,绘图动作不是集中在OnDraw 吗?因此OnUpdate 和OnDraw 之 



     间的分工有必要厘清。前面数个版本中这两个函数的动作是: 



                                                                                       637 


…………………………………………………………Page 700……………………………………………………………

                   第篇    深入  MFC  程式設計 



                     OnUpdate 啥也没做。事实上CScribbleView 原本根本没有改写此一函数。 



                     O
返回目录 上一页 下一页 回到顶部 0 0
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!