可视化编程_mfc_第1页
可视化编程_mfc_第2页
可视化编程_mfc_第3页
可视化编程_mfc_第4页
可视化编程_mfc_第5页
已阅读5页,还剩181页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

可视化编程,参考书,深入浅出MFC MFC Windows 程序设计,一、VC+ 基础,1、类与对象 2、继承及其思考 3、this指针 4、虚拟函数 5、静态成员 6、C+程序的生与死,1 面向对象编程的基本概念,对象 类: 属性,也称为成员变量 方法,也称为成员函数 访问权限: public protected private,2 基类与派生类:谈继承,人们习惯与把相同的性质抽取出来,成立一个基类(base class),再从中衍化出派生类(derived class)。 比如:(代码见shape.cpp),2 基类与派生类:谈继承(续),代码的事实与问题: 1.所有类都由CShape派生下來,所以它们都自然而然继承了CShape的成員,包括变量和函数。也就是說,所有的形状类都暗自具备了m_color变量和setcolor函数。这里所谓暗自(implicit),意思是无法从各派生类的声明中直接看出来。 rect1与rect2各自有自己的m_color,但是共享用相同的CRect:setcolor函数,那么同一个函数如何处理不同的数据?,基类与派生类:谈继承(续),代码的事实与问题(续): 3、既然所有的类都有display操作,那么把它提升到CShape中去,然后再继承如何?不好,因为display函数应该因不同的形状而操作不同。 4、如果display不能提升到基类去,就不能够以一个循环来完成以下动作: CShape* shapes4= ,2 基类与派生类:谈继承(续),代码的事实与问题(续): 5、Shape只是一个抽象的概念,以下的操作不符合生活规则: CShape shape; shape.setcolor(.);,3 this指针,解决问题2:如何同一个函数调用处理不同的数据,答案是: 成员函数有一个隐藏的参数,名为this指针,当调用 rect1.setcolor(2); rect2.setcolor(3); 时,编译器为你做出来的代码是 CRect:setcolor(2,(CRect*) 而在源代码的setcolor函数被编译器编译过后,实际上是: void setcolor(int color,(CShape*)this) this-m_color=color,4 虚拟函数与多态,编代码完成以下示意功能。,4 虚拟函数与多态(续),(在未实用虚拟函数时:) 如果你以一个“基类的指针”指向“派生类的对象”,那么经由该指针只能够调用基类所定义的函数 如果以一个“派生类的指针”指向“基类之对象”,必须先做明显的转型操作(explicit cast)。这种做法很危险,不符合生活经验,也会给程序员带来困惑。 如果基类和派生类都定义了相同名称的成员函数,那么通过指针调用成员函数时,到底调用哪一个函数,必须视该指针的原始类型而定,而不是视指针实际的对象的类型而定。与第1点其实意义相通。 解决办法:virtual,4.2 虚拟函数与一般化,“一般化”之所以重要,在于它可以把现在的、未来的情况统统纳入考虑。子类只要修改父类的相应的虚拟函数,在调用时,自然会根据子对象的类型来调用合适的函数。,4.3 类与对象大解剖,4.3 类与对象大解剖(续),见代码CO.cpp,4.4 纯虚类(抽象类),virtual func()=0; 抽象类中的虚拟函数不打算被调用,我们不应该定义它。 抽象类不能产生出对象实例,但是我们可以拥有指向抽向类的指针,以便于操作抽象类的各个派生类。,5 静态成员(变量与函数),static static成员变量不属于对象的一部分,而是类的一部分,所在程序可以在还没有产生任何该类的对象时就处理此种成员变量,但必须先初始化它。 应该在类以外的任何位置设定其初值,例如在任何函数之外。如: class SavingAccount private: . static double m_rate; double SavingAccount:m_rate = 0.0075;,5 静态成员(续),注意: 即使m_rate是private数据,设定static成员变量的初值时,不受任何存取权限的束缚。 static成员变量的类型也出现在初值设定中,因为这是一个初值设定操作,不是一个赋值操作。事实上,static成员变量是在这个时候才定义出来的,而不是类申明时。 由于static成员函数不需要借助任何对象就可以被调用执行,所以编译器不会为它暗加一个this指针。也因为如此,static成员函数无法处理类之中的non-static成员变量。,5 静态成员(续),static成员的调用方法(假设m_rate已经改为public类型): SavingAccount:m_rate = 0.075; 或: SavingAccount myAccount; myAccount.m_rate = 0.075;,6 C+程序的生与死:兼谈构造函数与析构函数,new 与 malloc 的区别 构造函数与析构函数 当一个程序中,既又基类,又在派生类;既有局部对象,又在static对象,又有全局对象,还有new产生的变量时,它们的构造函数与析构函数调用顺序如何?,6 C+程序的生与死:兼谈构造函数与析构函数,总结,当派生类的对象诞生时,构造函数的执行是由最基本类至最尾端类;当对象要销毁时,析构函数的执行则是反其道而行之。 对于全局对象,程序一开始构造函数就先被执行(比main更早);程序即将结束时析构函数被执行。 对于局部对象,诞生时,构造函数被执行,当离开其活动范围时,被析构。 对于静态对象,当对象诞生时,构造函数被调用,当程序将结束时,此对象被析构。 对于new产生的对象,诞生时,被构造,delete时被析构。,VC程序调试,断点+watch afxDump:输出结果到调试窗口 afxDump“the Value = ”i“n”; 调试代码debug.cpp,二、Windows程序设计基础,1、Windows编程模型:以消息为基础 2、传统的Windows编程方式,SDK风格简介 3、MFC编程风格及剖析,Windows编程模型:以消息为基础,操作系统捕捉键盘、鼠标等输入设备的输入,以消息形式(一种数据结构)进入程序之中。,MSG,typedef struct tagMSG HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; MSG;,常用的Windows消息,WM_CHAR 从键盘输入字符 WM_COMMAND 菜单或控件的消息 WM_CREATE 生成窗口 WM_LBUTTONDOWN 鼠标左键按下 WM_LBUTTONUP 释放鼠标左键 WM_MOUSEMOVE 移动鼠标 WM_PAINT 窗口需要重新绘制 WM_QUIT 应用程序将结束 WM_SIZE 窗口尺寸被调整 ,不管是什么样的消息,从哪里来,对于应用程序来说,只要做以下动作就可以了。 MSG msg; while(GetMessage( ,Windows程序本体与操作系统之间的关系,Windows SDK 程序框架,1、进入点WinMain(.) 2、创建一个新窗口CreateWindow 3、消息循环 4、消息响应函数,MFC代码的困惑,1、程序进入点WinMain在哪里? 2、消息循环在哪里 3、 DECLARE_MESSAGE_MAP () BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd) ON_WM_PAINT () END_MESSAGE_MAP () 是什么意思?,WinMain在哪里,见WINMAIN.CPP的int AFXAPI AfxWinMain(.)。MFC已经将该函数编好,并且程序编译的时候自动连接进去。 int AFXAPI AfxWinMain(.) CWinThread* pThread = AfxGetThread();/=AfxGetApp(),见THRDCORE.CPP CWinApp* pApp = AfxGetApp(); . pApp-InitApplication() . pThread-InitInstance() . nReturnCode = pThread-Run()/THRDCORE.CPP的int CWinThread:Run() . ,消息循环,int CWinThread:Run() . do / pump message, but quit on WM_QUIT if (!PumpMessage() . while (); ,消息循环(续),BOOL CWinThread:PumpMessage() . if (!:GetMessage( ,三个奇怪的宏,一张巨大的网,三个奇怪的宏,一张巨大的网(续),三、对话框,Windows程序的开发流程,最常用的控件,对控件的理解: 控件是可以处理与发送消息的对象。首先,控件是一个对象;其次控件可以处理消息(自身处理消息很少用)与发送消息(当自身状态发生改变的时候向父窗口发送消息,由父窗口负责消息响应)。 Static Text Edit box Button Check box Combo box List box Group box,与对话框中控件相互作用,方法1 CWnd* pWnd = GetDlgItem (IDC_CHECK); pWnd-EnableWindow (TRUE); 方法2 通过ClassWizard添加Control类型变量,对话框数据交换与数据校验,MFC提供了DDX(X表示eXchange)机制,允许程序员实现设定控件与变量之间的对应关系,并正确的传递数据。 使用UpdateData(TRUE):控件的值传给变量 使用UpdateData(FALSE):变量的值传给控件 对话框退出时,控件里的值自动传到对应的变量上去。 MFC提供了DDV(V表示Validation)机制,保证输入的数据在你要求的范围之内。 借助ClassWizard方便的完成这些工作。,Static Text,显示文字 如果其ID为IDC_STATIC,则不能对其进行其它操作。如果想对其进行操作(如改变显示的文字),则需要改变其ID。,Edit Box,可以输入string、整数、实数等 可以添加消息ON_EN_CHANGE的响应函数,在Edit内数据发生变化时调用。 可以输入Password,button,有四种状态 响应BN_CLICKED消息,Check Box,响应消息BN_CLICKED CButton:GetCheck(),List Box,有三种类型: Single,只能选一行。 Multiple,在Ctrl的帮助下可以选多行 Extended,在shift的帮助下可以选一个范围 通过AddString() 可以添加其对应的string变量 选择数据变化时,触发消息LBN_SELCHANGE 多行可用以下代码获取选择的数据 int count = listbox-GetSelCount(); int* itemIndex = new intcount; int itemselected = listbox-GetSelItems(count,itemIndex); . delete itemIndex; /得到某一个选择的数据的字符串 char data256; listbox-GetText(itemIndexi,data);,Combo Box,Editbox 与下拉列表的组合 可以通过设置其属性来修改其数据,也可通过代码手工修改: CComboBox* combox = (CComboBox*)GetDlgItem(IDC_COMBO1); combox-AddString(“Item1“); combox-AddString(“Item2“); combox-SetCurSel(5); CBN_SELCHANGE消息响应 CComboBox* combobox = (CComboBox*)GetDlgItem(IDC_COMBO1); int sel = combobox-GetCurSel(); char data256; combobox-GetLBText(sel,data);,单选钮与Group Box,groupbox与单选纽一点关系都没有,只是为了让使用者更容易理解。 第一个单选钮被选为group属性时,以后连续的单选纽都被认为为这一组的,直到有一个单选纽又被选为group,则又开始了新的一组。,TabOrder及快捷键,通过菜单Layout-Tab Order设置用户使用Tab键在控件间移动时的移动顺序。(控件必须含有样式TABSTOP) 通过设置控件名称加上“&”指定快捷键 通过指定DEFAULTBUTTON指定默认按钮,对话框分类,模式对话框 在清除对话框之前,模式对话框使它所属的窗口一直处于无效的状态。 无模式对话框 无模式对话框即使在显示时,它的所有者也能被激活。,创建模式对话框步骤,1、创建一个对话框模板,描述对话框和其中包含的控件。 构造一个CDialog类,并封装该对话框模板。 建立该类的一个对象,并调用CDialog:DoModal显示对话框。 If(dlg.DoModal()=IDOK) 关闭对话框(在对话框内)调EndDialog(int nResult);其中nResult包含了告诉DoModal()调用的结果,无模式对话框,与模式对话框的区别: CDialog:DoModal() CDialog:Create() EndDialog DestroyWindow 模式对话框通常在栈上实例化,所以析构是自动实现的。而无模式对话框通过new实例化,所以对话框对象不会过早地被清除。如果要确保清除对话框时删除无模式对话框对象,一种方法是在派生类的对话框类中覆盖CDialog:PostNcDestroy并执行delete this语句。,步骤:,建立一个对话框资源及相应的类。 修改对话框中默认的OnOK及OnCancel函数,使其不调用默认的函数,而是改为DestroyWindow() 创建并显示对话框 CMyDLg* dlg = new CMyDLg(); dlg-Create(IDD_DIALOG1); dlg-ShowWindow(SW_SHOW);,属性表,属性表的功能都被封装在一对MFC类中:CPropertySheet和CpropertyPage。 CPropertySheet代表属性表自身,是从CWnd派生而来。 CpropertyPage代表属性表的页,是从CDialog派生而来。,创建属性表的步骤,针对属性表的每一页创建一个对话框模板,定义页的内容和特性。将对话框标题设成你希望在属性表页上方标签中显现的标题。 针对属性表的每一页由CpropertyPage派生出一个类似对话框的类,其中包含通过DDX或DDV与页中控件相联系的公用数据数据成员(将IDOK及IDCANCEL按钮去掉,因为CpropertySheet 有自己的相应按钮) 。 由CpropertySheet派生出一个属性表的类。将属性表类和第二步中得到的属性表页类实例化。在构造函数中利用CpropertySheet:AddPage将各页按期望中的显示顺序添加到属性表中。 调用属性表的DoModal函数将属性表显示在屏幕上(也可以像对话框那样建立无模式的属性表),处理Apply按钮,1、激活Apply按钮 在Page类中调用SetModified(TRUE) 2、处理Apply按钮 手工为ID_APPLY_NOW按钮的BN_CLICKED消息添加一个消息响应函数。 在函数中做如下事情: GetActivePage()-UpdateData( TRUE ); for( int i = 0; i SetModified( FALSE ); 注意,只有活动属性页才需要调用UpdateData,当一页将要失效的时候(如从一页切换到另一页),MFC自动调用这一函数。,四、文档-视图 结构,1、文档视图结构简介 2、文档类简介 3、视图类简介 4、文档模板类简介,1、文档-视图结构,什么叫文档-视图结构 简单的说,与数据相关的部分由文档类负责,与数据显示的部分由视图类负责。 视图类的另一个重要作用是负责与使用者的交谈接口。 有什么好处 MFC已经把程序大结构完成了。模块与模块之间的消息传递路径以及各函数的功能都已确定好。这样就可以使程序员的精力放在真正的数据结构设计及数据显示操作上。,2.1、CDocument类,文档负责数据读取、存取以及其它的操作。 CDocument类本身只是一个空壳,我们需要从它派生一个数据自已的类,并在类中声明我们需要的变量,用以承载数据。 CDocument类已经为我们做好了一些重要的函数,其中包括与View类的“沟通”函数、文档存取等函数。,2.2 CDocument操作(非虚拟函数),表 主要的CDocument操作,2.3 CDocument可覆盖函数,表 主要的CDocument可覆盖函数,2.4 CDocument:Serialize(),何时被调用: 在打开文档时读取文件 在关闭文档时保存文件 如何用: CArchive:Read,CArchive:Write CArchive:GetFile获取CFile指针,3.1 CView类,视图类有两个用途: 提供文档的可视化表示 将用户输入(特别是鼠标和键盘消息)转换为操作文档数据的命令。 MFC还包含了一组CView类的派生类,用来完成不同功能的视图。,3.2 GetDocument,一个文档可以具有与其联系的多个视图,而一个视图只能属于一个文档。 CView类保存了m_pDocument数据成员,并将该指针提供给视图的GetDocument成员函数使用,用以标识出视图类所属的文档。 AppWizard为视图类生成源代码时,它覆盖了基类的GetDocument函数。其强制转换了m_pDocument为派生类指针。,3.3 CView可覆盖函数,表 主要的CView可覆盖函数,3.4 OnInitialUpdate与OnUpdate,在SDI中,视图与文档一样,只构造一次,重复使用。 在SDI中,每当文档被打开或创建时,都要调用视图的OnInitialUpdate() OnInitialUpdate()默认要调用OnUpdate() OnUpdate()的默认操作是使视图客户区无效并执行重绘。 在CView类的派生类中,如果重写了OnInitialUpdate(),需要要调用CView:OnInitialUpdate(),否则新文档被打开或创建时不会被更新。,3.5 CView:OnDraw,何时调用: 在WM_PAINT到来时(当视窗显示区域的一部分显示内容或者全部变为无效,以致于必须更新画面时,将由这个讯息通知程式。) 在文档被打印时 什么是CDC DC:Device Context,设备描述表。 在WM_PAINT到来时,DC指向屏幕设备 在文档被打印时,DC指向打印机设备,3.6 OnPaint()与OnDraw,WM_PAINT到来时会调用OnPaint()函数,此函数在CView中被定义。 WM_PRINT到来时会调用OnPrint()函数,此函数在CView中被定义。 两个函数都调用了OnDraw(),并传送不同的DC,分别代表屏幕设备与打印设备。,RUNTIME_CLASS(.),DECLARE_DYNCREATE(.) IMPLEMENT_DYNCREATE(.),4.1 文档模板对象,要打开一份文档,需要产生以下三个对象:文档类、视图类、以及作为视图类容器的框架类,这三个类是一个整体。 而这三个类由文档模板来管理,见代码C*App:InitInstance()。 文档模板接受三种类型的CRuntimeClass指针,于是每当使用者打开一份文件,文档模板就动态产生三个对象。,4.1 文档模板对象,CDocTemplate拥有三個成员函数,分別持有Document、View、Frame的CRumtimeClass指针,另有一个成员函数m_nIDResource,用來表示此Document显現时应该采用的UI界面。这四份资料应该在CMyWinApp:InitInstance函式构造CDocTemplate时指定之,成这构造函数的参数。当使用者欲打开一份文件(通常是借着【File/Open】或【File/New】命令项)时,CDocTemplate即可借由Document/View/Frame之CRuntimeClass指针进行动态生成。,4.1 文档模板对象(续),CWinApp拥有一个对象指针:CDocManager* m_pDocManager。 CDocManager拥有一个指针链表CPtrList m_templateList,用来维护一系列的Document Template。一个程序若支持两“种”文件类型,就应该有两份Document Templates,应用程序应该在CMyWinApp:InitInstance中以AddDocTemplate将这些Document Templates加入由CDocManager 所维护的链表之中。 CDocument有一个成员变量CDocTemplate* m_pDocTemplate,回指其Document Template;另有一个成员变量CPtrList m_viewList,表示它可以同时维护一系列的Views。 CFrameWnd有一个成员变量CView* m_pViewActive,指向当前活动的View。 CView有一个成员变量CDocument* m_pDocument,指向相关的Document。,模板、文档、视图、框架的关系,文档、文档模板、视图和框架类可以概括其联系为 (1)文档保留该文档的视图列表和指向创建该文档的文档模板的指针;文档至少有一个相关联的视图,而视图只能与一个文档相关联。 (2)视图保留指向其文档的指针,并被包含在其父框架窗口中; (3)文档框架窗口(即包含视图的MDI子窗口)保留指向其当前活动视图的指针; (4)文档模板保留其已打开文档的列表,维护框架窗口、文档及视图的映射; (5)应用程序保留其文档模板的列表。,一组函数让这些类之间相互可访问,举例,写一段代码,完成遍历文档模板、文档和视图的功能,CMyApp *pMyApp = (CMyApp*)AfxGetApp(); /得到应用程序指针 POSITION p = pMyApp-GetFirstDocTemplatePosition();/得到第1个文档模板 while (p != NULL) /遍历文档模板 CDocTemplate *pDocTemplate = pMyApp-GetNextDocTemplate(p); POSITION p1 = pDocTemplate-GetFirstDocPosition();/得到文档模板对应的第1个文档 while (p1 != NULL) /遍历文档模板对应的文档 CDocument *pDocument = pDocTemplate-GetNextDoc(p1); POSITION p2 = pDocument-GetFirstViewPosition(); /得到文档对应的第1个视图 while (p2 != NULL) /遍历文档对应的视图 CView *pView = pDocument-GetNextView(p2); ,MFC框架各部分指针获取方式,五、在窗体中绘图,Windows GDI,GDI:Graphics Device Interface,图形设备接口。提供了供应用程序可调用的多种服务。 GDI使用一种简单的机制保证应用程序的正确的输出到自己的窗口中:设备描述表(DC)。 当Windows程序在屏幕、打印机等设备上画图时,它并不是将像素直接输出到设备上,而是将绘图输出到由设备描述表(DC)表示的逻辑意义上的“显示平面”上。,设备描述表,专门用途的设备描述表: CPaintDC:用于在窗口中客户区绘图(仅限于OnPaint函数中) CClientDC:用于在窗口中客户区绘图(OnPaint函数以外) CWindowDC:用于窗口内任何地方绘图,包括非客户区。,获得设备描述表,1、调用CWnd:GetDC() CDC* pDC = GetDC(); /do some drawing ReleaseDC(pDC); 2、在处理WM_PAINT消息时 PAINTSTRUCT ps; CDC* pDC = BeginPaint(,CDC类中的一些常用成员函数,主要设备描述表属性,绘图模式,CDC:SetROP2(Set Raster Operation To),映射模式,映射模式用于确定从逻辑坐标值到设备坐标值的转换方式。传送给CDC输出函数的是逻辑坐标值。设备坐标值是指窗口中相应的像素点的位置。 CDC:SetMapMode(mode),映射模式(续),可编程映射模式,CDC:SetWindowExt():设置窗口的逻辑尺寸 CDC:SetViewportExt():设置窗口的像素尺寸 实际上是设定一个比例关系。 MM_ISOTROPIC模式下,X和Y方向拥有同一个缩放比例因子,而MM_ANISOTROPIC则可以不同。,坐标转换,LPtoDP():逻辑坐标转换为设备坐标 DPtoLP():设备坐标转换为逻辑坐标 比如用在鼠标命中测试中,鼠标单击后得到的是设备坐标,而用CDC输出函数则用逻辑坐标,移动原点,SetViewportOrg(x,y):将逻辑点(0,0)映射到设备点(x,y) SetWindowOrg(x,y):将逻辑点(x,y)映射成设备点(0,0),坐标系小结,关键点在于理解逻辑坐标系与设备坐标系,以及绘图时转换关系。 坐标系的设定实际上就是为了设定转换关系,GDI 对象,画笔(Pen) 画刷(Brush) 字体(Font) 位图(Bitmap) 调色板(Palette) 区域(Region) SelectObject(.)选入。,GDI画笔和CPen类,Windows用GDI的画笔绘制直线和曲线以及Rectangle、Ellipse等其它图形的边框。 默认画笔是一个像素宽度的黑色实线。,创建画笔,CPen pen(PS_SOLID,1,RGB(255,0,0); 或: CPen pen; pen.CreatePen(PS_SOLID,1,RGB(255,0,0); 笔可以为NULL,则不画线,如不画矩形的边框,画笔样式,GDI画刷和CBrush类,CDC输出函数画出的封闭图形的填充样式用GDI画刷控制。CBrush类封装了GDI画刷。 画刷有三种基本类型:单色、带阴影线和带图案,创建单色画刷,CBrush brush(RGB(255,0,0); 或: CBrush brush; brush.CreateSolidBrush(RGB(255,0,0,);,创建阴影线画刷,CBrush brush(HS_DIAGCROSS,RGB(255,0,0); 或: CBrush brush; brush.CreateHatchBrush(HS_DIAGCROSS,RGB(255,0,0);,阴影线画刷样式,画文本,CDC:DrawText(“Hello World“,-1,GDI字体和CFont类,所有的CDC文本函数都使用当前选入设备描述表的字体。字体是指一组具有特定尺寸(高度)和字样的字符;字样是指字符共有的属性,如字的粗细度-正常或黑体。 在传统印刷式样中,字体是以point(点)为单位来度量的。一个点相当于1/72英寸。 在MFC中,字体由CFont类的对象表示。,创建Font,以像素为单位: CreateFont CreateFontIndirect 以point为单位: CreatePointFont CreatePointFontIndirect,代码示例,CFont font; font.CreatePointFont(120,_T(“Times New Roman“); 或: CClientDC dc (this); int nHeight = -(dc.GetDeviceCaps (LOGPIXELSY) * 12) / 72); CFont font; font.CreateFont (nHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH FF_DONTCARE, _T (“Times New Roman“);,代码示例(续),LOGFONT lf; :ZeroMemory(,代码举例1,CRect rect; GetClientRect(,备用对象,Windows预先定义了一些画笔、画刷、字体以及其它一些GDI对象,它们在使用时不需要显式的创建了。 CDC:SelectStockObject(),备用对象,取消对GDI对象的选定,CPen pen (PS_SOLID, 1, RGB (255, 0, 0); CPen* pOldPen = dc.SelectObject (,六、鼠标和键盘,从鼠标获取输入,鼠标与键盘的输入以消息的形式出现 Windows鼠标消息可分为两类: 非客户区鼠标消息。通常可忽略,由Windows处理。 客户区鼠标消息,这是我们所要关心的。,客户区鼠标消息,添加消息响应函数,利用 ClassWiard,鼠标消息处理函数原型,afx_msg void OnMsgName (UINT nFlags, CPoint point) 其中: point给出了事件发生时鼠标的物理坐标 nFlags参数指出了消息生成时鼠标键及Shift、Ctrl键的状态。 nFlags参数如下: MK_LBUTTON The left mouse button is pressed MK_MBUTTON The middle mouse button is pressed MK_RBUTTON The right mouse button is pressed MK_CONTROL The Ctrl key is pressed MK_SHIFT The Shift key is pressed 检测方法: 如果Ctrl键被按下,则(nFlags & MK_CONTROL)值为非0,举例,TicTac,鼠标滚轮,WM_MOUSEWHEEL BOOL OnMouseWheel (UINT nFlags, short zDelta, CPoint point),捕获鼠标,即使当前光标不在程序中,也能接收鼠标的位置。好处. SetCapture(); ReleaseCapture(); If(GetCapture() = this) 如果本窗口捕获消息则为真。 思考:试着画一条通过鼠标拖动的直线。,光标,利用自定义光标资源 HCURSOR m_myCursor; m_myCursor = AfxGetApp()-LoadCursor(IDC_CURSOR1); SetCursor(m_myCursor); 利用系统定义的光标资源 HCURSOR m_myCursor; m_myCursor = AfxGetApp()-LoadStandardCursor(IDC_CROSS); SetCursor(m_myCursor);,光标,在鼠标移动时,Windows通过重画光标的背景把光标从旧位置上清除。然后它给光标下的窗口发送包含命中测试码为WM_SETCURSOR消息。 示例代码: if(nHitTest = HTCLIENT) HCURSOR m_myCursor; m_myCursor = AfxGetApp()-LoadStandardCursor(IDC_CROSS); SetCursor(m_myCursor); return TRUE;/important return CView:OnSetCursor(pWnd, nHitTest, message);,光标,忙光标: BeginWaitCursor(); EndWaitCursor(); 显示与隐藏光标 ShowCursor(FALSE); ShowCursor(TRUE); 说明 :内部有一个累加器,调用FALSE多少次就要相应的调用TRUE多少次,才能显示光标。,限制光标在一个区域,:ClipCursor(rect):可以限制鼠标在屏幕中指定的矩形范围 (CWnd:GetWindowRect(&rect)可以获得当前窗口在屏幕中的区域) 记得要解除限制,因为光标是所有应用程序共享的全局资源: :ClipCusror(NULL),举例,MouseCap,从键盘获取输入,WM_KEYDOWN WM_KEYUP WM_CHAR WM_SYSKEYDOWN:Alt或F10 WM_SYSKEYUP,击键消息处理函数原型,afx_msg void OnMsgName(UNIT nChar,UINT nRepCnt,UINT nFlags) 其中nChar是被按下或释放的键的虚拟键代码 nPepCnt是重复次数,一般很少理会 nFlags,与硬件相关,一般不用理会,虚拟键代码(参数nChar),传递给击键消息处理程序的最重要的值应该是nChar,它标识了被按下或释放的键。Windows用下表中给出的虚拟键代码来标识键,这样应用程序就不必依赖硬编码值了。 AZ、az、09的虚拟键代码与自身ANSI码一样,其它如下表:,虚拟键代码(续),虚拟键代码(续),Shift键状态,:GetKeyState(.):返回负值说明某键被按下。 如GetKeyState(VK_SHIFT)0,则Shift键被按下。同样可用于VK_CONTROL 一般不针对Alt键使用,因为Alt键按下时会触发WM_SYSKEYDOWN(UP)消息。 也可测试鼠标键是否被按下:VK_LBUTTON、VK_MBUTTON、VK_RBUTTON。 在鼠标响应函数中也可以用来测试Shift、Control键是否被按下。,字符消息,:TranslateMessage将与字符有关的击键消息转换为WM_CHAR消息。 举例: .OnChar(UNIT nChar,.) if(nChar = A&nChar =Z) . else if (nChar = VK_RETURN) . else if(nChar = VK_BACK) . ,插入符,在字处理程序或其他应用程序中,闪烁的竖直条称为插入符,它被用来标记下一个字符插入的地方。在Windows应用程序中,插入符所起的作用在字符模式应用程序中闪烁的下划线光标所起的作用一样。 下面给出MFC类提供的7个处理插入符函数,在下表中少一个基本函数,:DestroyCaret,由于在MFC中没有等价的,所以用户必须从Windows API直接调用它。,插入符,插入符,为了确保合适的处理,使用插入符的应用程序应该遵循以下简单的规则 使用插入符的窗口应该在接收到输入焦点时“创建”插入符,在失去焦点时“销毁”插入符。 在创建了插入符之后,直到调用ShowCaret使它可见之前,它是不可见的。插入符可以调用HideCaret再次隐藏起来。如果HideCaret进行了两次以上的连续调用,对ShowCaret也必须进行相同次数的调用才能使插入符可见。 在OnPaint处理程序以外包含插入符的窗口区域绘图时,应该隐藏插入符以避免显示冲突。在画图完成后重新显示插入符。不需要在OnPaint处理程序中隐藏和重新显示插入符,这是因为:BeginPaint和:EndPaint已经为您做了。 程序调用SetCaret来移动插入符,Windows并不为您移动插入符,处理输入的键盘消息(或是鼠标消息)并相应地控制插入符是您应用程序的工作。调用GetCaretPos可以检索插入符当前的位置。,七、菜单基础,顶层菜单,下拉菜单 弹出式菜单(上下文菜单) 系统菜单,添加下拉菜单步骤,在资源中修改(添加)菜单,设置其ID 设置其快捷键 通过菜单名称名称某个字符前加&,以添加Alt型快捷键 通过在资源中Accelerator来添加快捷键 添加响应函数处理消息COMMAND与UPDATE_COMMAND_UI 菜单COMMAND消息负责调用菜单的命令 菜单UPDATE_COMMAND_UI消息负责更新菜单,CCmdUI项的方法,各种菜单选项,创建层叠菜单方法 创建分隔栏,弹出式菜单,建立菜单资源,设其ID为IDR_MENU1 添加消息WM_CONTEXTMENU(鼠标右击时响应)。 在响应函数中可加入如下代码 CMenu popmenu; popmenu.LoadMenu(IDR_MENU1); popmenu.GetSubMenu(0)-TrackPopupMenu(TPM_RIGHTBUTTON,point.x,point.y, AfxGetMainWnd ();,TrackPopupMenu,BOOL TrackPopupMenu(UINT nFlags, int x, int y,CWnd* pWnd, LPCRECT lpRect = 0); x,y说明菜单显示的位置(屏幕坐标) nFlags:说明哪些键可以选中菜单中菜单项(TPM_LEFTBUTTON,TPM_RIGHTBUTTON)及菜单相对于x的位置(TPM_LEFTALIGN,TPM_CENTERALIGN,TPM_RIGHTALIGN) pWnd:确定哪个窗口能够接收菜单中各种操作所引发的消息 lpRect:确定一个矩形,在这个矩形中单击鼠标不会取消菜单,如果为NULL(默认),则在菜单外点击会取消菜单。,手工编程创建菜单,CMenu:CreateMenu:创建顶层菜单 CMenu:CreatePopMenu:创建弹出式菜单 CMenu:AppendMenu:在菜单尾部添加菜单项(或子菜单) CMenu:InsertMenu:在菜单给定位置插入一个菜单项 CMenu:ModifyMenu:改变菜单项的命令ID、正文或其他特性 CMenu:DeleteMenu:删除菜单项 GetMenu():获取顶层菜单的CMenu指针 CMenu:GetSubMenu():获得子菜单,代码示例1,在int CMainFrame:OnCreate()后加入下面代码: CMenu menuMain; menuMain.CreateMenu (); CMenu menuPopup; menuPopup.CreatePopupMenu (); menuPopup.AppendMenu (MF_STRING, ID_APP_EXIT, “E,代码示例2,CMenu* pMenu = GetMenu (); pMenu-DeleteMenu (1, MF_BYPOSITION); pMenu-DeleteMenu (ID_SHAPE_CIRCLE, MF_BYCOMMAND); - pMenu-ModifyMenu (ID_SHAPE_TRIANGLE, MF_STRING MF_BYCOMMAND, ID_SHAPE_TRIANGLE, “,代码举例,在弹出式菜单处理函数中: CMenu menuPopup; menuPopup.CreatePopupMenu(); menuPopup.AppendMenu(MF_STRING,ID_CIRCLE,“Circle“); menuPopup.AppendMenu(MF_STRING,ID_TRIANGLE,“Triangle“); menuPopup.AppendMenu(MF_STRING,ID_RECT,“Rectangle“); menuPopup.TrackPopupMenu(TPM_RIGHTBUTTON,point.x,point.y,this);,八、工具栏 状态栏,1.1 创建和初始化工具栏,因为工具栏是应用程序的主框架窗口的子窗口,通常随框架窗口的创立而创立,所以一般在框架窗口类中添加一个CToolBar成员,并在框架窗口的OnCreate函数中调用CToolBar:Create。 如: m_wndToolBar.Create (this, WS_CHILD WS_VISIBLE CBRS_BOTTOM); 或 m_wndToolBar.Create (this); m_wndToolBar.SetBarStyle (m_wndToolBar.GetBarStyle () ,1.2 为工具栏添加文字,在资源中双击工具栏的图标,修改图标大小为40,19 在创建工具栏的代码下加入如下代码 m_wndToolBar.SetButtonText(0,_T(“New“); m_wndToolBar.SetButtonText(1,_T(“Open“); m_wndToolBar.SetButtonText(2,_T(“Save“); m_wndToolBar.SetButtonText(4,_T(“Cut“); m_wndToolBar.SetButtonText(5,_T(“Copy“); m_wndToolBar.SetButtonText(6,_T(“Paste“); m_wndToolBar.SetButtonText(8,_T(“Print“); m_wndToolBar.SetButtonText(10,_T(“Help“); m_wndToolBar.SetSizes(CSize(48,42),CSize(40,19);/第一个size是BUTTON的大小,第二个size是图标的大小。 在添加文本后再调用SetSizes(),1.3 修改工具栏的样式,CToolBar:SetButtonStyle 创建复选按纽,使之一直处于下陷的状态直到再一次单击之。 m_wndToolBar.SetButtonStyle(1,TBBS_CHECKBOX); 注:当程序处理了ON_UPDATE_COMMAND_UI消息,并调用CCmdUI:SetCheck,则标准按纽会转换为复选按纽。,1.3 修改工具栏的样式,CTool

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论