【C++】【MFC】CView和CDocument关联以及COMMAND消息走向
MFC编程中,CView类负责显示,CDocument负责数据管理,所以其之间的联系十分重要,包括COMMAND消息的流向
CView中的m_pDocument成员将存储和其关联的唯一的CDocument地址,而CDocument中的m_viewList链表将存储和其关联的所有CView地址,即一个CDocument可以有多个CView,但一个CView只能有一个CDocument。
关于COMMAND消息走向,其优先级分别是:CView -> CDocument -> CFrameWnd -> CWinApp。
Code:
1 #include <afxwin.h> 2 #include <afxext.h> 3 #include "resource.h" 4 5 // 文档类 6 class CMyDoc : public CDocument { 7 DECLARE_MESSAGE_MAP() // 消息映射—类内声名宏 8 public: 9 CString str; // 数据管理 10 afx_msg void OnNew(); // ID_FILE_NEW消息映射回调函数 11 }; 12 BEGIN_MESSAGE_MAP(CMyDoc, CDocument) // 消息映射—类外实现宏 13 ON_COMMAND(ID_FILE_NEW, OnNew) // 触发COMMAND消息的控件和回调函数 14 END_MESSAGE_MAP() 15 16 // 在CMyDoc中触发 ID_FILE_NEW 控件后执行该函数 17 void CMyDoc::OnNew() { 18 str = "HELLO, WORLD"; 19 POSITION pos = GetFirstViewPosition(); // 获取m_viewList链表头节点的前一个地址 20 CView* pView = GetNextView(pos); // 获取头节点地址 21 UpdateAllViews(pView); // 更新除第一个View窗口以外的所有窗口 22 } 23 24 // 视图类 25 class CMyView : public CView { 26 DECLARE_DYNCREATE(CMyView) // 动态创建—类内声名宏 27 DECLARE_MESSAGE_MAP() 28 public: 29 virtual void OnDraw(CDC* pdc); // 父类绘图函数 30 afx_msg int OnCreate(LPCREATESTRUCT pcs); 31 afx_msg void OnNew(); 32 }; 33 IMPLEMENT_DYNCREATE(CMyView, CView) // 动态创建—类外实现宏 34 BEGIN_MESSAGE_MAP(CMyView, CView) 35 //ON_COMMAND(ID_FILE_NEW, OnNew) 36 ON_WM_CREATE() 37 END_MESSAGE_MAP() 38 39 // 在 CMyView 中触发 ID_FILE_NEW 控件后执行该函数 40 void CMyView::OnNew() { 41 AfxMessageBox("View."); // 弹出消息框,内容为“View.” 42 } 43 44 int CMyView::OnCreate(LPCREATESTRUCT pcs) { 45 46 return CView::OnCreate(pcs); 47 } 48 49 // 在 CView 客户区中绘制界面 50 void CMyView::OnDraw(CDC* pdc) { 51 //CMyDoc* pDoc = (CMyDoc*)m_pDocument; 52 CMyDoc* pDoc = (CMyDoc*)GetDocument(); // 获取文档类地址 53 pdc->TextOut(100, 100, pDoc->str); // 将文档类中的str成员变量输出至View窗口中 54 } 55 56 // 框架窗口类 57 class CMyFrameWnd : public CFrameWnd { 58 DECLARE_MESSAGE_MAP() 59 public: 60 CSplitterWnd split; 61 public: 62 afx_msg int OnCreate(LPCREATESTRUCT pcs); 63 afx_msg void OnPaint(); 64 virtual BOOL OnCreateClient(LPCREATESTRUCT psc, CCreateContext* pContext); 65 }; 66 BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd) 67 ON_WM_PAINT() 68 ON_WM_CREATE() 69 END_MESSAGE_MAP() 70 71 BOOL CMyFrameWnd::OnCreateClient(LPCREATESTRUCT psc, CCreateContext* pContext) { 72 // 划分为一个一行两列的两个View 73 split.CreateStatic(this, 1, 2); 74 // 创建第一个View 75 split.CreateView(0, 0, pContext->m_pNewViewClass, CSize(100, 100), pContext); 76 split.CreateView(0, 1, RUNTIME_CLASS(CMyView), CSize(100, 100), pContext); 77 78 // 设置第一个View为活动窗口 79 m_pViewActive = (CView*)split.GetPane(0,0); 80 return TRUE; 81 } 82 83 void CMyFrameWnd::OnPaint() { 84 PAINTSTRUCT ps = { 0 }; 85 HDC hdc = ::BeginPaint(m_hWnd, &ps); 86 ::TextOut(hdc, 100, 100, "123", 3); 87 ::EndPaint(m_hWnd, &ps); 88 } 89 90 int CMyFrameWnd::OnCreate(LPCREATESTRUCT pcs) { 91 92 return CFrameWnd::OnCreate(pcs); 93 //return 0; 94 } 95 96 class CMyWinApp : public CWinApp { 97 public: 98 virtual BOOL InitInstance(); 99 }; 100 101 BOOL CMyWinApp::InitInstance() { 102 CMyFrameWnd* pFrame = new CMyFrameWnd; 103 CMyDoc* pDoc = new CMyDoc; 104 CCreateContext cct; 105 cct.m_pNewViewClass = RUNTIME_CLASS(CMyView); 106 cct.m_pCurrentDoc = pDoc; 107 pFrame->LoadFrame(IDR_MENU1, WS_OVERLAPPEDWINDOW, NULL, &cct); 108 m_pMainWnd = pFrame; 109 pFrame->ShowWindow(SW_SHOW); 110 pFrame->UpdateWindow(); 111 112 return TRUE; 113 } 114 115 CMyWinApp theApp;