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

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

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


    UINT            m_nThickWidth; 

 。。。 

 } 



所以由CScribDoc 负责唤起对话框,接受笔宽设定,是很合情合理的事。 



如果命令消息处理例程名为OnPenWidths,我们希望在这个函数中先唤起对话框,由对 



话盒取得粗笔和细笔的宽度,然后再把这两个值设定给CScribbleDoc 中的两个对应变 



数。下面是设计步骤。 



   执行ClassWizard,选择【Message Map 】附页,并选择CScribbleDoc。 



     

 在【Object IDs 】清单中选择ID_PEN_ WIDTHS。 



     

 在【Messages 】清单中选择MAND 。 

     

 按下【Add Function 】钮并接受ClassWizard 给予的函数名称OnPenWidths。 



                                                                                                623 


…………………………………………………………Page 686……………………………………………………………

                    第篇    深入  MFC  程式設計 



                       按下【Edit Code 】钮,光标落在OnPenWidths 函数内,键入以下内容: 

                     



                        // SCRIBDOC。CPP 

                        #include 〃pendlg。h〃 

                        。。。 

                        void CScribbleDoc::OnPenWidths() 

                        { 

                            CPenWidthsDlg dlg; 

                            // Initialize dialog data 

                            dlg。m_nThinWidth = m_nThinWidth; 

                            dlg。m_nThickWidth = m_nThickWidth; 



                            // Invoke the dialog box 

                            if (dlg。DoModal() == IDOK) 

                            { 

                                // retrieve the dialog data 

                                m_nThinWidth = dlg。m_nThinWidth; 

                                m_nThickWidth = dlg。m_nThickWidth; 



                                // Update the pen that is used by views when drawing new strokes; 

                                // to reflect the new pen width definitions for 〃thick〃 and 〃thin〃。 

                                ReplacePen(); 

                            } 

                        } 



                    现在,Scribble Step3 全部完成,制作并测试之。 



624 


…………………………………………………………Page 687……………………………………………………………

                                              10     MFC 

                                            第 章       與對話盒 



本章回顾 



   上一章我们为Scribble 加上三个新的菜单命令项。其中一个命令项【Pen/Pen Widths。。。 】 



   将引发对话框,这个目标在本章实现。 



   制作对话框,我们需要为此对话框设计模板(Dialog Template),这可藉Visual C++ 整 



   合环境之对话框编辑器之助完成。我们还需要一个衍生自CDialog 的类别(本例为 



   CPenWidthsDlg)。ClassWizard 可以帮助我们新增类别,并增加该类别的成员变量,以 



   及设定对话框之DDX/DDV  。以上都是透过ClassWizard  以鼠标点点选选而完成,过程 



    中不需要写任何一进程序代码。 



   所谓DDX 是让我们把对话框类别中的成员变量与对话框中的控制组件产生关联,于是 



   当对话框结束时,控制组件的内容会自动传输到这些成员变量上。 



   所谓DDV 是允许我们设定对话框控制组件的内容类型以及资料(数值) 范围。 



   对话框的写作,在MFC 程序设计中轻松无比。你可以尝试练习一个比较复杂的对话框。 



                                                                625 


…………………………………………………………Page 688……………………………………………………………

                第篇    深入  MFC  程式設計 



626 


…………………………………………………………Page 689……………………………………………………………

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



   11 

 第  章 



           View 功能之加強  与 

               重绘效率之提升 



前面数章中,我们已经看到了View 如何扮演Document 与使用者之间的媒介:View 显 



示Document  的资料内容,并且接受鼠标在窗口上的行为(左键按下、放开、鼠标移动), 



视为对Document  的操作。 



Scribble 可以对同一份Document 产生一个以上的Views ,这是MDI 程序的「天赋」 



MDI 程序标准的【Window/New Window 】窗体项目就是为达此目标而设计的。但有一个 



缺点还待克服,那就是你在窗口A的绘图动作不能实时影响窗口B,也就是说它们之间 



并没有所谓的同步更新…即使它们是同一份资料的一体两面! 



Scribble Step4 解决上述问题。主要关键在于想办法通知所有相同血源(同一份 



Document )的各兄弟(各个Views ),让它们一起行动。但却因此必须考虑这个问题: 



如果使用者的一个鼠标动作引发许多许多的程序绘图动作,那么「同步更新」的绘图效 



率就变得非常重要。因此在考量如何加强显示能力时,我们就得设计所谓的「必要绘图 



区」,也就是所谓的Invalidate Region,或称「不再适用的区域」或「重绘区」。每当使 



用者增加新的线条,Scribble Step4 便把「包围该线条之最小四方形」设定为「必要绘图 



区」。为了记录这项资料,从Step1 延用至今的Document 数据结构必须有所改变。 



Step4 的同步更新,是以一笔画为单位,而非以一个点为单位。换句话说在一笔画未完 



                                                           627 


…………………………………………………………Page 690……………………………………………………………

               第篇    深入  MFC  程式設計 



               成之前,不打算让同源的多个View 窗口同步更新…那毕竟太伤效率了。 



               Scribble Step4 的另一项改善是为Document Frame 窗口增加垂直和水平滚动条,并且示范 



               一种所谓的分裂窗口(Splitter window ),如图11…1。这种窗口的主要功能是当使用者 



               欲对文件做一体两面(或多面)观察时,各个观察子窗口可以集中在一个大的母窗口中。 



               在这里,子窗口被称为「窗口」(pane )。 



                 图11…1 Scribble Step4 , 同源 (  同一份Document ) 之各个View 窗口 



                       具备同步更新的能力。Document Frame 窗口具备分裂窗口与卷轴。 



