Window消息可以分为三类:(1)标准Window消息(CWnd子类处理),(2)控制通知消息(CWnd子类处理),(3)命令消息(应用中的5类都可以)。所有派生自CCmdObjec对象的类都可以处理Windows消息。
(1)前缀以“WM_ ”开头,但是WM_COMMAND消息除外。如窗口重回WM_PAINT,WM_QUIT (2)WM_COMMAND消息,窗口上的各种空间发出的消息 (3)WM_COMMAND消息,只是指控制界面发出的消息,如菜单项与工具栏的按钮操作。MFC为“标准菜单”“工具栏”提供为独特的唯一表示符ID。
Windows消息与程序进行交互,MFC提供了消息的大部分处理流程,只需要程序猿完成与特定消息、特定环节、特定位置、特定时间处理的方法实现。在FMC中各类的消息处理必然都是一个类的成员函数。MFC中为每个接受Window消息处理的类中都定义了“消息映射函数”,完成将Window消息与特定的消息成员处理函数相关的声明,当特定消息出现时候,就调用响应的成员处理函数。并且消息的处理函数用afx_msg标识与普通函数进行区别,此预定义为空,仅仅作为标识作用。
// Type modifier for message handlers #ifndef afx_msg #define afx_msg // intentional placeholder #endif
类的定义文件:
// TextEditorDoc.cpp
IMPLEMENT_DYNCREATE(CTextEditorDoc, CDocument) //声明中第一个参数是消息映射函数的类, 第二个参数是其基累
BEGIN_MESSAGE_MAP(CTextEditorDoc, CDocument) ON_COMMAND(ID_N_ITEM1, &CTextEditorDoc::OnNItem1) END_MESSAGE_MAP()
类的声明文件:如果函授此声明的.h文件中有次DECLARE_MESSAGE_MAP()声明,则其CPP文件中,就要有BEGIN_MESSAGE_MAP(CTextEditorDoc, CDocument)END_MESSAGE_MAP()的定义。
// 生成的消息映射函数 protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnNItem1();
Window消息还带有其他的数据信息,用于对如同时WM_COMMAND消息的不同消息发送者的ID的信息区别不同的执行函数。不应该把一个消息映射给多个处理函数,因为MFC的消息处理机制第二个以及以后的所有处理消息都不回执行。
Windows消息处理函授不能乱放。如标准Window消息,以及控制通知消息一般是CWnd派生类可以处理,而Doc类则明显不能处理。所有的标准Window消息MFC都提供了默认的消息处理,这样如果本消息处理或者自己处理,或者处理后继续传递给默认的消息处理。
MFC定义处理Windows消息的(单文档应用程序)一般流程如下:View -> Doc -> DocTemplate -> Fram -> App
IDR_ 一般表示窗口定义完整资源
如(1)工具栏按钮图标ID标识前缀,(2)。
ID_ MFC约定此为菜单项的ID规范
利用类向导添加类成员,注意:如果手动添加(0)变量的初始化放在构造函数中(1)如果实在堆中分配空间,在析构函数中进行释放
对于菜单的特定条目会要处理两类消息:
(1)COMMAND :按下菜单项中触发的消息,消息响应函数完成对应的特定行为
(2)UPDATE_COMMAND_UI :取决于菜单的状态,如复选菜单,工具拦按钮等,在新菜单出现直线处理消息响应函数。
两类消息的映射形式:
BEGIN_MESSAGE_MAP(CTextEditorDoc, CDocument)
ON_COMMAND(ID_N_ITEM1, &CTextEditorDoc::OnNItem1)
ON_UPDATE_COMMAND_UI(ID_N_ITEM1, &CTextEditorDoc::OnUpdateNItem1)
END_MESSAGE_MAP()
单文档中添加工具栏简单操作:
窗口绘制经验,当外部事件调整窗口大小,绘制窗口颜色等,需要程序某部分需要发送WM_PAINT,window标准消息给应用程序,从而对响应的窗口进行重绘动作。
MFC收到WinOS消息队列中的WM_PAINT,后,通知WinOS去调用WinPro执行重绘的响应处理。
WinOS默认为窗口定义本地坐标系,如下图所示,WinOS需要知道需要重绘的窗口ID的左上角在[屏幕]的位置。
WindowOS使用图形定义界面GDI(Graphic,Device,Interface)抽象所有的图形输出硬件,实现程序与具体硬件的解耦。
WindowOS使用设备上下文CDC,一种WindOS的数据结构,将该包含的信息通过GDI物理硬件上的具体动作。MFC的CDC类中封装了一个设备上下文,对该类对象的操作可以影响到最终响应的硬件。CWnd类的onDraw()通过调用设备上下文,就可以执行响应的绘制处理。通过更改设备上下文的属性可以操作具体的物理设上下文CDC的设备映射默认是以像素为单位距离计算,可以变换,所以具体的输出图形的效果与具体的硬件设备的DPI有关。MFC已经对一些细节进行了封装。
MFC绘图的机制:
继承Cwnd的派生类实现的onDraw(),每当窗口重新使,需要执行此函数,如View类。方法传入的是设备上下文指针。无论如何修改设备上下文的画笔,画刷,颜色扥个,函数的末尾都要讲画笔画刷等替换回来。
// CTextEditorView 绘制 void CTextEditorView::OnDraw(CDC* pDC) { CTextEditorDoc* pDoc = GetDocument();//返回现有视图相关联的对象 ASSERT_VALID(pDoc);//调试版本使用,确保参数有效。发布版本将被忽略。 if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 }
由于鼠标的交互主要是View区域,所以一般鼠标的响应函数放在View中(视图类)。
鼠标可能存在某个窗口在收到LbuttonUp之前,没有收到LbuttonDown,如按下后滑动到另一个控件View上。程序猿需要注意
MFC支持只绘制部分区域的工作区。如果现实的比较复杂时,则可以接上大量的时间。通过调用CWnd成员的InvialdateRect(CRectangle,Bool)函数,对响应窗口的指定位置进行绘制。参数1需是需要在此Wnd类对应的窗口中从新绘制的区域,如果为0,则对此类的整个窗口进行绘制。参数2,True,擦除举行的背景,False,举行与背景的颜色进行重接显示,默认True擦除。InvilateDate()函数执行把需要重绘的区域传递给WinOs,然后维护者不同窗口发来的重绘无效的举行,形成一个包络矩形。最后WM_PAINT消息发送到响应的CWnd窗口对象是进行onDraw()重绘。而每个CWnd派生类都会通过UpdateWindow()而发送一个处理本窗口的WM_PAINT的消息。所以InvalidateRect()用法后,紧跟着一个UpdateWindow()这样是提高效率。
CDocument::UpdateAllViews(三个参数),提供了一个文档将更新消息发送到所有视图。参数1:指向修改文档的视图,或 NULL,如果将更新所有视图。将会使document的所有相关的View调用其OnUpdate()函数。或者进行重载,进行参数传递。