首先我们来写一个例子:
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.为什么不用框架窗口的客户区显示数据,而非要用视图窗口显示?
框架窗口:就好像个容器,负责装各种各样的子窗口
视图窗口:是一种子窗口,父类是框架窗口,负责显示数据。这样做是因为当应用程序比较复杂时,我们希望一个类去做一件事
|