一、视图窗口
提供一个用于显示数据的窗口
1、视图窗口相关类
CView及其子类,父类为CWnd类,封装了关于视图窗口的各种操作,以及和文档类的数据交互
2、视图窗口的使用
(1)定义了一个自己的视图类(CMyView),派生自CView,并重写父类成员纯虚函数void OnDraw(CDC* pDC),可以用于绘图
(2)其余框架类和应用类程序代码不变
(3)处理框架的WM_CREATE消息时,定义CMyView类对象,并调用Create函数创建视图窗口,视图窗口的ID为 AFX_IDW_PANE_FIRST
3、创建项目(MFCView)
(1)创建项目
(2)编写程序
#include <afxwin.h>
#include "resource.h"
class CMyView:public CView
{
DECLARE_MESSAGE_MAP()
public:
virtual void OnDraw(CDC* pDC);
afx_msg void OnPaint();
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyView, CView)
//ON_WM_PAINT()
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
//父类处理绘图消息时会调用OnDraw,当本类由绘图消息处理,则OnDraw不会被调用
void CMyView::OnDraw(CDC* pDC)
{
pDC->TextOut(100, 100, "CMyView::OnDraw");
}
void CMyView::OnPaint()
{
PAINTSTRUCT ps = {0};
HDC hdc = ::BeginPaint(m_hWnd, &ps);
::TextOutA(hdc, 200, 200, "CMyView::OnPaint", strlen("CMyView::OnPaint"));
::EndPaint(m_hWnd, &ps);
}
void CMyView::OnNew()
{
AfxMessageBox("视图类处理了OnNew消息");
}
class CMyFrameWnd:public CFrameWnd
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_WM_PAINT()
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
CMyView* pView = new CMyView;
pView->Create(NULL, "MFCView", WS_CHILD|WS_VISIBLE|WS_BORDER, CRect(0, 0, 200, 200),
this, AFX_IDW_PANE_FIRST); //AFX_IDW_PANE_FIRST 生成的视图窗口会平铺在框架窗口
m_pViewActive = pView; //将窗口赋值给活动窗口
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnPaint()
{
PAINTSTRUCT ps = {0};
HDC hdc = ::BeginPaint(m_hWnd, &ps);
::TextOutA(hdc, 100, 100, "框架窗口客户区", strlen("框架窗口客户区"));
::EndPaint(m_hWnd, &ps);
}
void CMyFrameWnd::OnNew()
{
AfxMessageBox("框架类处理了OnNew消息");
}
class CMyWinApp:public CWinApp
{
DECLARE_MESSAGE_MAP()
public:
virtual BOOL InitInstance();
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
AfxMessageBox("框架类处理了OnNew消息");
}
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
pFrame->Create(NULL, "MFCView", WS_OVERLAPPEDWINDOW, CFrameWnd::rectDefault,NULL,
(char*)IDR_MENU1);
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
(3)命令消息处理顺序
视图类 -》 框架类 -》 应用程序类
(4)对象关系图
theApp
theApp->m_pMainWnd = pFrame
pFrame->m_pViewActive = pView
二、文档类
相关类 CDocument,提供了用于管理数据的类,封装了关于数据的管理(数据提取,数据转换,数据存储等),并和视图类进行数据交互。
1、创建项目
(1)创建项目(MFCDoc)
(2)编写程序
#include <afxwin.h>
#include <afxext.h>
#include "resource.h"
class CMyDoc:public CDocument
{
};
class CMyView:public CView
{
DECLARE_DYNCREATE(CMyView)
DECLARE_MESSAGE_MAP()
public:
virtual void OnDraw(CDC* cDC);
afx_msg int OnCreate(LPCREATESTRUCT pcs);
};
IMPLEMENT_DYNCREATE(CMyView, CView)
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_WM_CREATE()
END_MESSAGE_MAP()
void CMyView::OnDraw(CDC* cDC)
{
cDC->TextOut(100, 100, "视图窗口");
}
int CMyView::OnCreate(LPCREATESTRUCT pcs)
{
return CView::OnCreate(pcs);
}
class CMyFrameWnd:public CFrameWnd
{
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnPaint();
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_WM_PAINT()
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnPaint()
{
PAINTSTRUCT ps = {0};
HDC hdc = ::BeginPaint(m_hWnd, &ps);
::TextOutA(hdc, 200, 200, "CMyFrameWnd::OnPaint", strlen("CMyFrameWnd::OnPaint"));
::EndPaint(m_hWnd, &ps);
}
class CMyWinApp:public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
CCreateContext cct;
CMyDoc* pDoc = new CMyDoc;
cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);
cct.m_pCurrentDoc = pDoc;
pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL, &cct);
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
(3)创建过程
利用框架类对象地址(pFrame)调用LoadFrame函数,创建框架窗口
在处理框架窗口的WM_CREATE消息时,(父类CFrameWnd)动态创建视图类对象,并创建视图窗口
在处理视图窗口的WM_CREATE消息时,(父类CView)将文档类和视图类对象见理关系
2、创建流程
CMyFrameWnd* pFrame = new CMyFrameWnd;
CMyDoc* pDoc = new CMyDoc;
CCreateContext cct;
cct.m_pCurrentDoc = pDoc;//文档类对象地址
cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);//&CMyView::classCMyView
pFrame->LoadFrame(... &cct)//函数内部this为pFrame
{
Create(...,&cct)//函数内部this为pFrame
{
CreateEx(...&cct)//函数内部this为pFrame
{
CREATESTRUCT cs;
....
cs.lpCreateParams = &cct;
::CreateWindowEx(...,&cct);//创建主框架窗口
}
}
}
//处理框架窗口的WM_CREATE消息
CFrameWnd::OnCreate( pcs )//函数内部this为pFrame,参数可以获取::CreateWindowEx的12个参数
{
CCreateContext* pContext = (CCreateContext*)pcs->lpCreateParams;//获取&cct
OnCreateHelper(pcs, pContext)//函数内部this为pFrame,pContext===&cct
{
OnCreateClient(pcs, pContext)//函数内部this为pFrame,pContext===&cct
{
CreateView(pContext..)//函数内部this为pFrame,pContext===&cct
{
CWnd* pView = pContext->m_pNewViewClass->CreateObject();
//动态创建视图类对象,并返回对象地址
pView->Create(..,pContext)//函数内部this为pView,pContext===&cct
{
CreateEx(..,pContext)//函数内部this为pView,pContext===&cct
{
CREATESTRUCT cs;
....
cs.lpCreateParams = pContext;//pContext===&cct
::CreateWindowEx(...,pContext);//创建视图窗口
}
}
}
}
}
}
//处理视图窗口的WM_CREATE消息
CView::OnCreate( pcs )//函数内部this为pView,参数可以获取::CreateWindowEx函数的12个参数
{
CCreateContext* pContext = (CCreateContext*)lpcs->lpCreateParams;//获取&cct
pContext->m_pCurrentDoc->AddView(pView)//函数内部this为pDoc,参数为视图类对象地址
{
m_viewList.AddTail(pView);//文档类对象用一个链表成员变量,保存视图类对象地址
pView->m_pDocument = this;//视图类对象用一个普通成员变量,保存文档类对象地址
}
}
3、对象关系
(1)文档类对象用一个链表成员变量,保存视图类对象地址
(2)视图类对象用一个普通成员变量,保存文档类对象地址
一个文档类对象可以对应多个视图类对象(视图窗口)
一个视图类对象(视图窗口)只能对应一个文档类对象
4、视图切分
(1)相关类
CSplitterWnd 不规则框架窗口类,分装了关于不规则框架窗口的操作
(2)窗口切分的使用
重写CFrameWnd类的成员虚函数OnCreateClient
在虚函数中调用CSplitterWnd::CreateStatic创建不规则框架窗口
在虚函数中调用CSplitterWnd::CreateView创建视图窗口
(3)编写程序
#include <afxwin.h>
#include <afxext.h>
#include "resource.h"
class CMyDoc:public CDocument
{
};
class CMyView:public CView
{
DECLARE_DYNCREATE(CMyView)
DECLARE_MESSAGE_MAP()
public:
virtual void OnDraw(CDC* cDC);
afx_msg int OnCreate(LPCREATESTRUCT pcs);
};
IMPLEMENT_DYNCREATE(CMyView, CView)
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_WM_CREATE()
END_MESSAGE_MAP()
void CMyView::OnDraw(CDC* cDC)
{
cDC->TextOut(100, 100, "视图窗口");
}
int CMyView::OnCreate(LPCREATESTRUCT pcs)
{
return CView::OnCreate(pcs);
}
class CMyFrameWnd:public CFrameWnd
{
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnPaint();
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
private:
CSplitterWnd m_split; //不规则框架窗口
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_WM_PAINT()
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnPaint()
{
PAINTSTRUCT ps = {0};
HDC hdc = ::BeginPaint(m_hWnd, &ps);
::TextOutA(hdc, 200, 200, "CMyFrameWnd::OnPaint", strlen("CMyFrameWnd::OnPaint"));
::EndPaint(m_hWnd, &ps);
}
BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
//创建两个视图窗口
m_split.CreateStatic(this, 1, 2);
m_split.CreateView(0, 0, RUNTIME_CLASS(CMyView), CSize(100, 100), pContext);
m_split.CreateView(0, 1, pContext->m_pNewViewClass, CSize(100, 100), pContext);
m_pViewActive = (CView*)m_split.GetPane(0,0); //设置活动窗口
return TRUE;
}
class CMyWinApp:public CWinApp
{
public:
virtual BOOL InitInstance();
};
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
CCreateContext cct;
CMyDoc* pDoc = new CMyDoc;
cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);
cct.m_pCurrentDoc = pDoc;
pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL, &cct);
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
三、命令消息(WM_COMMAND)处理顺序
对象关系图
1、编写程序
#include <afxwin.h>
#include <afxext.h>
#include "resource.h"
class CMyDoc:public CDocument
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyDoc, CDocument)
//ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyDoc::OnNew()
{
AfxMessageBox("CMyDoc::OnNew");
}
class CMyView:public CView
{
DECLARE_DYNCREATE(CMyView)
DECLARE_MESSAGE_MAP()
public:
virtual void OnDraw(CDC* cDC);
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnNew();
};
IMPLEMENT_DYNCREATE(CMyView, CView)
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_WM_CREATE()
//ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyView::OnDraw(CDC* cDC)
{
cDC->TextOut(100, 100, "视图窗口");
}
int CMyView::OnCreate(LPCREATESTRUCT pcs)
{
return CView::OnCreate(pcs);
}
void CMyView::OnNew()
{
AfxMessageBox("CMyView::OnNew");
}
class CMyFrameWnd:public CFrameWnd
{
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnPaint();
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
afx_msg void OnNew();
private:
CSplitterWnd m_split; //不规则框架窗口
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_WM_PAINT()
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnPaint()
{
PAINTSTRUCT ps = {0};
HDC hdc = ::BeginPaint(m_hWnd, &ps);
::TextOutA(hdc, 200, 200, "CMyFrameWnd::OnPaint", strlen("CMyFrameWnd::OnPaint"));
::EndPaint(m_hWnd, &ps);
}
BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
//创建两个视图窗口
m_split.CreateStatic(this, 1, 2);
m_split.CreateView(0, 0, RUNTIME_CLASS(CMyView), CSize(100, 100), pContext);
m_split.CreateView(0, 1, pContext->m_pNewViewClass, CSize(100, 100), pContext);
m_pViewActive = (CView*)m_split.GetPane(0,0); //设置活动窗口
return TRUE;
}
void CMyFrameWnd::OnNew()
{
AfxMessageBox("CMyFrameWnd::OnNew");
}
class CMyWinApp:public CWinApp
{
DECLARE_MESSAGE_MAP()
public:
virtual BOOL InitInstance();
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
AfxMessageBox("CMyWinApp::OnNew");
}
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
CCreateContext cct;
CMyDoc* pDoc = new CMyDoc;
cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);
cct.m_pCurrentDoc = pDoc;
pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL, &cct);
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;
2、处理顺序
视图类 -》文档类 -》框架列 -》 应用类
3、消息执行流程
//WM_COMMAND消息的路线
OnCommand(wParam, lParam)//函数内部this为pFrame
{
CWnd::OnCommand(..)//函数内部this为pFrame
{
OnCmdMsg(...)//函数内部this为pFrame *****CFrameWnd::OnCmdMsg 起点
{
CView* pView = GetActiveView()//函数内部this为pFrame
{
return this->m_pViewActive;//活动视图窗口对象地址
}对象
pView->OnCmdMsg(..) ===>终点 CCmdTarget::OnCmdMsg 此函数内部this为pView
m_pDocument->OnCmdMsg(.)==>终点CCmdTarget::OnCmdMsg 此函数内部this为文档类对象
CWnd::OnCmdMsg(..)==>终点 CCmdTarget::OnCmdMsg 此函数内部this为pFrame
CWinApp* pApp = AfxGetApp();//获取&theApp
pApp->OnCmdMsg(..)==>终点 CCmdTarget::OnCmdMsg 此函数内部this为&theApp
}
}
}
四、文档类和视图类的关系
1、使用文档类更新视图类数据
(1)更新与文档类绑定的视图窗口
方式1:
使用this->UpdateAllViews(NULL);更新视图窗口 //NULL为所有窗口
方式2:
POSITION pos = this->GetFirstViewPosition(); //获取m_viewList(保存与文档类绑定的视图列表)迭代器前一个地址
CView* pView = this->GetNextView(pos); //获取第一个视图视图窗口
this->UpdateAllViews(pView); //刷新除pView的所有窗口
(2)使用文档类数据
CMyDoc* pDoc = this->GetDocument(); ‘//this->m_pDocument
cDC->TextOut(100, 100, pDoc->m_strData);
2、程序
#include <afxwin.h>
#include <afxext.h>
#include "resource.h"
class CMyDoc:public CDocument
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnNew();
CString m_strData;
};
BEGIN_MESSAGE_MAP(CMyDoc, CDocument)
ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyDoc::OnNew()
{
AfxMessageBox("CMyDoc::OnNew");
m_strData = "hello word";
//this->UpdateAllViews(NULL);
POSITION pos = this->GetFirstViewPosition(); //获取m_viewList(保存与文档类绑定的视图列表)迭代器前一个地址
CView* pView = this->GetNextView(pos); //获取第一个视图视图窗口
this->UpdateAllViews(pView); //刷新除pView的所有窗口
}
class CMyView:public CView
{
DECLARE_DYNCREATE(CMyView)
DECLARE_MESSAGE_MAP()
public:
virtual void OnDraw(CDC* cDC);
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnNew();
};
IMPLEMENT_DYNCREATE(CMyView, CView)
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_WM_CREATE()
//ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyView::OnDraw(CDC* cDC)
{
CMyDoc* pDoc = (CMyDoc*)this->m_pDocument;
cDC->TextOut(100, 100, pDoc->m_strData);
}
int CMyView::OnCreate(LPCREATESTRUCT pcs)
{
return CView::OnCreate(pcs);
}
void CMyView::OnNew()
{
AfxMessageBox("CMyView::OnNew");
}
class CMyFrameWnd:public CFrameWnd
{
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT pcs);
afx_msg void OnPaint();
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
afx_msg void OnNew();
private:
CSplitterWnd m_split; //不规则框架窗口
};
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_WM_CREATE()
ON_WM_PAINT()
//ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs)
{
return CFrameWnd::OnCreate(pcs);
}
void CMyFrameWnd::OnPaint()
{
PAINTSTRUCT ps = {0};
HDC hdc = ::BeginPaint(m_hWnd, &ps);
::TextOutA(hdc, 200, 200, "CMyFrameWnd::OnPaint", strlen("CMyFrameWnd::OnPaint"));
::EndPaint(m_hWnd, &ps);
}
BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
//创建两个视图窗口
m_split.CreateStatic(this, 1, 2);
m_split.CreateView(0, 0, RUNTIME_CLASS(CMyView), CSize(100, 100), pContext);
m_split.CreateView(0, 1, pContext->m_pNewViewClass, CSize(100, 100), pContext);
m_pViewActive = (CView*)m_split.GetPane(0,0); //设置活动窗口
return TRUE;
}
void CMyFrameWnd::OnNew()
{
AfxMessageBox("CMyFrameWnd::OnNew");
}
class CMyWinApp:public CWinApp
{
DECLARE_MESSAGE_MAP()
public:
virtual BOOL InitInstance();
afx_msg void OnNew();
};
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
//ON_COMMAND(ID_NEW, OnNew)
END_MESSAGE_MAP()
void CMyWinApp::OnNew()
{
AfxMessageBox("CMyWinApp::OnNew");
}
BOOL CMyWinApp::InitInstance()
{
CMyFrameWnd* pFrame = new CMyFrameWnd;
CCreateContext cct;
CMyDoc* pDoc = new CMyDoc;
cct.m_pNewViewClass = RUNTIME_CLASS(CMyView);
cct.m_pCurrentDoc = pDoc;
pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL, &cct);
m_pMainWnd = pFrame;
pFrame->ShowWindow(SW_SHOW);
pFrame->UpdateWindow();
return TRUE;
}
CMyWinApp theApp;