628 


…………………………………………………………Page 691……………………………………………………………

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



同時修改多个                    :                      OnUpdate 

                 Views      UpdateAllViews 和  



    在Scribble View 上绘图,然后选按【Window/New Window 】,会蹦出另一个新的View , 



    其内的图形与前一个View 相同。这两个Views 就是同一份文件的两个「观景窗」。新 



    窗口的产生导至WM_PAINT 产生,于是OnDraw 发生效用,把文件内容画出来: 



         图11…2 一份Document 连结两个Views , 没有同步修正画面。 



    但是, 此后如果你在Scrib1:1 窗口上绘图而未缩放其尺寸的话(也就是不产生 



     WM_PAINT ),Scrib1:2 窗口内看不到后续绘图内容。我们并不希望如此,不幸的是上 



    一章的Scribble Step3 正是如此。 



    不能同步更新的关键在于,没有人通知所有的兄弟们(Views )一起动手…动手调用 



    OnDraw 。你是知道的,只有当WM_PAINT 产生,OnDraw 才会被调用。因此,解决方 



    式是对每一个兄弟都发出WM_PAINT ,或任何其它方法…只要能通知到就好。也就是 



    说,让附属于同一Document  的所有Views 都能够立即反应Document  内容变化的方法 



    就是,始作俑者(被使用者用来修改Document  内容的那个View )必须想办法通知其 



    他兄弟。 



                                                                   629 


…………………………………………………………Page 692……………………………………………………………

                 第篇    深入  MFC  程式設計 



                 经由CDocument::UpdateAllViews,MFC 提供了这样的一个标准机制。 



                 让所有的Views  同步更新资料的关键在于两个函数: 



                   1。 CDocument::UpdateAllViews 这个函数会巡访所有隶属同一份Document  的各 



                    个Views ,找到一个就通知一个,而所谓「通知」就是调用其OnUpdate 函数。 



                  2。 CView::OnUpdate 我们可以在这个函数中设计绘图动作。或许是全部重绘(这 



                     比较笨一点),或许想办法只绘必要的一小部份(这比较聪明一些)。 



                                              Document 



                                                       



                                 View:1        View:2       View:3 



                         o1 使用者在View:1 做动作(View 扮演使用者接口的第一线)。 

                         o2 View:1 调用GetDocument ,取得Document 指针,更改资料内容。 

                         o3 View:1 调用Document  的UpdateAllViews 。 

                         o4 View:2 和View:3  的OnUpdate 一一被调用起来,这是更新画面的时机。 



                如果想让绘图程序聪明一些,不要每次都全部重绘,而是只择「必须重绘」的区域重绘, 



                那么OnUpdate 需要被提示什么是「必须重绘的区域」,这就必须借助于UpdateAllViews 



                的参数: 



                 virtual void UpdateAllViews(CView* pSender; 

                                                  LPARAM lHint; 

                                                  CObject* pHint); 



                  

                    第一个参数代表发出此一通牒的始作俑者。这个参数的设计无非是希望避免重 



                  复而无谓的通牒,因为始作俑者自己已经把画面更新过了(在鼠标消息处理常 



                  式中),不需要再被通知。 



                   



630 


…………………………………………………………Page 693……………………………………………………………

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



     ■后面两个参数lHint 和pHint  是所谓的提示参数(Hint ),它们会被传送到同 



      一Document 所对应的每一个Views  的OnUpdate 函数去。lHint 可以是一些 



      特殊的提示值,pHint  则是一个衍生自CObject 的对象指针。靠着设计良好的 



       「提示」,OnUpdate 才有机会提高绘图效率。要不然直接通知OnDraw 就好 



      了,也不需要再搞出一个OnUpdate。 



    另一方面,OnUpdate 收到三个参数(由CDocument:: UpdateAllViews 发出): 



       virtual void OnUpdate(CView* pSender; 



                            LPARAM lHint; 



                            CObject* pHint); 



    因此,一旦Document 资料改变,我们应该调用CDocument::UpdateAllViews  以通知所有 



    相关的Views 。而在CMyView::OnUpdate 函数中我们应该以效率为第一考量,利用参数 



    中的hint 设定重绘区,使后续被唤起的OnDraw 有最快的工作速度。注意,通常你不 



    应该在OnUpdate 中执行绘图动作,所有的绘图动作最好都应该集中在OnDraw;你在 



    OnUpdate 函数中的行为应该是计算哪一块区域需要重绘, 然后调用 



    CWnd::InvalidateRect ,发出WM_PAINT 让OnDraw 去画图。 



    结论是,改善同步更新以及绘图效率的前置工作如下: 



     1。 定义hint  的数据类型,用以描述已遭修改的资料区域。 



     2。 当使用者透过View 改变了Document  内容,程序应该产生一个hint ,描述此 



       一修改,并以它做为参数,调用UpdateAllViews。 



     3。 改写CMyView::OnUpdate,利用hint 设计高效率绘图动作,使hint 描述区之 



       外的区域不要重画。 



在View 中定义一个hint 



    以Scribble 为例,当使用者加上一段线条,如果我们计算出包围此一线条之最小四方 



    形,那么只有与此四方形有交集的其它线条才需要重画,如图11…3。因此在Step4 中 



    把hint 设计为RECT 类型,差堪为用。 



                                                                        631 


…………………………………………………………Page 694……………………………………………………………

                第篇    深入  MFC  程式設計 



                效率考量上,当然我们还可以精益求精取得各线条与此四方形的交点,然后只重绘四方 



                形内部的那一部份即可,但这么做是否动用太多计算,是否使工程太过复杂以至于不划 



                算,你可得谨慎评估。 



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