本节演示在MFC中,开发弹出对话框的过程和弹出对话框消息处理的过程。MFC的消息处理不是使用一个全局的回调函数,而是创建一个与窗口关联的派生类,用于消息关联的成员函数来接收和处理窗口的消息。在类向导中选择对应的消息,添加与该消息关联的成员函数来处理该消息,这就是MFC的消息映射机制。MFC的消息映射机制,一般不需要开发者解析这些复杂的数据,因为消息映射函......
2023-11-25
要想透彻地解析类向导自动生成的代码,首先必须有一定的C++语法基础,比如,了解构造函数、静态成员变量和静态成员函数等基础知识。
1)类向导专用的注释代码。
在MyDlg.h和MyDlg.cpp中,都有一些以“//{{AFX_”开头的注释代码,并且这些注释代码颜色都变成灰色了。虽然注释代码不参与编译,但是也不要随便删除这些注释代码,因为这些代码是类向导生成的。类向导(ClassWizard)用于代码管理的3种标志如下。
①“//{{AFX_DATA”下面的代码,是用来管理关联成员变量使用的,后面会介绍到。
②“//{{AFX_MSG”下面的代码,是用来管理以“WM_”开头的Windows消息映射函数的。消息映射函数,就是MFC自动把每个消息分离出来,并关联到一个类成员函数上。例如,OnMouseMove和OnPaint等。
③“//{{AFX_VIRTUAL”下面的代码,是用来管理重写基类虚函数的。它是另一类回调函数,和消息回调映射函数类似。在MFC的窗口类中有两类回调函数,一种是消息映射回调函数,另一种是虚函数回调函数。
在类向导(ClassWizard)的消息列表(Messages)中,可以创建两类成员函数,后半部分以“WM_”开头的是窗口消息函数,前半部分不是以“WM_”开头的那些就是虚函数。两种方式创建的函数,分别通过“//{{AFX_MSG”和“//{{AFX_VIRTUAL”注释代码来管理,如图3-60所示。
图3-60 类向导代码
2)关联窗口消息与成员函数的桥梁,即BEGIN_MESSAGE_MAP和END_MESSAGE_MAP。
每次在ClassWizard中建立一个消息映射函数后,在窗口类源代码(.cpp)文件中,就会在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间添加一行代码。这些代码是关联Windows消息和消息映射函数的桥梁,例如,ON_WM_MOUSEMOVE()和ON_WM_PAINT(等)。
3)下面通过查看和替换这些宏定义的方式,来解析这些代码消息关联代码的含义。
选中ON_WM_MOUSEMOVE或者ON_WM_PAINT代码,单击鼠标右键,在弹出的快捷菜单中,选择“Go To Definition Of xxx”命令,或者按<F12>键,查看此类宏定义的原型。
基于以上宏定义,把消息映射关联代码替换成原型后会发现ON_WM_MOUSEMOVE是WM_MOUSEMOVE消息和OnMouseMove成员函数地址的关联。ON_WM_PAINT是WM_PAINT消息和OnPaint成员函数地址的关联。而且每一个关联都是用“{…},”的格式包裹起来,其形式类似于结构体数组的初始化。如果解析清楚BEGIN_MESSAGE_MAP这些宏定义,那么秘密就被揭晓了。(www.chuimin.cn)
4)解密消息映射宏定义(以下消息机制代码解析难度较大,对于C++语言基础较弱者可以忽略)。
替换DECLARE_MESSAGE_MAP宏。这个宏定义是窗口类头文件.h的类声明的结尾处。在源代码窗口中,选中DECLARE_MESSAGE_MAP后按<F12>键查看定义。
替换这个宏定义之后,类内新增了一个成员函数的声明和两个静态成员变量的声明。这三行代码不是新增的代码而是一直就存在于类内的,只不过被DECLARE_MESSAGE_MAP宏掩盖了而已。
静态成员变量_messageEntries是一个结构体数组,数组元素类型是AFX_MSGMAP_ENTRY结构体。选中AFX_MSGMAP_ENTRY再按<F12>键去查看其结构体定义。这就是把消息类型nMessage和成员函数的地址pfn关联起来的结构体。
按照以上方法继续查看BEGIN_MESSAGE_MAP的宏定义。
BEGIN_MESSAGE_MAP是一个带2个参数的宏定义,实际参数在窗口类源代码中指定。例如,BEGIN_MESSAGE_MAP(CMyDlg,CDialog)。要替换这个有参数的宏定义,必须将CMyDlg替换到宏定义中的所有theClass,而把CDialog替换到宏定义中的所有baseClass。
其中BEGIN_MESSAGE_MAP产生了一个成员函数GetMessageMap的函数体,还产生一个静态成员变量messageMap的结构体定义。messageMap结构体主要是建立和处理基类消息和派生类消息之间的关系。最后还提供了静态成员变量_messageEntries结构体数组的初始化语句的起始部分。
END_MESSAGE_MAP提供的是_messageEntries结构体数组初始化语句中的最后一个元素,是一个空的AFX_MSGMAP_ENTRY结构体对象。END_MESSAGE_MAP()最后一行是一个大括号和分号,结束了结构体数组_messageEntries的初始化语句。
有关VC++就业培训宝典之MFC视频教程的文章
本节演示在MFC中,开发弹出对话框的过程和弹出对话框消息处理的过程。MFC的消息处理不是使用一个全局的回调函数,而是创建一个与窗口关联的派生类,用于消息关联的成员函数来接收和处理窗口的消息。在类向导中选择对应的消息,添加与该消息关联的成员函数来处理该消息,这就是MFC的消息映射机制。MFC的消息映射机制,一般不需要开发者解析这些复杂的数据,因为消息映射函......
2023-11-25
在第2章中的计算器程序中,实际上已经使用了消息处理机制。在回调函数中通过分支语句对消息进行解析和处理,就是Win32程序的消息处理机制。图3-30 查看运行结果图3-31 保存工作区设置10)继续修改消息回调函数,增加一些消息的种类,进一步观察Win32程序的消息处理机制。在本例中WM_PAINT消息用于界面绘图和WM_ LBUTTONDOWN处理单击左键操作。Windows中常见的消息及其说明见表3-3。......
2023-11-25
1)SendMessage和PostMessage函数都是消息传递函数,通过MSDN查看两个函数的格式。2个函数的4个参数的意义是一样的,只有返回值类型不同,LRESULT表示消息被处理后的返回值,BOOL表示消息是否传递成功。3)新建一个Win32工程,编写一段简单的代码测试消息传递函数。在MFC程序中,必须使用ON_MESSAGE来关联消息映射函数。PostMessage是非阻塞的,不等OnPostMessage执行完就继续向下执行,而且返回值是1,代表消息已经传送到。......
2023-11-25
在本章第5节中,通过“Win32 Application”建立的MFC32工程,目的是为了演示MFC工程的架构原理。一个MFC工程必须包含一个CWinApp的派生类,并定义一个派生类的全局变量theApp,最后重写InitInstance虚函数用于处理进程启动过程。本节直接通过“MFC AppWizard”来创建MFC工程,用于对照以上说明的MFC必备因素。图3-54 程序向导生成的代码图3-55 MFC类向导在Class name下拉列表中选择CTestMFCDlg类,在Member functions列表框中显示4个已添加的回调函数。......
2023-11-25
互联网网络通信的基础是TCP/IP,即传输控制协议和网络互联协议。按照TCP/IP规定,32位IP地址用4个字节来表示,例如,“192.168.1.100”。图15-1 通过命令查看本机网络配置在“本地连接”的属性设置对话框中,双击“Internet协议”,如图15-2所示。图15-2 查看网络邻居属性图15-3 TCP/IP属性设置在TCP/IP中计算机软件通信必须依赖于通信端口,端口号的范围是0~65535。......
2023-11-25
当框架类窗口大小变化时,客户区内所有子窗口的位置自动排布。CFrameWnd类对工具栏的停靠和浮动控制,在其他CWnd派生类中都难以实现。图12-35 CFrameWnd类①调用CFrame::Create函数直接创建。LoadFrame对参数进行裁剪,只有第一个参数必须代入,其余参数具有默认数值。LoadFrame不需要代入窗口类型名,也就无需在创建前先注册。CDocTemplate对象将框架、视图与文档绑定在一起,三个组成部分统一由系统内部创建。表12-5 CFrameWnd类的常用成员(续)2)CMDIFrameWnd类如图12-36所示。......
2023-11-25
创建一个工程名为“vr”的对话框程序,用于演示手动创建控件并调用创建好的控件。图11-1 添加普通成员函数图11-2 填写函数名称和返回值4)单击“OK”按钮,在函数中编写创建控件的代码。6)手动创建3个按钮的消息映射函数,如图11-3所示。在对话框启动时,基类成员函数CDialog::OnInitDialog会自动创建控件。手动创建控件难度大而且麻烦,不但创建控件的过程要手动编码实现,而且控件的消息映射过程也要手工编码实现。......
2023-11-25
CBrush类的主要成员见表7-4。表7-4 CBrush类的主要成员1)用于填充的阴影线风格主要包括以下几种。创建一个工程名为“Brush”的对话框程序,用于演示选用不同画刷进行绘画的效果。2)在资源视图中,单击鼠标右键,在弹出的快捷菜单中,选择“Import”命令导入位图,如图7-16所示。图7-19 查看运行结果CBrush类构造函数与CreateSolidBrush和CreateHatchBrush等函数的功能基本一样,都可以用于创建一个画刷。一般当使用新画刷绘画结束后,最好恢复选择回旧画刷。......
2023-11-25
相关推荐