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

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

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






有任何参数,如何使WM_PAINT 流到OnPaint 函数呢? 



MFC 把消息主要分为三大类,Message Map 机制中对于消息与函数间的对映关系也明定 



以下三种: 



■ 标准Windows 消息(WM_xxx )的对映规则: 



  宏名称                  对映消息            消息处理函数(名称已由系统预设) 



ON_WM_CHAR                WM_CHAR              OnChar 



ON_WM_CLOSE               WM_CLOSE             OnClose 



ON_WM_CREATE              WM_CREATE            OnCreate 



ON_WM_DESTROY             WM_DESTROY           OnDestroy 



ON_WM_LBUTTONDOWN         WM_LBUTTONDOWN        OnLButtonDown 



ON_WM_LBUTTONUP           WM_LBUTTONUP          OnLButtonUp 



ON_WM_MOUSEMOVE           WM_MOUSEMOVE         OnMouseMove 



ON_WM_PAINT               WM_PAINT              OnPaint 



。。。 



                                                                                 395 


…………………………………………………………Page 458……………………………………………………………

                第篇    湷觥 FC  程式設計 



                ■  命令消息(WM_MAND)的一般性对映规则是: 



                    ON_MAND(;) 



                例如: 



                   ON_MAND(IDM_ABOUT; OnAbout) 



                   ON_MAND(IDM_FILENEW; OnFileNew) 



                   ON_MAND(IDM_FILEOPEN; OnFileOpen) 



                   ON_MAND(IDM_FILESAVE; OnFileSave) 



                ■   「Notification 消息」(由控制组件产生,例如BN_xxx )的对映机制的宏分 



                    为好几种(因为控制组件本就分为好几种),以下各举一例做代表: 



                 控制组件         宏名称                       消息处理函数 



                Button    ON_BN_CLICKED(;) memberFxn 



                boBox  ON_CBN_DBLCLK(;) memberFxn 



                Edit      ON_EN_SETFOCUS(;) memberFxn 



                ListBox   ON_LBN_DBLCLK(;) memberFxn 



                 各个消息处理函数均应以afx_msg void 为函数型式。 



                 为什么经过这样的宏之后,消息就会自动流往指定的函数去呢?谜底在于Message Map 



                 的结构设计。如果你把第3章的Message Map 仿真程序好好研究过,现在应该已是成竹 



                 在胸。我将在第9章再讨论MFC  的Message Map 。 



                 好奇心摆两旁,还是先把实用上的问题放中间吧。如果某个消息在Message Map 中找不 



                 到对映记录,消息何去何从?答案是它会往基础类别流窜,这个消息流窜动作称为 



                  「Message Routing」。如果一直窜到最基础的类别仍找不到对映的处理例程,自会有预 



                 设函数来处理,就像SDK 中的DefWindowProc 一样。 



                 MFC  的CCmdTarget 所衍生下来的每一个类别都可以设定自己的Message Map ,因为 



                 它们都可能(可以)收到消息。 



396 


…………………………………………………………Page 459……………………………………………………………

                                                第6章    MFC 程式的生死因果 



     消息流动是个颇为复杂的机制,它和Document/View 、动态生成(Dynamic Creation ), 



     文件读写(Serialization)一样,都是需要特别留心的地方。 



来龙去脉总整理 



     前面各节的目的就是如何将表面上看来不知所以然的MFC 程序对映到我们在SDK 程序 



     设计中学习到的消息流动观念,从而清楚地掌握MFC 程序的诞生与死亡。让我对MFC 



     程序的来龙去脉再做一次总整理。 



  程序的诞生: 



       ■ Application object 产生,内存于是获得配置,初值亦设立了。 



       ■ Afx WinMain 执行AfxWinInit,后者又调用AfxInitThread ,把消息队列尽量加大到 



          96。 



       ■ Afx WinMain  执行InitApplication 。这是CWinApp 的虚拟函数,但我们通常不改 



         写它。 



       ■ AfxWinMain 执行InitInstance 。这是CWinApp 的虚拟函数,我们必须改写它。 



       ■ CMyWinApp ::InitInstance 'new'  了一个CMyFrameWnd 对象。 



       ■ CMyFrameWnd 构造式调用Create,产生主窗口。我们在Create 参数中指定的 



         窗口类别是NULL , 于是MFC 根据窗口种类, 自行为我们注册一个名为 



         〃AfxFrameOrView42d〃  的窗口类别。 



       ■ 回到InitInstance  中继续执行ShowWindow ,显示窗口。 



       ■ 执行UpdateWindow ,于是发出WM_PAIN T。 



       ■ 回到AfxWinMain,执行Run ,进入消息循环。 



   程序开始运作: 



       ■  程序获得WM_PAINT 消息(藉由CWinApp::Run  中的::GetMessage 循环)。 



       ■   WM_PAINT 经由::DispatchMessage 送到窗口函数CWnd::DefWindowProc  中。 



                                                                         397 


