一 MFC的消息映射机制(3)
1 消息映射机制的使用
1.1 自己的类必须派生自 CCmdTarget
1.2 自己的类内 必须添加声明宏 DECLARE_MESSAGE_MAP
1.3 自己的类外 必须添加实现宏
BEGIN_MESSAGE_MAP( theClass, baseClass )
END_MESSAGE_MAP( )
2 消息映射机制的实现
2.1 数据结构
struct AFX_MSGMAP_ENTRY (静态数组的每个元素)
{
UINT nMessage; // 消息ID
UINT nCode; // 通知码
UINT nID; // 命令ID、控件ID
UINT nLastID; // 最后一个控件ID
UINT nSig; // 消息处理函数的类型
AFX_PMSG pfn; // 消息处理函数的指针(地址)
};
struct AFX_MSGMAP (静态变量)
{
const AFX_MSGMAP* pBaseMap;
//保存的是父类的静态变量地址
const AFX_MSGMAP_ENTRY* lpEntries;
//本类的静态数组首地址
};
2.2 展开后的代码
见代码
2.3 宏展开各部分的作用
_messageEntries[] - 静态数组
数组中每个元素的类型AFX_MSGMAP_ENTRY
数组中每个元素保存的是 消息ID 对应的 处理函数
messageMap - 静态变量
类型AFX_MSGMAP
第一个成员保存的是父类的静态变量地址(用于连接链表)
第二个成员保存的是本类的静态数组首地址。
GetMessageMap - 虚函数
返回本类静态变量地址(获取链表头节点)
2.4 消息的处理过程
2.4.1 利用本类的对象(pFrame)调用GetMessageMap成员
虚函数,获取本类静态变量地址(pMessageMap)
2.4.2 利用pMessageMap的第二个成员获取 相应的静态数组
首地址,然后匹配数组中的每个元素,一旦找到执行
2.4.4
2.4.3 如果找不到,利用pMessageMap的第一个成员,获取
父类静态变量地址,如果为NULL,结束查找,如果不为
NULL执行2.4.2
2.4.4 利用找到的 数组元素的第六个成员,并调用这个成员
中保存的成员函数指针,完成消息的处理。
2.4.5 如果遍历整个链表未找到 利用 DefWindowProc处理。
二 MFC消息的分类
1 windows的标准(键盘/鼠标/定时器消息等等...)
ON_WM_XXX
2 自定义消息
#define WM_MYMESSAGE WM_USER+n
ON_MESSAGE
3 命令消息(WM_COMMAND)
ON_COMMAND( ID, 处理函数)
ON_COMMAND_RANGE( 起始ID, 终止ID, 处理函数 )
4 通知消息
ON_通知码
-------------------------------
一 MFC的菜单
1 菜单相关
WIN32 - HMENU(菜单句柄标识菜单)。
MFC - CMenu类对象表示菜单。
2 相关类
CMenu - 封装了对菜单的各种操作,另外还封装了一个成员
m_hMenu(保存了菜单句柄)。
3 菜单的使用
3.1 添加菜单资源
3.2 设置菜单
1)在CFrameWnd::Create可以设置菜单
2)在框架窗口的WM_CREATE消息的处理中
CMenu menu;
menu.LoadMenu - 加载菜单资源
CFrameWnd::SetMenu - 将菜单设置到窗口
3.3 菜单项的消息处理
ON_COMMAND( 菜单项ID, 处理函数 )
3.4 设置菜单项的状态
ON_WM_INITMENUPOPUP
::CheckMenuItem / ::EnableMenuItem
3.5 菜单项消息的处理顺序(WM_COMMAND)
Frame->App(CFrameWnd::OnCmdMsg内部执行顺序决定的)
4 右键菜单
ON_WM_CONTEXTMENU
::TrackPopupMenu
CMenu::GetSubMenu - 获取某个顶层菜单项的下拉菜单
二 工具栏
1 相关类
CToolBarCtrl - 父类CWnd,封装了工具栏控件的操作。
CToolBar - 父类为CControlBar,封装了 工具栏 和 框架窗口
之间的关系,还包括 工具栏的创建
2 工具栏的使用
2.1 添加工具栏资源
2.2 创建工具栏 CToolBar::Create/CToolBar::CreateEx
2.3 加载工具栏资源 CToolBar::LoadToolBar
2.4 工具栏准备停靠的位置
CToolBar::EnableDocking
2.5 框架窗口允许停靠的位置
CFrameWnd::EnableDocking
2.6 设置 工具栏 可以停靠的位置
CFrameWnd::DockControlBar
2.7 工具栏的风格
CBRS_GRIPPER - 把手,夹子风格
CBRS_SIZE_DYNAMIC - 工具栏可以改变形状
CBRS_TOOLTIPS - 工具栏按钮,有标签提示
TBSTYLE_TRANSPARENT - 工具栏按钮突起
2.8 设置工具栏的显示和隐藏
CFrameWnd::ShowControlBar - 设置工具栏显示/隐藏
CWnd::IsWindowVisible - 判断窗口是否处于显示状态 。
练习:(不要出现标志量)
工具栏 处于显示状态 菜单项 勾选
工具栏 处于隐藏状态 菜单项 非勾选
菜单项每点击一次 工具栏的 显示/隐藏 状态切换一次
三 状态栏
1 状态栏的相关类
CStatusBarCtrl - 父类CWnd,封装了状态栏控件的操作。
CStatusBar - 父类CControlBar,封装了 状态栏和框架窗口
之间关系,还包括 状态栏的创建。
2 状态栏的使用
2.1 创建状态栏
CStatusBar::CreateEx/Create
2.2 设置状态栏指示器
CStatusBar::SetIndicators
BOOL SetIndicators(
const UINT* lpIDArray,//指示器ID数组首地址
int nIDCount //指示器的个数
);
2.3 设置状态栏指示器的 宽度 和 风格
CStatusBar::SetPaneInfo
2.4 设置指示器的文本内容
CStatusBar::SetPaneText
-----------------------------------------
什么是MFC?
编程框架,庞大的类库。基于框架,使用各种类(包括系统的和
自定义的),添加各种消息,完成各种功能。
生成基本的窗口,基于窗口添加菜单、工具栏、状态栏。
菜单-通常创建窗口时,传入菜单资源ID添加菜单
工具栏/状态栏-添加窗口的成员变量,在OnCreate函数中,
创建、加载、设置停靠和停靠。
一 MFC视图
1 相关类
CView类-专门用于显示数据的窗口,所有视图类的父类,继承自
CWnd,本质上是一个窗口。
CCtrlView类-继承自CView,在CView中内嵌了一个控件。根据
嵌入的控件不同,派生了CEditView、CListView、
CRichEditView、CTreeView等。
CFormView类-拥有对话框资源窗口,可以方便的拖放控件。
CHtmlView类-专门用来显示网页的视图窗口。我们可以使用这
个类做简单的网页浏览器。
CRecordView类-专门用于显示数据库中记录的视图。
二 CView类的使用
1 派生自CView类的子类重新OnDraw()这个虚函数,才能使用子类
创建对象。
2 由于在CView::PostNcDestroy()函数中,调用了delete this;
所以,视图对象的创建放到堆中,即new 对象。
3 创建时,视图铺满框架窗口的客户区,视图的ID使用MFC给定的
AFX_IDW_PANE_FIRST
4 视图类可以处理菜单等命令消息的前提是必须是框架窗口的活
动视图,设置的方式有两种:
4.1 调用函数:SetActiveView(m_pWndView);
4.2 指针赋值:m_pViewActive=m_pWndView;
5 处理菜单等命令消息的先后顺序(CFrameWnd::OnCmdMsg()):
活动视图->框架窗口->应用程序
6 OnPaint与OnDraw之间的关系?
在CMyView不处理WM_PAINT消息时,当有消息产生时,系统的
CView类处理了WM_PAINT消息,在CView::OnPaint中,调用了
OnDraw函数,由于虚函数的机制,调用CMyView::OnDraw 。
如果在CMyView中处理了WM_PAINT消息,父类的CView的OnPaint
函数不会被调用,OnDraw也不会被调用。
OnDraw函数的输出比OnPaint更简单,所以视图的信息显示,
直接在OnDraw函数中。
二 运行时类信息(4)
1 概念
程序在运行时,得到对象的类的信息以及所属类的继承层次关系。
class CAnimal:public CObject{}
class CDog:public CAnimal{}
CDog dog;
dog is a CDog? TRUE,还能得到类的大小,版本等信息
dog is a CAnimal?TRUE,还能得到CAnimal类的信息
dog is a CObject? TRUE, ...
2 使用
2.1 定义支持运行时类信息的类
2.1.1 派生自CObject类
2.1.2 添加运行时类信息的宏(包括声明宏和实现宏)
DECLARE_DYNAMIC(CDog)
IMPLEMENT_DYNAMIC(CDog,CAnimal)
2.2 调用IsKindOf()函数判断对象是否属于某个类
3 实现原理
3.0 结构
struct CRuntimeClass
{
LPCSTR m_lpszClassName;//类的名称
int m_nObjectSize;//类的大小
UINT m_wSchema; //类的版本
CObject* (PASCAL* m_pfnCreateObject)(); //NULL
CRuntimeClass* m_pBaseClass;//父类的运行时
类信息变量的地址
...
}
3.1 成员以及其作用
3.1.1 classCDog-类型是CRuntimeClass的变量,静态的成员。
3.1.2 GetRuntimeClass-虚函数,作用是返回classCDog的地址
3.2 关系,(类的信息链表)
CDog::GetRuntimeClass()
|->&classCDog
|->类的名称,大小,版本等信息
|->&classCAnimal
|->CAnimal类的名称、大小、版本等信息
|->&classCObject
|->CObject类的名称、大小版本等
|->NULL
dog.IsKindOf(RUNTIME_CLASS(CObject)) TRUE
&classCDog &classCObject
&classCAnimal
&classCObject
3.3 IsKindOf函数的执行过程
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
//classCDog的地址
CRuntimeClass* pClassThis = GetRuntimeClass();
return pClassThis->IsDerivedFrom(pClass);
pClassThis->IsDerivedFrom(pClass)
{
//classCDog的地址
const CRuntimeClass* pClassThis = this;
while (pClassThis != NULL)
{
//比较
if (pClassThis == pBaseClass)
return TRUE;
//获取父类的变量的地址
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE;
}
}
3.3.1 调用GetRuntimeClass获取&classCDog
3.3.2 调用IsDerivedFrom()函数,在函数中,把&classCDog
与参数的&classCWnd比较,如果相等,返回TRUE,表示
对象属于该类,如果不相等,获取&classCAnimal,继续
循环比较,直到&classCObject的父类的变量地址为空,
最后,返回FALSE,表示对象不属于该类。
三 动态创建(5)
1 概念
创建未知类型的对象。指的是,可以先写一个创建对象的函数,
任何类的对象都可以使用该函数创建,包括后来定义的类。
2 使用
2.1 定义支持动态创建的类
2.1.1 派生自CObject
2.1.2 添加动态创建的声明宏和实现宏
DECLARE_DYNCREATE(theClass)
IMPLEMENT_DYNCREATE(theClass,baseClass)
3 实现原理
3.1 展开宏的代码
3.1.1 CreateObject()-静态函数,创建该类的对象。
3.1.2 classCDog-静态变量,在运行时类信息时,pfnNew为NULL;
在动态创建时,它是CreateObject函数的地址。
4 实现步骤
4.1 调用CRuntimeClass::CreateObject()函数
4.2 在函数中,首先判断,m_pfnCreateObject是否为空,
如果不为空,通过它调用CDog::CreateObject函数,
在函数中,return new CDog;
四 动态创建的例子(动态切分窗口)
OnCreateClient-创建窗口的客户区对象