# 视图
# 视图窗口简述
在 MFC 的设计中,图形的显示的这部分工作,交由 视图窗口
负责。
框架窗口则担容器之任,成为菜单、标题栏、视图窗口等窗口的容身之所,通常不直接在其客户区中绘制。
视图窗口就被设计为一个没有标题栏,只有客户区的窗口,通常覆盖在框架窗口的客户区上。
# CView
在 MFC 中,视图窗口对应的类即 CView
,继承自 CWnd
;
# CView::OnDraw
CView
中声明了一个纯虚函数 CView::OnDraw
,因此继承必须重写这个函数,用于处理绘制消息;
这个函数是由 CView::OnPanit
调用的。
# 使用视图窗口
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| #include <afxwin.h> #include <afxext.h>
class CMyView : public CView { public: virtual void OnDraw(CDC* pDC); };
void CMyView::OnDraw(CDC* pDC) { pDC->TextOut(100, 100, L"CMyView::OnDraw"); }
class CMyFrameWnd : public CFrameWnd { DECLARE_MESSAGE_MAP() public: afx_msg int AFX_MSG_CALL OnCreate(LPCREATESTRUCT); };
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP()
int AFX_MSG_CALL CMyFrameWnd::OnCreate(LPCREATESTRUCT pCS) { CMyView* pView = new CMyView; pView->Create(nullptr, L"MFCView", WS_CHILD | WS_VISIBLE | WS_BORDER, CRect{}, this, AFX_IDW_PANE_FIRST); m_pViewActive = pView; return CFrameWnd::OnCreate(pCS); }
class CMyWinApp :public CWinApp { public: CMyWinApp(); virtual BOOL InitInstance(); };
CMyWinApp::CMyWinApp() {
}
BOOL CMyWinApp::InitInstance() { CMyFrameWnd* frame = new CMyFrameWnd; frame->Create(nullptr, L"MFCBase"); m_pMainWnd = frame; frame->ShowWindow(SW_SHOW); frame->UpdateWindow(); return TRUE; }
CMyWinApp g_theApp;
|
老朋友了,相信读者阅读起来不会有什么困难,我们为框架窗口的客户区覆盖上了一个视图窗口。
# 文档
# 文档简述
在 MFC 中,将数据的管理交给 文档
负责,再与负责显示数据的 视图
进行数据交互。
# CDocument
MFC 提供的文档类。
一个文档可以同时与多个视图窗口交互
- 内部维护了一个链表,连接所有与当前文档对象交互的视图对象。
一个视图窗口只能与一个文档交互
# 使用文档
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| #include <afxwin.h> #include <afxext.h>
#include "resource.h"
class CMyDoc : public CDocument { };
class CMyView : public CView { DECLARE_DYNCREATE(CMyView); DECLARE_MESSAGE_MAP() public: int AFX_MSG_CALL OnCreate(LPCREATESTRUCT pCs); virtual void OnDraw(CDC* pDC); };
IMPLEMENT_DYNCREATE(CMyView, CView);
BEGIN_MESSAGE_MAP(CMyView, CView) ON_WM_CREATE() END_MESSAGE_MAP()
int AFX_MSG_CALL CMyView::OnCreate(LPCREATESTRUCT pCs) { return CView::OnCreate(pCs); }
void CMyView::OnDraw(CDC* pDC) { pDC->TextOut(100, 100, L"CMyView::OnDraw"); }
class CMyFrameWnd : public CFrameWnd { DECLARE_MESSAGE_MAP() public: afx_msg int AFX_MSG_CALL OnCreate(LPCREATESTRUCT); };
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP()
int AFX_MSG_CALL CMyFrameWnd::OnCreate(LPCREATESTRUCT pCS) { return CFrameWnd::OnCreate(pCS); }
class CMyWinApp :public CWinApp { public: CMyWinApp(); virtual BOOL InitInstance(); };
CMyWinApp::CMyWinApp() {
}
BOOL CMyWinApp::InitInstance() { CMyFrameWnd* frame = new CMyFrameWnd; CMyDoc* pDoc = new CMyDoc;
CCreateContext createContext; createContext.m_pCurrentDoc = pDoc; createContext.m_pNewViewClass = RUNTIME_CLASS(CMyView);
frame->LoadFrame(IDR_MENU_TOP, WS_OVERLAPPEDWINDOW, nullptr, &createContext);
m_pMainWnd = frame;
frame->ShowWindow(SW_SHOW); frame->UpdateWindow(); return TRUE; }
CMyWinApp g_theApp;
|
这回,我们有了不少改动。
首先,我们先从应用的实例初始化开始看起:
CMyWinApp::InitInstance
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| BOOL CMyWinApp::InitInstance() { CMyFrameWnd* frame = new CMyFrameWnd; CMyDoc* pDoc = new CMyDoc;
CCreateContext createContext; createContext.m_pCurrentDoc = pDoc; createContext.m_pNewViewClass = RUNTIME_CLASS(CMyView);
frame->LoadFrame(IDR_MENU_TOP, WS_OVERLAPPEDWINDOW, nullptr, &createContext);
m_pMainWnd = frame;
frame->ShowWindow(SW_SHOW); frame->UpdateWindow(); return TRUE; }
|
我们修改了 CMyWinApp::InitInstance
(及 CMyView
类),通过 MFC 的 动态创建机制
,让 MFC 为我们创建视图窗口,并与主框架窗口建立关联。
说实话,我觉得 MFC 整这么多种选择就很烦 = =,这个也要学哪个也要学,既然要封装不妨封装彻底一点。
这里我们还建立了消息映射 CMyFrameWnd::OnCreate
、 CMyView::OnCreate
,但是并没有做别的事,只是调用了父类实现的消息映射;
实际上并不需要我们去建立消息映射然后调用父类的成员函数,这里是为了方便读者看得更明显。
# 多视图
在一个 不规则框架窗口
中,可以同时存在多个视图窗口。
我们需要在主框架窗口的客户区中,放置不规则框架窗口;
再在不规则框架窗口中放置多个视图窗口。
# CSplitterWnd
拆分窗口类,即不规则框架窗口,其客户区可以放置多个视图窗口。
# 尝试多视图
代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| #include <afxwin.h> #include <afxext.h>
#include "resource.h"
class CMyDoc : public CDocument { };
class CMyView : public CView { DECLARE_DYNCREATE(CMyView); DECLARE_MESSAGE_MAP() public: int AFX_MSG_CALL OnCreate(LPCREATESTRUCT pCs); virtual void OnDraw(CDC* pDC); };
IMPLEMENT_DYNCREATE(CMyView, CView);
BEGIN_MESSAGE_MAP(CMyView, CView) ON_WM_CREATE() END_MESSAGE_MAP()
int AFX_MSG_CALL CMyView::OnCreate(LPCREATESTRUCT pCs) { return CView::OnCreate(pCs); }
void CMyView::OnDraw(CDC* pDC) { pDC->TextOut(100, 100, L"CMyView::OnDraw"); }
class CMyFrameWnd : public CFrameWnd { DECLARE_MESSAGE_MAP() public: afx_msg int AFX_MSG_CALL OnCreate(LPCREATESTRUCT);
virtual BOOL OnCreateClient(LPCREATESTRUCT pCs, CCreateContext* pContext); private: CSplitterWnd m_pSplitWnd; };
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP()
int AFX_MSG_CALL CMyFrameWnd::OnCreate(LPCREATESTRUCT pCS) { return CFrameWnd::OnCreate(pCS); }
BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT pCs, CCreateContext* pContext) { m_pSplitWnd.CreateStatic(this, 1, 2); m_pSplitWnd.CreateView(0, 0, RUNTIME_CLASS(CMyView), CSize(500,500), pContext); m_pSplitWnd.CreateView(0, 1, pContext->m_pNewViewClass, CSize(500, 500), pContext); return TRUE; }
class CMyWinApp :public CWinApp { public: CMyWinApp(); virtual BOOL InitInstance(); };
CMyWinApp::CMyWinApp() {
}
BOOL CMyWinApp::InitInstance() { CMyFrameWnd* frame = new CMyFrameWnd; CMyDoc* pDoc = new CMyDoc;
CCreateContext createContext; createContext.m_pCurrentDoc = pDoc; createContext.m_pNewViewClass = RUNTIME_CLASS(CMyView);
frame->LoadFrame(IDR_MENU_TOP, WS_OVERLAPPEDWINDOW, nullptr, &createContext);
m_pMainWnd = frame;
frame->ShowWindow(SW_SHOW); frame->UpdateWindow(); return TRUE; }
CMyWinApp g_theApp;
|