…………………………………………………………Page 460……………………………………………………………

                第篇    湷觥 FC  程式設計 



                ■  CWnd::DefWindowProc 将消息绕行过消息映射表格(Message Map )。 



                ■  绕行过程中发现有吻合项目,于是调用项目中对应的函数。此函数是应用程序 



                  利用BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP 之间的宏设立起来的。 



                ■  标准消息的处理例程亦有标准命名,例如WM_PAINT 必然由OnPaint 处理。 



                以下是程序的死亡: 



                ■  使用者选按【File/Close】,于是发出WM_CLOSE 。 



                ■  CMyFrameWnd 并没有设置WM_CLOSE 处理例程,于是交给预设之处理例程。 



                ■  预设函数对于WM_CLOSE  的处理方式是调用::DestroyWindow , 并因而发出 



                   WM_DESTRO Y。 



                ■  预设之WM_DESTROY 处理方式是调用::PostQuitMessage,因此发出WM_QUIT 。 



                ■  CWinApp::Run 收到WM_QUIT 后会结束其内部之消息循环, 然后调用 



                  ExitInstance,这是CWinApp 的一个虚拟函数。 



                ■  如果CMyWinApp 改写了ExitInstance  , 那么CWinApp::Run 所调用的就是 



                  CMyWinApp ::ExitInstance,否则就是CWinApp::ExitInstance 。 



                ■  最后回到AfxWinMain,执行AfxWinTerm,结束程序。 



           Callback 函数 



                Hello  的OnPaint 在程序收到WM_PAINT 之后开始运作。为了让〃Hello; MFC〃 字样从 



                天而降并有动画效果,程序采用LineDDA API  函数。我的目的一方面是为了示范消息的 



                处理,一方面也为了示范MFC 程序如何调用Windows API  函数。许多人可能不熟悉 



                LineDDA,所以我也一并介绍这个有趣的函数。 



398 


…………………………………………………………Page 461……………………………………………………………

                                                          第6章    MFC 程式的生死因果 



首先介绍LineDDA : 



    void WINAPI LineDDA(int; int; int; int; LINEDDAPROC; LPARAM); 



这个函数用来做动画十分方便,你可以利用前四个参数指定屏幕上任意两点的(x;y)  

                                                                             座 

标,此函数将以Bresenham 算法(注) 计算出通过两点之直线中的每一个屏幕图素座 



标;每计算出一个坐标,就通知由LineDDA 第五个参数所指定的callback 函数。这个 



callback 函数的型式必须是: 



     typedef void (CALLBACK* LINEDDAPROC)(int; int; LPARAM); 



通常我们在这个callback 函数中设计绘图动作。玩过Windows  的接龙游戏吗?接龙成 



功后扑克牌的跳动效果就可以利用LineDDA 完成。虽然扑克牌的跳动路径是一条曲 



线,但将曲线拆成数条直线并不困难。LineDDA  的第六个(最后一个)参数可以视应用 



程序的需要传递一个32 位指针,本例中Hello 传的是一个Device Context 。 



Bresenham 算法是计算机图学中为了「显示器(屏幕或打印机)系由图素构成」的这个 



特性而设计出来的算法,使得求直线各点的过程中全部以整数来运算,因而大幅提升 



计算速度。 



{       (x1; y1)                                LineDDACallback(int; int; PLARAM) 



                                                { 

                                                。。。 

                                                。。。 

                                                。。。 

                                                } 



} 

                          (x2; y2) 



                     LineDDA        Bresenham 算法计算出通过两点之直线中每一个 

你可以指定两个坐标点,                    将以 



 屏幕图素的坐标。每计算出一个坐标,就以该坐标为参数,调用你所指定的callback 函数。 



                         图6…6 LineDDA 函数说明 



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