消息驱动运行中发生的各种事件(鼠标键盘输入,各种状态的改变等),以消息的形式通知Windows系统Windows系统接收消息,提交给发生事件的应用程序应用程序的窗口处理函数负责处理响应收到的消息处理完成后继续等待下一个消息API application programming Interface SDK software Development kit 事件是用户对计算机操作的动作或程序中某个对象的状态发生的变化,每个事件对应一个消息,即每个事件发生的效果是产生消息消息是描述事件发生的信息事件驱动程序执行的顺序不是事先规定的,而是由事件的发生来控制在程序执行过程中,当某个对象的状态发生变化,或有外部输入等情况发生,则产生相应的事件当事件产生时,系统会发出特定的消息编写程序时可以对这些消息做出反应,也可以不做出;若要做出反应(即响应消息),则把响应此消息的程序写在与此消息相关联的函数中在程序执行时,一旦产生了一个消息,会调用与此消息相关联的函数窗口是Windows应用程序基本的操作单位,是应用程序与用户之间交互的接口,也是系统管理应用程序的基本单位消息传输事件发生,产生消息消息保存到消息队列分配给应用程序消息队列消息循环提取消息窗口函数响应消息MFC Microsoft foundation class MFC应用程序框架提供了一般应用程序需要的全部面向对象软件组件的集成集合MFC程序结构基于框架窗口的应用程序(早期的MFC)程序运行管理、窗口及数据管理分开两部分,与SDK程序类似基于文档/视图的应用程序单文档应用程序(重点)程序运行管理、窗口管理、交互管理、数据管理分开基于对话框的应用程序程序运行管理、对话框管理分开目前的MFC应用程序都采用文档/视图结构,把原来窗口框架类的工作分开窗口框架类管理窗框视图类(即视窗类)管理数据显示、接收用户输入文档类负责数据管理文档视图架构的思想数据嵌入文档中,利用文档的架构管理文档与视图通信,使数据在视图中显示视图显示数据,并与用户交互视图放入窗口中文档模板类对象管理上述对象协调工作CDocument是负责管理数据的类应用程序中的文档类是这个类的派生类作用数据管理程序员应将用户的实际数据对象内嵌在自己的文档类中需要与自己的视图类通信在程序中实现CDocument的派生类,以便嵌入数据对象,并改写成员函数实现对数据的处理用于派生应用程序的视图类CView 作用处理与用户的交互显示文档类中的数据接收用户输入(例如鼠标操作)通常要改写视图类的成员函数OnDraw或OnPrint,实现数据显示框架自动调用OnDraw函数WM_PAINT消息OnPaint()OnDraw() 菜单及响应利用菜单编辑器修改IDR_MAINFRAME 菜单资源在相应的类中为新菜单项映射消息COMMAND单击或用快捷键选中时生产UPDATE_COMMAND_UI上一级菜单显示前生产用于控制菜单状态编写新菜单项的消息处理函数快捷键在菜单项标题后面加“(&字母)”菜单动态为要添加的菜单项定义一个宏(例如ID_MENU1)用CWnd::GetMenu( )获得指向菜单条的指针(如果在子菜单上添加,应用CMenu::GetSubMenu()获得该菜单的指针)为菜单项手工映射消息处理函数在适当的地方调用InsertMenu或AppendMenu添加菜单项调用CWnd::DrawMenuBar()函数重画菜单动态删除菜单项与上面类似(使用DeleteMenu函数)动态创建菜单项用函数BOOL CreateMenu( );获得新菜单句柄,再用此句柄当作AppendMenu函数的第2个参数(需进行(UTIN)强制类型转换)通常用于创建弹出式菜单的顶级(不需映射消息)快捷菜单建立菜单如果菜单已经存在,且功能齐全,只需确定弹出方式即可也可以另加一个菜单资源,此法可使菜单条中不显示快捷菜单关联类(对于新加菜单)把此菜单资源关联到视图类上选中此菜单资源的情况下打开类向导,选视图类影射消息并编写消息处理函数选择弹出方式可在视图类的WM_CONTEXTMENU消息(鼠标右键单击客户区时产生)处理函数中弹出Windows系统有一个存放消息的队列每个应用程序也有一个消息队列Windows系统先将收到的消息存放在系统队列中,然后再分发到相应的应用程序队列中应用程序则从自身的队列中获取消息并进行处理类的消息响应一个类要响应多种消息对于每一种消息最重要的是知道是哪个消息:消息的标识(ID 身份证)这个消息对应的响应函数是什么(函数的起始地址)解决的办法建立一个结构体数组(消息映射表)一行(一个数组元素)是一个消息的信息每行至少包含消息的标识(ID)指向响应函数的指针消息的响应当收到消息后,根据消息ID在表中查找,找到后调用对应的消息处理函数消息路由当一个类收到消息后,先在自己的消息映射表中搜索,搜索到就执行相应的消息处理函数,然后结束消息处理过程未搜到,则到上一层基类中搜索,依此类推如果都未搜到,则交给系统默认的窗口处理函数去处理消息种类窗口消息命令消息控件通知消息实现消息映射消息映射的要点为每个要响应的消息建立一个处理函数为每个能够响应消息的类建立一个结构类型的数组(消息映射表)并填写这个数组编写每个消息处理函数的代码声明消息处理函数afx_msg void 函数名( ); //有些有返回值或参数(特别是窗口消息)对于窗口消息格式:ON_消息ID( )对于命令消息格式:ON_COMMAND(产生消息对象的ID,函数名)对于控件通知消息格式:ON_通知码(控件ID,函数名)在类的实现文件中为每个消息处理函数编写代码用户自定义消息何时用当程序运行到某个节点,需要发出一个消息要做的事:需要有一个消息标示(ID)需要一个消息处理函数把消息ID和消息处理函数填写到类的消息映射表中为消息处理函数编写代码在需要发出消息的程序代码处发出该消息不能使用类向导用户自定义消息方法定义一个消息ID(宏)声明消息处理函数在类的声明文件中(.h文件)afx_msg void OnMyMessage( ); 说明:根据需要决定是否有返回值、参数填写消息映射表编写消息响应函数在类的程序文件中(.cpp文件)void CMyMsgView::OnMyMessage( ) {……}在需要发出消息的地方用CWnd ::SendMessage发出消息Message ——消息ID也可用CWnd ::PostMessage函数(参数相同,返回值类型:BOOL)区别将消息放置在消息队列的末尾,不等待窗口处理该消息就直接返回SendMessage():发送消息,且一直等待窗口处理完该消息之后才返回对话框对话框是一种资源,使用时要用一个CDialog类的派生类与它相关联CDialog类是CWnd类的派生类,所以对话框是一个窗口CDialog类封装了对话框常用操作的功能函数对话框是窗口的集合,上面放置各种控件控件所对应的类是CWnd类的派生类控件是对话框窗口的子窗口种类模式对话框对话框弹出后,只能进行对话框操作,不能进行其他窗口的操作,直到本对话框被关闭无模式对话框对话框弹出后,可以进行其他窗口的操作(可以与其他窗口切换操作)模式对话框创建用对话框编辑器设计对话框(包括上面的控件)为对话框关联一个类(利用类向导)在相应打开对话框的类里面声明一个对话框类对象调用对话框对象的DoModal()成员函数来创建对话框,关闭对话框后对话框对象自动销毁CMyDlg dlg; dlg.DoModal( );可以根据DoModal()函数的返回值判断对话框关闭方式IDOK 表示按“确定”按钮(ID是IDOK)关闭IDCANCEL表示按“取消”按钮(ID是IDCANCEL )关闭CPasswordDlg dlg; if(dlg.DoModal( )==IDOK){ if(dlg.m_Password == "123456")......Else }非模式对话框创建、用Create函数创建调用ShowWindow函数显示对话框CMyDlg *pDlg; //声明对话框类指pDlg=new CMyDlg ; //动态创建对象pDlg->Create(对话框ID, this); //创建对话pDlg->ShowWindow(SW_SHOW); //显示对话框…//其他操作delete pDlg; //释放内存空间(对话框销毁)创建基于对话框的应用程序:用AppWizard创建应用程序用对话框编辑器设计界面(添加控件)用ClassWizard使控件与对象的关联用ClassWizard进行消息映射控件控件是对话框上或窗口上的子窗口每一类控件有自己的类,控件是该类对象所有控件都是窗口,所有控件类都由CWnd类派生使用对话框编辑器可以很方便地添加和删除控件控件产生“控件通知消息”,由它们的父类(承载窗口,例如对话框类)接收控件通知消息的处理函数是其父类的成员函数访问控件数据把控件当作窗口处理使用GetDlgItem(控件ID)获得指向控件的指针用GetWindowText获得该控件中的文本用SetWindowText设置该控件中的文本本方法不需要为控件关联变量对于有标题的控件(3种按钮、分组框等)处理的是标题对于编辑框、组合框、静态文本处理的是框中的文本CWnd *pEdit1=GetDlgItem(IDC_EDIT1);CString str;pEdit1->GetWindowText(str);pEdit1->SetWindowText("");pEdit2->SetWindowText(str);文档视图结构中类之间的访问应用程序类(由CWinApp派生)封装了初始化、创建窗口、消息循环等功能可以在虚函数InitInstance( )中添加程序代码窗口框架类CMainFrame(由CFrameWnd派生)负责标题栏、菜单、工具栏、状态栏的管理文档类(由CDocument派生)负责组织、管理数据视图类(由CView派生)负责与用户交互,显示文档类管理的数据用GetDocument( )返回文档类的指针通常在OnDrow( )函数中显示数据获得应用程序类对象地址在程序的任何地方,可以使用函数AfxGetApp()返回本程序的应用程序类对象的地址CWinApp* AfxGetApp( ); CWinApp是应用程序类的基类获得主框架类对象地址CWinApp类由CWinThread类派生CWinThread类有一个成员变量CWnd * m_pMainWnd指向应用程序线程主窗口对象对于基于文档视图的程序,指向主框架窗口对于基于对话框的程序,指向对话框窗口你的应用程序类继承了m_pMainWnd利用m_pMainWnd可以可以获得主框架窗口(或对话框窗口)对象的地址注意m_pMainWnd是CWnd类指针,应把它强制转换为你的主框架类指针(或对话框类指针)CMainFrame *m_p=(CMainFrame*)AfxGetApp()->m_pMainWnd;视图类中可以调用CWnd类函数获得其父框架类对象地址CFrameWnd* CWnd:: GetParentFrame( )在主框架类中获得视图类对象的地址对于SDI程序调用函数:CView *CFrameWnd::GetActiveView( )返回当前视图类对象的地址(应进行强制类型转换)若无当先视图,返回NULL对于MDI程序主框架窗口中无视图每个子框架窗口中才有视图要先找到当前框架窗口CMDIChildWnd* CMDIFrameWnd:: MDIGetActive( BOOL*pbMaximized = NULL ) const;或CFrameWnd* CFrameWnd::GetActiveFrame()再获得它的当前视图CView *CFrameWnd::GetActiveView( )在视图类中获得文档类对象的地址CDocument* CView::GetDocument( )获得其父框架类对象地址CFrameWnd* CWnd:: GetParentFrame( )在文档类中获得视图对象的地址先获得视图列表中第一个课件视图的位置使用文档类函数用返回的位置信息(POSITION 类型)获得该视图对象的地址使用文档类函数返回rPosition 所表示的视图的地址rPosition 变为下一个视图的位置,无下一视图rPosition为NULL POSITION pos = GetFirstViewPosition();while (pos != NULL) { CView* pView = GetNextView(pos); pView->UpdateWindow(); }文档与视图的相互作用在文档类中,当数据发生变化,要通知所有视图进行更新,用函数void UpdateAllViews( …); //参数见MSDN当CDocument::UpdateAllViews函数被调用时,会自动调用视图类函数:virtual void CView::OnUpdate(…); //参数见MSDN当应用程序启动时,或用户选择“新建”或“打开”菜单项时会自动调用视图类函数:virtual void CView::OnInitialUpdate( );可重载此函数初始化视图,以便适应新文档的需要当用户选择“新建”菜单项时,框架将先构造一个文档对象,然后调用文档类函数:virtual BOOL CDocument::OnNewDocument( ); 通常,用此函数设置文档数据程艳的初始值GDI(Graphics Device Interface)是Windows操作系统的重要部分,提供了绘图的基本工具,如画点、线、多边形、位图、文本输出等,负责Windows环境下的图形输出和图形模式下的文本输出DC(Device Context)为实现设备无关性,应用程序一般不直接向物理设备输出,而是面向一个虚拟逻辑设备,即DCDC是Windows 定义的一个数据结构,包含了向设备输出时所需要的绘图属性使用GDI函数之前,必须先创建一个DC设备环境类CDCMFC 对DC进行了封装,即CDC类CDC的基类是CObject 封装了GDI的所有绘图函数可利用CDC类对象在显示器和非显示设备(如打印机等)上输出CDC派生了几种不同的设备环境类CClientDC窗口客户区(窗口中客户可用部分)设备环境坐标(0,0)一般指客户区左上角绘图时可先调用CWnd类的GetClientRect()函数获得客户区的大小CWindowDC整个窗口的设备环境,可以在窗口的任何位置绘图坐标(0,0)指该窗口的左上角绘图时可先调用CWnd类的GetWindowRect()函数获得窗口在屏幕坐标系中的外边框坐标CPaintDC可对客户区和非客户区进行操作主要用于响应窗口重绘消息(WM_PAINT)的绘图DC在OnDraw函数中绘图void OnDraw(CDC * pDC);是使用应用程序向导生成SDI、MDI应用程序时视图类的成员函数由WM_PAINT消息处理函数OnPaint调用可以利用参数pDC 在此函数中绘图使用OnDraw函数绘图的好处窗口每次重绘,都可显示最新图形若函数参数中没有CDC参数,则要自己创建CDC对象或指针,并用this对其初始化CClientDC dc(this); dc.TextOut(20, 20, “输出文字");若不是在函数所属的类所对应的窗口输出,则应先获得输出窗口的DC,再进行输出例:在ID为IDC_BUTTON1的按钮的左上角输出“按钮”CButton * pBtn; pBtn =(CButton *)GetDlgItem(IDC_BUTTON1); CDC *pDC=pBtn->GetDC();pDC->TextOut(0,0,"按钮"); ReleaseDC(pDC);视图类的OnDraw 函数当窗口有任何变化时会产生WM_PAINT消息,它的消息处理函数是OnPaintOnPaint会调用OnDraw函数在窗口中画图的代码一般都放在OnDraw函数中(一般不要修改OnPaint函数),以保证在窗口发生变化时,仍然可以显示已经画好的图(即重画一遍)为在其他函数中也可以画图,一般在该函数中调用CWnd类的Invalidate函数,迫使WM_PAINT消息产生清除void Invalidate( BOOL bErase = TRUE ); 功能:使客户区无效(因此需要更新)bErase ——更新时是否擦除背景内容CDC类GDI的绘图工具GDI提供了很多绘图工具,称为GDI对象(图形对象)用户申请设备环境绘图时,使用的是默认的绘图工具,若要使用不同的绘图工具绘图,需要重新设置或定义绘图工具绘图工具与设备环境的关系绘图工具也称图形对象,有多种,例如画笔、笔刷、字体等等图形对象决定绘图的效果,DC决定绘图的形状和绘图的位置每种图形对象有一个“当前”对象,“当前”对象影响对DC的输出结果,要想改变某次绘图的效果,应在这次绘图之前改变相应的“当前”图形对象MFC把不同的绘图工具封装到不同的类,它们基类都是CObject的子类CGdiObject,而不是CDCCPen(画笔类)CBrush (笔刷类)CFont(字体类)CBitmap(位图类)绘图int color=RGB(red,green,blue);CPen newPen(PS_SOLID,width,color);CPen *oldPen=pDC->SelectObject(&newPen); CDC绘图CPoint MoveTo( int x, int y ); CPoint MoveTo( POINT point );功能:把当前位置设置为(x、y)或point 处返回:原来位置的坐标获得当前位置CPoint GetCurrentPosition( ) const;画直线BOOL LineTo( int x, int y );BOOL LineTo( POINT point );功能:以当前位置为起点,函数参数位置为终点画一条直线,并把终点作为新的当前位置返回:失败——0,否则为非0画椭圆BOOL Ellipse( int x1, int y1, int x2, int y2 ); BOOL Ellipse( LPCRECT lpRect );功能:画椭圆,参数确定椭圆外接矩形的坐标画矩形BOOL Rectangle( int x1, int y1, int x2, int y2 ); BOOL Rectangle( LPCRECT lpRect );功能:画矩形,参数确定矩形的坐标输出文本virtual BOOL TextOut( int x, int y, LPCTSTR lpszString, int nCount );BOOL TextOut( int x, int y, const CString& str ); x、y ——文本起始点坐标lpszString ——指向文本的字符指针nCount ——文本的字符数str ——存放文本的对象设置、获得文本颜色virtual COLORREF SetTextColor( COLORREF crColor ); 返回:原来的文本色COLORREF GetTextColor( ) const; 返回当前文本色设置、获得背景色virtual COLORREF SetBkColor( COLORREF crColor ); 返回原来的背景色COLORREF GetBkColor( ) const; 返回当前背景色设置、获得背景模式int SetBkMode( int nBkMode ); 返回原来的背景模式nBkMode ——OPAQUE (默认)显示背景TRANSPARENT :背景透明int GetBkMode( ) const;画折线图int k; CPoint Origin(100,500); // 设置坐标原点for(k=0;k<=600;k+=20){ // 画垂直坐标线pDC->MoveTo(Origin.x+k,Origin.y); pDC->LineTo(Origin.x+k,Origin.y - 400); }for(k=0;k<=400;k+=20){ // 画水平坐标线pDC->MoveTo(Origin.x,Origin.y-k); pDC->LineTo(Origin.x+600,Origin.y - k) } CPoint Point(Origin.x,Origin.y - pnbuf[0]); // 1月数据为起点pDC->MoveTo(Point);CPen pen(PS_SOLID,2,RGB(255,0,0)); pDC->SelectObject(&pen);for(k=1;k<12;k++){Point.x+=50;Point.y=Origin.y - pnbuf[k];pDC->LineTo(Point); // 到下一月数据点画线pDC->Ellipse( Point.x-3 , Point.y-3, Point.x+3 , Point.y+3 ); // 在数据点画个小圆修改字体:CFont cf; cf.CreateFontIndirect(&longf); //按参数创建新字体CDC *pDC=m_Show.GetDC();pDC->SelectObject(&cf); //在设备环境中使用字体pDC->TextOut(50,10,"在控件上输出文字"); ReleaseDC(pDC);在OnInitDialog函数中添加代码:CFont *cf= this->GetFont(); //获得本对话框的默认字体if ( cf ){ cf->GetLogFont(&m_longf); } // 默认字体信息存入m_longfm_FontSize=abs(m_longf.lfHeight) ; //设置并显示默认字号UpdateData(false);组合框消息处理函数添加代码:// UpdateData();int nIndex=m_FontName.GetCurSel(); //获得选中项的索引CString strFont;m_FontName.GetLBText(nIndex,strFont); //获得该索引项的文字内容strcpy(m_longf.lfFaceName,strFont); //以选中的文字设置字体MySetFont(m_longf);通用对话框颜色对话框CColorDialog类字体对话框CFontDialog类文件对话框CFileDialog类文件对话框:void CAView::OnLButtonDown(UINT nFlags, CPoint point){CClientDC dc(this);CString FilePathName; // 存放文件名和路径CFileDialog dlg(TRUE);if(dlg.DoModal()==IDOK)FilePathName=dlg.GetPathName();dc.TextOut(20,20,FilePathName);文件:打开已有文件和新建文件都要创建一个文件对象(CFile 类对象)使用CFile 类的构造函数 使用CFile 类的Open 函数对文件进行操作要使用CFile 类的成员函数 Read 、Write 函数按字节长度读写 写字符串时无法与后面的数据区分 读字符串时需指定读入的长度⏹ 写字符串 读字符串 int n;int n;CString cstr(“test”); CString cstr;char ch[80];n=cstr.GetLength(); file.Read(&n, sizeof(n)); file.Write(&n, sizeof(n));file.Read(ch, n); file.Write(cstr, n);ch[n]='\0'; cstr=ch;文件指针 void SeekToBegin( ) // 定位到文件头 DWORD SeekToEnd( ) //定位到文件尾,返回文件长度获得文件相关信息virtual DWORD GetLength( ) const 返回文件长度 virtual CString GetFileName( ) const 返回文件名 virtual DWORD GetPosition( ) const 返回文件指针位置 MFC 把缓冲区中数据强制写入文件virtual void Flush( )MFC 异常类CException 类 CObject 类的派生类CException 类的子类(派生出的类) CFileException 类 提供文件输入输出时的异常状态CArchiveException 类提供串行化的异常状态⏹ 异常处理程序分为2部分⏹ try 语句块 ⏹ catch 语句块⏹ 用throw 语句“抛出”异常⏹ throw 表达式⏹ 抛出异常的语句放在try 块里⏹ 产生异常后的过程⏹ 跳出try 块,用throw 后面表达式的类型依次与catch 中的类型比较 ⏹ 执行类型匹配的catch 块⏹ 若没有匹配的catch 块,则向上层调用函数传递异常,直到遇到匹配的catch 块⏹ 若程序中没有匹配的catch 块,则程序终止try{可能出现异常的语句块 }catch(异常类型声明1) {异常处理语句块1 }catch(异常类型声明2) {异常处理语句块2 } …catch(异常类型声明n) {异常处理语句块n }void CEx8_1Doc::OnFileSave () {char *pFileName="test.dat";CFile file(pFileName,CFile::modeCreate | CFile::modeWrite); try{ file.Write(&m_pos,sizeof(m_pos)); // 写坐标数据个数file.Write(m_mousePoint,sizeof(m_mousePoint));file.Close();void CEx8_1Doc::OnFileOpen(){ char *pFileName="test.dat";CFile file(pFileName,CFile::modeRead);try{file.Read(&m_pos,sizeof(m_pos));file.Read(m_mousePoint,sizeof(m_mousePoint));file.Close();}catch(CFileException *e){CString estr;estr.Format("错误原因:%d",e->m_cause);AfxMessageBox(estr);file.Abort(); e->Delete();}。