一、MFC的视图窗口
1.相关问题
视图窗口:提供了一个用于显示数据的窗口,并和用户进行交互操作
2.相关的类
CView及其子类 - 父类CWnd,封装了关于视图窗口的操作
3.视图窗口的使用
(1)从CView类派生一个自己的视图类(CMyView),并必须重写父类的纯虚函数OnDraw
当CView类帮我们处理WM_PAINT消息时将调用OnDraw
(2)在框架窗口的WM_CREATE消息处理中:new一个CMyVIew类对象(pView),并调用Create函数,完成视图窗口的创建
4.命令消息(WM_COMMAND)处理顺序
View --> Frame --> App
CFrameWnd::OnCmdMsg函数内部代码执行的先后顺序决定的
5.对象的关系图
m_pMainWnd = pFrame;
m_pViewActive = pView;
theApp
|------->m_pMainWnd(框架类对象地址pFrame)
|------->m_pViewActive(视图类对象地址pView)
相关代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include "stdafx.h" class CMyView :public CView { DECLARE_MESSAGE_MAP() public: virtual void OnDraw(CDC* pDC); public: afx_msg void OnPaint(); afx_msg void OnNew(); }; BEGIN_MESSAGE_MAP(CMyView, CView) ON_COMMAND(ID_NEW, OnNew) //ON_WM_PAINT() END_MESSAGE_MAP() void CMyView::OnNew() { AfxMessageBox(L"视图类处理了新建被点击"); } void CMyView::OnPaint() { PAINTSTRUCT ps = { 0 }; HDC hdc = ::BeginPaint(this->m_hWnd, &ps); ::TextOut(hdc, 200, 200, L"CMyView::OnPaint", 16); ::EndPaint(this->m_hWnd, &ps); } void CMyView::OnDraw(CDC* pDC) { pDC->TextOutW(100, 100, "CMyView::OnDraw"); } class CMyFrameWnd :public CFrameWnd { DECLARE_MESSAGE_MAP() public: afx_msg void OnPaint(); afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); }; BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_WM_CREATE() ON_WM_PAINT() END_MESSAGE_MAP() int CMyFrameWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { CMyView *pView = new CMyView; this->m_pViewActive = pView; pView->Create(NULL, L"", WS_VISIBLE|WS_CHILD|WS_BORDER, CRect(0, 0, 100, 100), this, AFX_IDW_PANE_FIRST); return CFrameWnd::OnCreate(lpCreateStruct); } void CMyFrameWnd::OnPaint() { PAINTSTRUCT ps = { 0 }; HDC hdc = ::BeginPaint(this->m_hWnd, &ps); ::TextOut(hdc, 100, 100, L"我是框架窗口客户区", 9); ::EndPaint(this->m_hWnd, &ps); } class CMyWinApp :public CWinApp { public: virtual BOOL InitInstance(); }; CMyWinApp theApp; BOOL CMyWinApp::InitInstance() { CMyFrameWnd *pFrame = new CMyFrameWnd; m_pMainWnd = pFrame; pFrame->Create(NULL, L"MFC View", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault, NULL, MAKEINTRESOURCE(IDR_MENU1)); pFrame->ShowWindow(SW_SHOW); pFrame->UpdateWindow(); return TRUE; }
运行结果:
二、运行时类信息机制(MFC第四大机制)
1.运行时类信息机制的作用
在程序执行过程中,可以通过这个机制获知对象相关类的信息(获知一个对象是不是某个类的对象)
2.运行时类信息机制的使用
(1)类必须派生自CObject
(2)类内必须添加声明宏 DECLARE_DYNAMIC
(3)类外必须添加实现宏 IMPLEMENT_DYNAMIC
CObject::IsKindOf( ) - 可以判断对象是不是属于某个类
3.运行时类信息实现
(1)数据结构
struct CRuntimeClass(宏展开静态变量的类型)
{
LPCSTR m_lpszClassName; //类名称
int m_nObjectSize; //类的大小sizeof
UINT m_wSchema; //类的版本0xFFF
CObject* (PASCAL* m_pfnCreateObject)( ); //用于动态创建机制,此处没用,为NULL
CRuntimeClass* m_pBaseClass; //父类静态变量地址(负责连接链表)
CRuntimeClass* m_pNextClass; //运行时类信息为NULL
};
(2)宏展开代码
见代码
(3)宏展开各部分的作用
classCDog - 静态变量,保存了关于类的相关信息(类名、大小、版本...)
GetRuntimeClass( ) - 虚函数,获取本类静态变量地址(获取链表头结点地址)
(4)关系图
GetRuntimeClass( )
|->类名/大小/版本
|->&classCDog
|->类名/大小/版本
|->&classCAnimal
|->类名/大小/版本
|->&classCObject
|->类名/大小/版本
|->NULL
(5)IsKindOf的实现
利用类对象(yellowDog)调用宏展开的虚函数GetRumtimeClass获取本类静态变量地址(&classCDog链表头结点)
利用&classCDog和目标(IsKindOf的参数)进行比对,如果相等,证明yellowDog属于该类;如果不相等,利用&classCDog
第五个成员获取父类静态变量,和目标进行循环比对,只要又一次比对成功,也能证明yellowDog属于该类
如果循环结束一次比对都不成功才证明yellowDog不属于这个类
伪代码:
yellowDog.IsKindOf( RUNTIME_CLASS( CObject ) )
{
CRuntimeClass* pClassThis = GetRuntimeClass( ); //获得链表头结点地址
return pClassThis->IsDerivedFrom( RUNTIME_CLASS( CObject ) ) //函数内部this为链表头结点,参数为链表尾节点
{
const CRuntimeClass* pClassThis = this; //获取链表头结点
while ( pClassThis != NULL )
{
if ( pClassThis == RUNTIME_CLASS( CObject ) )
return TRUE;
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE;
}
}
附:RUNTIME_CLASS( theClass ) ==> &theClass::classtheClass
括号中指明的类的静态变量地址
相关代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include "stdafx.h" class CAnimal : public CObject { DECLARE_DYNAMIC(CAnimal) }; IMPLEMENT_DYNAMIC(CAnimal, CObject) class CDog : public CAnimal { public: static const CRuntimeClass classCDog; virtual CRuntimeClass* GetRuntimeClass() const; }; AFX_COMDAT const CRuntimeClass CDog::classCDog = { "CDog", sizeof(class CDog), 0xFFFF, NULL, ((CRuntimeClass*)(&CAnimal::classCAnimal)), NULL }; CRuntimeClass* CDog::GetRuntimeClass() const { return ((CRuntimeClass*)(&CDog::classCDog)); } int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { CDog yellowDog; if (yellowDog.IsKindOf(RUNTIME_CLASS(CObject))) { printf("yellowDog is CObject\n"); } else { printf("yellowDog is not CObject\n"); } return 0; }
运行结果:
三、动态创建机制(MFC第五大机制)
1.动态创建机制的作用
在不知道类名的情况下,将类的对象创建出来
2.动态创建机制的使用
(1)类必须派生自CObject
(2)类内必须添加声明宏 DECLARE_DYNCREATE
(3)类外必须添加实现宏 IPLEMENT_DYNCREATE
CRuntimeClass::CreateObject - 负责动态创建类的对象
3.动态创建机制的实现
(1)宏展开代码
见代码
(2)宏展开各部分的作用(和运行时类信息机制的区别)
多了一个静态函数CDog::CreateObject(new了一个CDog类对象)
静态变量的第四个成员不在为NULL,保存了新增加静态函数的地址(函数名称)
(3)CRuntimeClass::CreateObject执行过程
利用CDog类静态变量(&CDog::classCDog)的第四个成员获取新增加静态函数(CDog::CreateObject)
调用这个静态函数(CDog::CreateObject),在这个静态函数内部new了一个CDog对象,并将对象地址返回
伪代码:
CObject *pObj = RUNTIME_CLASS(CDog)->CreateObject( ) //this为&classCDog,链表头结点
{
CObject* pObject = ( *m_pfnCreateObject )( ) //CDog::CreateObject,pObject就是CDog
{
return new CDog;
}
return pObject; //把CDog返回
}
相关代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include "stdafx.h" class CAnimal :public CObject { DECLARE_DYNCREATE(CAnimal) }; IMPLEMENT_DYNCREATE(CAnimal, CObject) class CDog :public CAnimal { public: static const CRuntimeClass classCDog; virtual CRuntimeClass* GetRuntimeClass() const; static CObject* PASCAL CreateObject(); }; CObject* PASCAL CDog::CreateObject() { return new CDog; } AFX_COMDAT const CRuntimeClass CDog::classCDog = { "CDog", sizeof(class CDog), 0xFFFF, CDog::CreateObject, ((CRuntimeClass*)(&CAnimal::classCAnimal)), NULL }; CRuntimeClass* CDog::GetRuntimeClass() const { return ((CRuntimeClass*)(&CDog::classCDog)); } int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { CObject *pObj = RUNTIME_CLASS(CDog)->CreateObject(); if (pObj->IsKindOf(RUNTIME_CLASS(CDog))) { printf("pObj is CDog\n"); } else { printf("pObj is not CDog\n"); } return 0; }
运行结果: