MFC应用程序中的对象通信 Visual C++基于MFC的可视化编程技术给程序员带来了巨大的方便,程序员可以用 很少的精力去关心用户界面的设计,而把主要精力投入到编制具体的事件操作代 码。使用MFC AppWizard构造的应用程序框架,主要包括以下几个对象:应用程序 对象、文档模板、主框架窗口对象、文档对象、视口对象等,它们各自的任务见 表一,它们之间的关系见图一。 表一 应用程序的对象和任务 对象 任务 应用程序对象 是应用程序和Windows间的界面,负责注册窗口类、建立事例、接受和发送消息。 文档模板 链接应用程序对象、文档对象、子框架窗口对象、视口对象。 主框架窗口对象 构造应用程序的外观,管理菜单、工具条、状态条等。 文档对象 存放应用程序的数据,实现磁盘I/O。 子框架窗口对象 管理子窗口、文档、视窗对象等。 视窗对象 显示应用程序的数据、接受外界事件。 菜单对象 管理程序的菜单。 工具条对象 管理程序的工具条。 状态条对象 管理程序的状态条。 图一 应用程序、文档模板、文档、框架窗口及视口对象之间的相互关系 应用程序用对象分工的方式,将程序的主要任务分布在这些对象中。这些对象通 过用其它对象成员函数和发送消息来相互通信协同工作。 当我们没有弄清MFC应用程序的这种对象分工机制和这些对象之间的通信方法时, 我们就总感慨MFC编程的困难,一头雾水,无法领略到MFC编程的魅力。 由此看来,MFC编程的一个经常遇到的问题就是如何访问应用程序的其它对象,以 利用属于这些对象的函数,也就是对象通信的问题。当我们用AppWizard产生一个 应用程序后,在视类中就自动加入了成员函数GetDocument(),有了这个函数,视 类就可以完成从视类到文档对象的通信,就可以操作文档类的成员函数和成员变 量。但这是不够的,下表列出了MFC应用程序的对象之间的通信方法。 表二 应用程序的对象通信方法 对象 通信对象 方法 任意对象 应用程序对象 AfxGetApp()。 应用程序对象 主框架窗口对象 m_pMainWnd。 文档对象 视窗对象 GetFirstViewPosition()函数获得第一个视窗位置,以现有 位置参数用GetNextView()函数获取此视窗和后续视窗的指针。 文档对象 文档模板对象 GetDocTemplate()。 视窗对象 文档对象 GetDocument(),用UpdateAllViews()函数通知视窗对象更新。 视窗对象 子框架窗口对象 GetParentFrame()。 视窗对象 视窗对象 GetFirstViewPosition()函数获得第一个视窗位置,以现有位置参数用GetNextView()函数获取此视窗和后续视窗的指针。用IsKindOf()函数判定。 子框架窗口对象 视窗对象 GetActiveView()。 主框架窗口对象 子框架窗口对象 MDIGetActive()。 应用程序对象 菜单对象 GetMenu()。 任意对象 状态条对象 CStatusBar*pStatus=(Cstatus-Bar*) AfxGetApp()-> m_pMainWnd-> GetDescendantWindow(AFX_IDW_STATUS_BAR) 任意对象 工具条对象 CToolBar*pTool=( CToolBar *) AfxGetApp()-> m_pMainWnd-> GetDescendantWindow(AFX_IDW_TOOLBAR)     下面我们给出一个实例,当双击视窗时,它将实现以下功能: 改变原来视窗显示的内容和变量的值; 改变主框架窗口和子框架窗口的标题; 改变状态条的内容; 增加一个菜单的选项; 变化工具条图标。 运行AppWizard,产生一个多文档的名称为Test的工程。 为工程加入ID号为ID_MY_MENU的资源; 为CTestDoc类增加成员变量CString TestText; class CTestDoc : public Cdocument { public: CString TestText; }; BOOL CTestDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; TestText="初次进入,未有双击事件!";//初始化TestText; return TRUE; } void CTestView::OnDraw(CDC* pDC) { CTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDC->TextOut(5,5,pDoc->TestText); } 用ClassWizard为CTestView类增加处理鼠标左键双击事件的函数; void CTestView::OnLButtonDblClk(UINT nFlags, CPoint point) { CView::OnLButtonDblClk(nFlags, point); //CTestDoc 的成员变量TestText被重新赋值! CTestDoc* pDoc = GetDocument(); pDoc->TestText="双击事件发生,变量TestText被重新赋值!"; InvalidateRect(NULL,TRUE); //变化子框架窗口的标题 CWnd* pParent= GetParentFrame(); pParent->SetWindowText("双击事件发生,变量TestText被重新赋值!这是在子窗口!!"); //变化主框架窗口的标题 AfxGetApp()->m_pMainWnd->SetWindowText("双击事件发生,变量TestText被重新赋值!这是在主窗口!!"); //变化状态条的内容 CStatusBar* pStatus=(CStatusBar*) AfxGetApp()->m_pMainWnd->GetDescendantWindow(AFX_IDW_STATUS_BAR); if (pStatus) pStatus->SetPaneText(0, "双击事件发生,变量TestText被重新赋值!这是在状态条!!"); //插入新的菜单项目ID_MY_MENU,标题为新菜单 CMenu* pMenu; pMenu=AfxGetApp()->m_pMainWnd->GetMenu(); pMenu->InsertMenu(-1,MF_BYCOMMAND,ID_MY_MENU,"新菜单"); AfxGetApp()->m_pMainWnd->DrawMenuBar(); //变化工具条 CToolBar*pTool=(CToolBar*)AfxGetApp()-> m_pMainWnd->GetDescendantWindow(AFX_IDW_TOOLBAR); pTool->SetButtons(NULL,8); pTool->SetButtonInfo(0,ID_FILE_NEW,TBBS_BUTTON,0); pTool->SetButtonInfo(1,ID_FILE_OPEN,TBBS_BUTTON,1); pTool->SetButtonInfo(2,ID_FILE_SAVE,TBBS_BUTTON,2); pTool->SetButtonInfo(3,ID_SEPARATOR,TBBS_SEPARATOR,4); pTool->SetButtonInfo(4,ID_EDIT_CUT,TBBS_BUTTON,4); pTool->SetButtonInfo(5,ID_EDIT_COPY,TBBS_BUTTON,5); pTool->SetButtonInfo(6,ID_EDIT_PASTE,TBBS_BUTTON,6); pTool->SetButtonInfo(7,ID_SEPARATOR,TBBS_SEPARATOR,4); }