首先我们来写一个样例:
1.建一个win32简单应用程序,不要觉得这样就不能写出MFC程序,由于是不是MFC程序取决于调没调MFC函数。
2. 删除入口函数。仅仅留下#include "stdafx.h"
3.将stdafx.h中的头文件 <windows.h> 更改为 <afxwin.h>。4.Project-->Settings菜单项中设置使用MFC库
5.编写代码:
#include "stdafx.h" #include "resource.h" //视图类(创建方式与工具栏与工具栏步骤类似) class CMyView:public CView { public: virtual void OnDraw( CDC* pDC ); DECLARE_MESSAGE_MAP () protected: afx_msg void OnTest(); }; BEGIN_MESSAGE_MAP(CMyView,CView) ON_COMMAND(ID_TEST,OnTest) END_MESSAGE_MAP() void CMyView::OnTest() { MessageBox("CMView::OnTest"); } void CMyView::OnDraw( CDC* pDC ) { pDC->TextOut(100,100,"Hello World!"); } //框架窗体类 class CMainFrame :public CFrameWnd { public: // CMyView m_wndView;//视图类对象 CMyView*m_pWndView;//视图类的指针 DECLARE_MESSAGE_MAP() protected: afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct ); }; BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP() int CMainFrame::OnCreate( LPCREATESTRUCT lpCreateStruct ) { if(-1==CFrameWnd::OnCreate(lpCreateStruct))//父类的 { return -1; } //创建视图窗体 m_pWndView = new CMyView;//在堆中创建对象 m_pWndView->Create(NULL,"MyView",WS_VISIBLE|WS_CHILD|WS_BORDER,CRect(0,0,100,100), this,AFX_IDW_PANE_FIRST);//AFX_IDW_PANE_FIRST可使边框和客户区重叠 //将视图设置为活动视图 //方式1:调用函数 // SetActiveView(m_pWndView); //方式2:指针赋值 m_pViewActive = m_pWndView; return 0; } //应用程序类 class CViewApp :public CWinApp { public: virtual BOOL InitInstance(); }; CViewApp theApp;//唯一的应用程序对象 BOOL CViewApp::InitInstance() { //创建主要的主框架窗体 CMainFrame *pFrame = new CMainFrame; //创建窗体,内部调用Create函数 pFrame->LoadFrame(IDR_MENU1);//比Create函数用起来简单 //将窗体设置为应用程序主窗体 m_pMainWnd = pFrame; //显示和更新 pFrame->ShowWindow(SW_SHOW); pFrame->UpdateData(); return TRUE; }注意:
实例化CMyView对象前必须重写OnDraw()函数,由于OnDraw()是纯虚函数
视图窗体的创建是在CMainFrame的 OnCreate()函数中调Create函数
思考&提升:
1. 为什么非要使用视图类的指针来?
因为在CView::PostNcDestroy()函数中,调用了delete this; 所以,视图对象的创建放到堆中。即new 对象。
2. 创建视图时,如何视图铺满框架窗体的客户区?
创建时视图的ID填AFX_IDW_PANE_FIRST
3. 为什么要将视图对象设置为框架窗体的活动视图?
由于 处理菜单等命令消息的先后顺序: 活动视图->框架窗体->应用程序。
我们将对此进行验证:在消息提示框那行加断点,调试执行,我们通过调用堆栈得到下图调用信息
菜单消息都属于命令消息。所以我们找CFrameWnd 的 OnCmdMsg。双击进入CFrameWnd::OnCmdMsg()中得到
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { CPushRoutingFrame push(this); // pump through current view FIRST CView* pView = GetActiveView(); if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; // then pump through frame if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; // last but not least, pump through app CWinApp* pApp = AfxGetApp(); if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE; return FALSE; }
能够看出:处理菜单等命令消息的先后顺序: 活动视图->框架窗体->应用程序
4.OnPaint与OnDraw之间的关系?
OnPaint调的是OnDraw。
由于OnDraw函数比OnPaint更简单。不用加入消息映射所以视图的信息显示,直接在OnDraw函数中。
5.为什么不用框架窗体的客户区显示数据。而非要用视图窗体显示?
框架窗体:就好像个容器,负责装各种各样的子窗体
视图窗体:是一种子窗体。父类是框架窗体,负责显示数据。这样做是由于当应用程序比較复杂时,我们希望一个类去做一件事