版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
任课教师信息姓名:钟樑手机618765)Email:zlkmust@163.comVisualC++学习参考学习步骤:1、掌握C++的核心知识:继承、派生、多态性。2、熟悉利用API进行WINDOWS开发的基本原理,如消息映射。3、学习MFC程序开发,多利用MSDN或者网上资源进行自学。4、细分方向的开发,如图形图像方面。参考资料:1、MSDN2、MFC程序设计第二版,清华大学出版社。3、深入浅出MFC,华东理工大学出版社。4、,VisualC++简介VisualStudio是一种集成开发环境,其提供了包括VisualC++,VisualBasic,C#,ASP.NET,SQLServerExpress在内的多项开发功能。VisualC++是VisualStudio的一个子集,其不是一门语言,而是多种开发技术的合集,主要包括:1)Win32API(WindowsSDK开发)2)Win32Console(传统C/C++开发)3)MFC(MicrosoftFoundationClasses)4)ATL(ActiveTemplateLibrary)VisualC++简介VisualC++功能:WEB控件:如银行的各种安全控件、甚至各种流氓控件。通信的程序:聊天工具如QQ、BT下载工具、视频点播工具等。图形图像处理:VisualC++在图形图像处理上有先天的优势,可以说是图形图像处理领域的唯一选择。游戏开发:VisualC++可以很方便的调用OpenGL和DirectX,是游戏开发的首选工具。
底层开发及二次开发:VisualC++有强大的底层开发功能,并能很方便为其它设计软件进行二次开发,如AutoCAD,TransModel。VisualC++简介利用VC编制windows程序主要有两种方法:(1)SDK(SoftwareDevelopmentKit)软件开发工具包(2)MFC(MicrosoftFoundationClassLibrary)微软基本类库传统的结构化WINDOWS程序开发(SDK):SDK的编程方式就是传统的C的编程方式。通过调用库函数(win32API,也就是ApplicationProgrammingInterface,即操作系统留给应用程序的一个调用接口)来实现程序的搭建。
优点在于:程序比较小,效率高。缺点在于:无框架化结构,API函数混乱,实现一个简单窗口程序就需要上百行代码。VisualC++简介MFC程序开发:MFC是面向对象程序设计与Applicationframework的完美结合。它是把WinAPI进行封装的类库,是一个类的集合。它通过覆盖WindowAPI,为编程提供了一个面向对象的界面。优点在于:利用C++面象对象的特性进行编程,提供了一般性框架,大大缩短开发时间,易于实现代码移植,而且使得用户界面元素的编写变得容易起来。缺点在于:封装复杂,细节隐藏过深,入门难度大,且不便于全面掌握其内部机理。面向对象概念回顾1、类基本格式:
class类名称
{public:
公有成员
protected:
保护型成员
private:
私有成员
};类成员函数声明的一般形式:
返回类型函数名(形参表);类成员函数定义的一般形式(类外定义):
返回类型类名::函数名(形参表)
{//函数体
}类属性(成员变量)的申明同普通变量申明一致面向对象程序设计——复习2、类的构造函数构造函数的作用: 用于在对象创建时,对对象的属性进行初始化。构造函数的特点:是一个函数,但没有返回值类型。是一个和类名同名的函数。只在对象创建时,自动地被编译器调用。其它特征和普通函数相同,可以重载(即可以有多个版本的构造函数)。面向对象程序设计——复习构造函数的一般声明方式:类名(形参表);构造函数的一般实现方式: 类名::类名(形参表) {//函数体; }构造函数的另一种实现方式: 类名::类名(形参表):初始化列表
{//函数体; }
初始化列表形式:属性(值或形参),属性(值或形参)…面向对象程序设计——复习3、类的析构函数析构函数的作用:
用于在对象生命期结束后,对对象占用的内存进行清理工作。析构函数的特点:是一个函数,但没有返回值类型。是一个在“类名”前加上“~”符号的函数。只在对象生命期结束时,自动地被编译器调用。析构函数一个类中只能有一个,且不能重载。面向对象程序设计——复习4、this指针指向当前对象的指针。例:Point类为例
voidmain(){ Pointpt[3];for(intid=0;id<3;id++){ pt[id].SetX(id);pt[id].SetY(id);}}voidPoint::SetX(intnewX){m_iX=newX;}谁的m_iX?怎么确定的?voidPoint::SetX(intnewX){this->m_iX=newX;}面向对象程序设计——复习(类的)继承:一个新类从已有的类那里获得其已有的特性(属性和方法)。获得方:子类或派生类给予方(被获得方):父类或基类继承的关系:继承是一种“是一个(is-a)”的关系。即如果一个子类B继承了父类A,我们可以说B是一个A。5、继承的概念面向对象程序设计——复习派生类的一般申明形式:class类名
:继承控制基类名{//类声明};6、基类和派生类的申明基类的申明同一般类的申明方式。可以是public,private,protected;注意:基类的属性和方法在派生类中都保存了相应的一份拷贝面向对象程序设计——复习7、多重继承派生类可以继承自多个类,一般申明形式:class类名
:继承控制基类名,继承控制基类名,…8、继承情况下的构造派生类负责基类的构造派生类利用初始化列表构造基类的属性。派生类总是负责直接基类的构造。有多个基类的情况下,派生类对基类的构造顺序取决于继承顺序,先继承的先构造,最后构造自身。析构顺序与此相反。9、派生类和基类的关系以及安全赋值问题:
派生类和基类的关系为”is-a”的关系,即:
派生类是一个基类面向对象程序设计——复习派生类的对象可以通过多种方式安全的赋值给基类1)、派生类对象可以直接赋值给基类对象。2)、派生类对象可以初始化给基类的引用。3)、派生类对象可以初始化给基类的指针。动态绑定静态绑定基类的对象却无法安全的赋值给派生类面向对象程序设计——复习10、虚函数与多态虚函数的形式:virtual成员函数申明虚函数的意义:该成员函数在派生类中会有不同的实现方式,即该行为因类型不同有不同的表现方法(多态)多态的使用:第一步:必须存在继承关系。第二步:需要表现出多态性的成员方法必须声明为基类的虚函数。第三步:在派生类中将从基类继承而来的虚函数按照需求进行重新定义。第四步:将派生类的对象赋值给基类的引用或者指针第五步:通过该基类的引用或者指针调用相应的虚函数,就能根据对应的派生类表现出相应的行为。面向对象程序设计——复习11、虚函数的注意事项
几乎所有的成员函数都可以申明为虚函数(包括析构函数),但构造函数不能申明为虚函数(包括拷贝构造函数。)12、纯虚函数与抽象类纯虚函数:一个必须由派生类实现的基类的成员方法,其实质是一个“占位符”。作用是告诉该基类的派生类,此方法必须由派生类实现。声明方法:虚成员函数声明=0;
如:virtualvoidGoToSchool()=0;抽象类:即包含了纯虚函数的类。注意:抽象类不能实例化(即不能定义对象)面向对象程序设计——复习13、new和delete:在堆上申请和释放内存new的一般格式:
new类型(初值)
或new类型[数量]delete的一般格式:
delete指针 或delete[]指针1)、必须成对使用2)、new和delete在创建和删除对象的时候会自动调用类的构造函数和析构函数。WINDOWS程序设计基础基本概念:Windows程序设计是完全不同于Dos环境下的程序设计,是一种事件驱动的程序设计方法。主要是基于消息的。当用户需要完成某种功能时,会调用操作系统的某种支持,操作系统将用户的需要包装成某种消息,并投递到消息队列当中。然后利用应用程序从消息队列中取走消息并进行响应。消息:指Windows发出的一个通知,告诉应用程序某个事情发生了,每一次键盘按键,鼠标单击,窗口更新都会产生消息。程序中的消息:在WINDOWS开发中,一个消息被定义成了一个结构体typedefStructtagMsg{//…}MSG;WINDOWS程序设计基础MSG的内部结构typedefstructtagMSG{//msgHWNDhwnd;
UINTmessage;
WPARAMwParam;
LPARAMlParam;
DWORDtime;
POINTpt;
}MSG;
//消息来源的窗口句柄//消息ID//消息的附加参数//消息产生的时间//消息产生的窗口位置其为消息的实质,通常为WM_XXX的样式//如鼠标消息WINDOWS程序设计基础消息队列:
操作系统会为每个应用程序建立一个消息队列。这个队列是个先进先出的缓冲区:消息响应:当应用程序收到消息的时候,针对这个消息的进行处理的过程就叫消息响应。消息1消息2……消息n消息产生消息响应消息响应是通过程序实现的,这也是Windows应用程序的主要代码区。WINDOWS程序设计基础消息的传递机制:检索队列中是否存在消息属于某一个窗口WINDOWS程序设计基础窗口:窗口是屏幕上的一个矩形区域WINDOWS程序设计基础句柄(HANDLE):资源的标识
句柄,是整个windows编程的基础。一个句柄是指一个用来标志应用程序中的不同对象和同类对象中的不同的实例的唯一存在的32位整数值,其特性类似一个地址。
在Windows编程中,句柄可以看做是相关资源或实例,如一个窗口,按钮,图标,滚动条,输出设备,控件或者文件等,的唯一标示。句柄在Windows编程中,大量使用,如HINSTANCE(实例句柄)HBITMAP(位图句柄)HDC(设备描述表句柄)HICON(图标句柄)实际上,WINDOWS编程中的所有句柄均统一为:HXXXWINDOWS程序设计基础WINDOWS自定义类型简介:
为了维护方便,WINDOWS将C/C++的内建类型都进行了重新定义,其一般定义规则为:
typedeftypeTYPE;如:int对应INT,char对应CHAR,float对应FLOAT
同时,WINDOWS还按照匈牙利命名法的相关规则对相关类型指针进行了重新定义,如LPSTR,PBYTE等。另外,WINDOWS还按照需要重新定义了一些类型,如WPARAM,LPARAM,WORD等,其实质也是内建类型的重命名。参考:ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/winprog/winprog/windows_data_types.htmWINDOWS程序设计基础UNICODE简介:传统的英文字符采用的是ASCII编码,但A的意思是American,这也是ASCII编码最大的问题。而要表示中文、日语在内的东方语系,ASCII就不能满足要求,这时候引入了双字节的UNICODE码。‘a’979700ASCIIUNICODEcharc=‘a’wchar_tc=‘a’“abc”char*p=“abc”;wchar_t*p=L“abc”;WINDOWS程序设计基础C/C++语言的UNICODE类型以及对应函数:定义头文件:wchar.hstrlenstrcatstrcpystrcmpASCII版UNICODE版getcwcslenwcscatwcscpywcscmpgetwcASCII版UNICODE版putcputwcputcharputwchargetchargetwcharprintfwprintfsprintfwsprintf类型:wchar_t实质:typedefunsignedshortwchar_tWINDOWS程序设计基础练习:请定义两个UNICODE字符串,并将大的字符串连接到小的字符串后面。wchar_t*p1=L”Hello”;wchar_t*p2=L”myclass”;intnewLength=wcslen(p1)+wcslen(p2);wchar_t*p3=newwchar_t[newLength+1];if(wcscmp(p1,p2)){wcscpy(p3,p2);wcscat(p3,p1);}else{wcscpy(p3,p1);wcscat(p3,p2);}WINDOWS程序设计基础WINDOWS程序中的UNICODE类型:TCHAR:解决通用的关键WINDOWS使用了一个预定义宏来解决可能存在的ASCII和UNICODE不通用问题,TCHAR!#ifdefUNICODEtypedefwchar_t
TCHAR#elsetypedefcharTCHAR同时,为了简便操作,还定义了一个更简短的宏_T/_TEXT,来表示一个通用字符串来源:#define_T(x)__T(x)UNICODE:#define__T(x)L##xASCII:#define__T(x)xWINDOWS程序设计基础例:一个TCHAR数组TCHARt[10]={_T(“abcde”)};TCHARt[10]={‘a’,‘b’,‘c’,‘d’,‘e’};t[5]=‘d’;TCHAR*p=_T(“Hello”);intlen=lstrlen(p);TCHAR*q=_T(“World”);lstrcat(p,q);WINDOWS定义了一系列的操作TCHAR的函数:lstrlenlstrcpylstrcpynlstrcatlstrcmpWINDOWS程序设计基础WINDOWS程序中的定义的其他UNICODE类型:PCHAR,LPCH,PCH,LPSTR,PSTR=CHAR*(char*)LPCCH,PCCH,LPCSTR,PCSTR=CONST
CHAR*PWCHAR,LPWCH,PWCH,LPWSTR,PWSTR=WCHAR*LPCWCH,PCWCH,LPCWSTR,PCWSTR=CONST
WCHAR
CHAR*LPCTSTR=CONSTTCHAR*LPTSTR=TCHAR*WINDOWS程序设计基础WINDOWSSDK程序设计WINDOWS程序设计基础例:一个完整的程序HelloWindowsSDKWINDOWS程序设计基础程序源代码://helloWin.cpp#include<tchar.h>#include<Windows.h>#pragmacomment(lib,"Winmm.lib")LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intiCmdShow){
//申明消息处理函数//WinMain函数入口,原型查阅MSDN//调用lib,为了声音WINDOWS程序设计基础staticTCHARszAppName[]=_T("Hello");HWNDhWnd;MSGmsg;WNDCLASSwndClass;wndClass.style=CS_HREDRAW|CS_VREDRAW;wndClass.lpfnWndProc=WndProc;wndClass.cbClsExtra=0;wndClass.cbWndExtra=0;wndClass.hInstance=hInstance;wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);wndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);wndClass.lpszMenuName=NULL;wndClass.lpszClassName=szAppName;//程序名//窗口句柄//消息结构体//窗口结构体//窗口模式初始化//窗口过程函数//窗口实例句柄//读取图标//读取光标//窗口背景设为白色//设置菜单//设置窗口类名WINDOWS程序设计基础if(!RegisterClass(&wndClass)){MessageBox(NULL,_T("程序出错"),szAppName,MB_ICONERROR);return0;}hWnd=CreateWindow(szAppName, _T("Hello"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,NULL, NULL, hInstance, NULL);//注册窗口//创建窗口//程序名和窗口名//窗口样式//x和y坐标//高度和宽度//父窗口句柄//菜单句柄//实例句柄//附加参数WINDOWS程序设计基础ShowWindow(hWnd,iCmdShow);UpdateWindow(hWnd);while(GetMessage(&msg,NULL,0,0)){ TranslateMessage(&msg); DispatchMessage(&msg);}returnmsg.wParam;}//WinMainEnd//显示窗口//更新窗口,发送WM_PAINT//消息循环WINDOWS程序设计基础LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam){HDChdc;PAINTSTRUCTps;RECTrect;switch{//…代码见下页}returnDefWindowProc(hWnd,message,wParam,lParam);}//定义一个设备上下文句柄//定义一个绘制结构体//矩形区域//消息处理,见下页//默认的消息处理函数WINDOWS程序设计基础switch(message){caseWM_CREATE:PlaySound(_T("hello.wav"),NULL,SND_FILENAME|SND_ASYNC);return0;caseWM_PAINT: hdc=BeginPaint(hWnd,&ps);
GetClientRect(hWnd,&rect);
DrawText(hdc,_T("HelloWindowsSDK!"),-1,&rect,DT_SINGLELINE|DT_RIGHT|DT_BOTTOM); EndPaint(hWnd,&ps); return0;caseWM_DESTROY: PostQuitMessage(0); return0;}//对消息进行处理//处理WM_CREATE消息//处理WM_PAINT消息//关闭窗口消息WINDOWS程序设计基础入口函数:WinMainintWINAPIWinMain(
HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPSTRlpCmdLine,
intnShowCmd)当前实例之前实例命令行窗口显示模式实例句柄字符串,typedefchar*LPSTR如同C/C++的Main函数一样,WinMain代表了一个WINDOWS程序的入口点,其样式必须保持不变。WINDOWS程序设计基础WINDOWS程序设计基本流程:1、设计窗口typedefstruct_WNDCLASS{UINTstyle;WNDPROClpfnWndProc;intcbClsExtra;intcbWndExtra;HINSTANCEhInstance;HICONhIcon;HCURSORhCursor;HBRUSHhbrBackground;LPCTSTRlpszMenuName;LPCTSTRlpszClassName;}WNDCLASS;
窗口类型窗口过程函数指针当前应用程序句柄图标句柄光标句柄背景画刷句柄窗口类名WNDCLASSwc;//初始化相关字段WINDOWS程序设计基础2、注册窗口RegisterClass(&wc);3、创建窗口HWNDCreateWindow(LPCTSTRlpClassName,//已注册的窗口类的名字LPCTSTRlpWindowName,//窗口的名字,即标题栏上显示的文字DWORDdwStyle,//窗口的类型intx,//窗口显示时左上角的x坐标inty,//窗口显示时左上角的y坐标intnWidth,//窗口宽度intnHeight,//窗口高度HWNDhWndParent,//父窗口的句柄HMENUhMenu,//菜单的句柄HINSTANCEhInstance,//实例的句柄LPVOIDlpParam//与窗口相关的附加参数);HWNDhwnd=CreateWindow(…);WINDOWS程序设计基础4、显示和更新窗口ShowWindow(hWnd,iShowCmd);创建好的窗口句柄显示状态UpdateWindow(hWnd);5、开始消息循环MSGmsg;
while(GetMessage(&msg,NULL,0,0))
{ TranslateMessage(&msg);
//翻译消息
DispatchMessage(&msg);
//分派消息
}来源于WinMain参数,有3种状态:SW_SHOWNORMAL,SW_SHOWMAXMIZED,SW_SHOWMINNOACTIVEWINDOWS程序设计基础消息循环相关函数:BOOLGetMessage(LPMSGlpMsg,//消息
HWNDhWnd,//哪个窗口的消息队列
UINTwMsgFilterMin,//消息的最小值
UINTwMsgFilterMax//消息的最大值);1)GetMessage:负责从消息队列中获取消息消息过滤2)TranslateMessage:翻译消息BOOLTranslateMessage(constMSG*lpMsg);例:键盘按下某个键会产生WM_KEYDOWN消息,但是要知道到底按下的那个键,需将按键信息的ASCII码插入消息,并翻译为WM_CHAR消息进行处理。WINDOWS程序设计基础2)DispatchMessage:分发消息DispatchMessage函数的作用是将收到的消息传给窗口的回调函数(CallBackFunction),即窗口过程函数去处理。这个窗口过程函数就是在设计窗口类时指定的。回调函数的概念:回调函数是一个由开发者实现,但交由系统自动调用的函数。其往往通过函数指针的方式赋值给某个其它函数或者数据结构作为参数。窗口过程函数是一个典型的回调函数。WINDOWS程序设计基础6、窗口过程函数(消息处理)。函数原型:LRESULTCALLBACKFuncName(
HWNDhWnd,
UINTmsg,
WPARAMwParam,
LPARAMlParam
)所属窗口消息附加参数内部结构:switch(msg){caseWM_XXX://Dosomething;//…}returnDefWindowProc(hWnd,Msg,wParam,lParam);函数名自定实际是一个unsignedintMFC程序设计基础MFC程序设计,从向导生成开始:选择MFC应用程序MFC程序设计基础直接下一步MFC程序设计基础选择应用程序类型:这里使用单文档这里调节样式MFC程序设计基础这里可以设置扩展名,标题等MFC程序设计基础数据库支持,这里不选择MFC程序设计基础添加高级功能,这里不更改MFC程序设计基础查看向导生成的类,并可根据需要进行更改MFC程序设计基础运行结果MFC程序设计基础向导生成的程序清单和类清单:MFC程序设计基础如果把这里改成CEditViewMFC程序设计基础
可见,利用MFC进行WINDOWS程序设计,相比SDK来说要方便的多但问题是MFC有SDK编程那种清晰结构吗?MFC程序设计基础MFC中消失的WinMain试图在项目中寻找WinMain会得到以下结果难道MFC中没有入口点函数吗?MFC的类层次结构MFC是一个用面向对象进行封装后的类层次结构MFC的类层次结构MFC9.0的所有类ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.chs/dv_vclib/html/19d70341-e391-4a72-94c6-35755ce975d4.htmMFC的类层次结构解析
从CWinApp派生出了CMyApp,代表应用程序本身。
从CView派生出了CMyView,代表一个视图窗口。
从CFrameWnd派生出了CMyFrameWnd,代表一个框架窗口。
线程类,实际上一个应用程序就等于一个线程。
消息映射MFC的类层次结构解析virtualBOOLInitInstance();virtualBOOLRun()virtualBOOLInitInstance();virtualBOOLRun()virtualBOOLInitApplication();virtualBOOLInitInstance();问题的关键:MFC程序怎么开始的呢?MFC程序的生死循环1、MFC程序的活水源头,CMyWinApp的全局对象。2、链接期隐式链接的WinMain函数。//inAPPMODUL.CPP#define_tWinMainWinMain;MFC程序的生死循环3、真正的入口点,多态的威力:AfxWinMain()//inWINMAIN.CPP,AfxWinMain简略版
AfxWinMain(…){ CWinApp*pApp=AfxGetApp(); pApp->InitApplication(); pApp->InitInstance(); pApp->Run(); AfxWinTerm();}获取全局对象
由于CWinApp重写,所以调用的是CWinApp的版本。
由于CMyApp重写了InitInstance(),所以调用的是CMyApp的版本。MFC程序的生死循环3.1InitInstance,窗口的设计、注册与创建//DOCTEMPL.CPP的264行CFrameWnd*pFrame=(CFrameWnd*)m_pFrameClass->CreateObject();在这个函数内会通过new算子创建框架类CMainFrame。//DOCTEMPL.CPP的277行pFrame->LoadFrame(m_nIDResource,WS_OVERLAPPEDWINDOW|FWS_ADDTOTITLE,NULL,&context))在这个函数内完成窗口类的注册,产生主窗口并加挂菜单等诸元素,并指定窗口标题、文件标题、文件扩展名等。MFC程序的生死循环3.2InitInstance,窗口的显示和更新m_pMainWnd是一个定义在CWinThread中的public成员,类型为CFrameWnd/CFrameWndEx;MFC程序的生死循环4、隐晦的消息循环,pApp->Run();//inThredCore.cpp,Run简单版由于派生类没有重写过Run(),所以这里调用的是CWinThread的版本。BOOLCWinThread::Run() {do GetMessage(); TranslateMessage(); DispathMessage(); }While(PeekMessage())MFC程序的生死循环5、不存在的窗口过程函数,取而代之的消息映射消息映射的基本使用方法:DECLARE_MESSAGE_MAP()申明消息映射BEGIN_MESSAGE_MAP(类名,基类名)//消息映射END_MESSAGE_MAP()开始消息映射结束消息映射6,程序的结束:AfxWinTerm();MFC程序的生死循环不用向导生成MFC程序:第一步:包含头文件<afxwin.h>第二步:从CWinApp派生出CMyApp,重载虚函数InitInstance();classCMyApp:publicCWinApp{public:virtualBOOLInitInstance();}第三步:从CFrameWnd派生出CMyWnd,实现构造函数以创建窗口。MFC程序的生死循环classCMyWnd:publicCFrameWnd{public:CMyWnd();
};第四步:为CMyWnd添加消息映射。DECLARE_MSG_MAP()BEGIN_MSG_MAP(CMyWnd,CFrameWnd)
END_MSG_MAP()ON_WM_PAINT()afx_msgvoidOnPaint();MFC程序的生死循环代码清单://inhelloMFC.h#include<afxwin.h>classCMyApp:publicCWinApp
{public: virtualBOOLInitInstance();
};classCMyWnd:publicCFrameWnd{public: CMyWnd(); afx_msgvoidOnPaint(); DECLARE_MESSAGE_MAP();};MFC程序的生死循环//inhelloMFC.cppCMyAppmyApp;BOOLCMyApp::InitInstance()
{
m_pMainWnd=newCMyWnd;
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
returnTRUE;}//forCMyWndBEGIN_MESSAGE_MAP(CMyWnd,CFrameWnd) ON_WM_PAINT()END_MESSAGE_MAP()MFC程序的生死循环CMyWnd::CMyMainWnd()
{
Create(NULL,_T("TheHelloApplication"));}voidCMyWnd::OnPaint(){ CPaintDCdc(this); CRectrect; GetClientRect(&rect); dc.DrawText(_T("HelloWorld"),-1,rect,DT_CENTER|DT_SINGLELINE|DT_VCENTER);}MFC程序的生死循环执行结果:MFC程序的生死循环来龙去脉:隐式链接afx_msgvoidOnPaint();上述程序的创建步骤:创建一个Console程序,项目->属性中修改以下设置:MFC重要概念——窗口封装所有的Windows程序设计,可以说是基于消息和窗口的程序设计,几乎所有常见的控件都可以说是一个窗口。出于这个理由,MFC将所有的窗口进行了抽象,得到了CWnd类,并从这个基类派生出了多种窗口和控件。对话框视图类控件类框架类MFC重要概念——消息处理MFC采取了一套封装后的消息处理机制,称为消息映射。通过消息映射,将消息和相应的消息处理函数绑定,从而实现了消息处理功能。使用规则如下:1、申明消息映射
要使用消息映射,首先要申明消息映射。在需要进行消息映射的类申明文件里面添加:DECLARE_MSG_MAP()实际上是一个预编译宏,定义了一个用于存放消息的数据结构和一个指向该数据结构的数据结构基类结构消息处理MFC重要概念——消息处理2、开始消息循环要使用消息循环,必须在类对应的cpp文件中添加如下语句:
BEGIN_MESSAGE_MAP(派生类名,基类名)基类结构基类结构BEGIN_MESSAGE_MAP(derive,base)其实也是一个预编译宏,其完成了派生类和基类消息的链接如:BEGIN_MESSAGE_MAP(CMyWnd,CFrameWnd)CMyWndCFrameWndMFC重要概念——消息处理3、填充消息映射以及定义消息处理函数在完成BEGIN_MESSAGE_MAP(derive,base)后,需要进行消息映射的填充,并定义对应的消息处理函数。填充消息映射对应afx_msgOnPaint()对应afx_msgOnLButtonDown(UINT,CPoint)有afx_msg的函数才是消息处理函数MFC重要概念——消息映射模式
标准Windows消息的对应规则
概念:标准Windows消息是指以“WM_”开头的消息,有100多个,主要用于处理基本的绘制、键盘、鼠标等消息。对应规则:一般情况下
WM_XXX
消息对应的消息映射为ON_WM_XXX(),消息处理函数为afx_msg
OnXXX(…)WM_PAINTON_WM_PAINT()OnPaint()MFC根据消息类型不同,采取了四种不同的映射模式:如:WM_CHARON_WM_CHAR()OnChar()MFC重要概念——消息映射模式
例1:鼠标定位程序。当鼠标左键在窗口上点击时,弹出消息框提示鼠标点击位置。MFC重要概念——消息映射模式例1的实现:第一步:利用向导创建一个基于对话框的MFC应用程序MFC重要概念——消息映射模式第二步:添加对应的消息映射
在生成的对话框程序中找到基类为CDialog的类(所在头文件和源文件一般命名为CXXXDlg.h/cpp),在源文件中找到消息映射,添加ON_WM_LBUTTONDOWN(),以处理鼠标左键单击消息。MFC重要概念——消息映射模式第三步:在类中添加对应的消息处理函数第四步:实现该消息处理函数CString是一个字符串类,类似stringCString::Format(…),类似sprintf函数,格式化字符串。CWnd::MessageBox(输出文本,标题,样式)字符分为unicode和ascii两种,对应wchar和char,这里的_T是一种自动判断的手段。实际上MFC中定义了一种通用字符TCHAR,也会自动判断MFC重要概念——消息映射模式ON_COMMAND消息ON_COMMAND消息主要是为了映射菜单命名,其基本映射规则为:ON_COMMAND(<命令id>,<memberFxn>);其处理函数的原型均为:afx_msgvoidmemberFxn();例:如何建立菜单,并响应菜单消息。菜单创建和ON_COMMAND例:如何建立菜单,并响应菜单消息。第一步:利用向导创建一个单文档程序第二步:切换到资源视图第三步:打开Menu,并选择
IDR_MAINFRAME第四步:双击进入编辑模式MFC重要概念——消息映射模式续前例:第五步,添加一个菜单Test,取消Popup属性,ID取名ID_TEST_MENU。菜单的Popup样式:Popup菜单是一种顶层菜单,其可以包含子菜单但一般不响应消息,如word里面的“文件”菜单就是个Popup菜单。MFC重要概念——消息映射模式第六步,添加消息处理函数和消息映射。MFC重要概念——消息映射模式执行结果:MFC重要概念——消息映射模式补充:上例第六步消息映射的向导添加模式:选择哪个类响应消息选择消息类型输入消息处理函数名MFC重要概念——消息映射模式ON_CONTROL/ON_NOTIFY
这两个消息映射都是用于控件,如按钮、列表、编辑框等的消息,这两个消息映射的原型如下:ON_CONTROL(<wNotifyCode>,<id>,<memberFxn>)ON_NOTIFY(<wNotifyCode>,<id>,<memberFxn>)消息代码控件id消息处理函数对应消息处理函数原型:ON_CONTROL:afx_msgvoidMemberFunction();ON_NOTIFY:afx_msgvoidMemberFunction(NMHDR*pNotifyStruct,LRESULT*result);一个附加信息的数据结构MFC重要概念——消息映射模式例:按钮消息的使用。第一步:前例的基于对话框的应用程序,切换到资源视图,双击Dialog,利用工具箱添加按钮。MFC重要概念——消息映射模式第二步:添加消息处理,使用ON_CONTROL向导生成的为ON_BN_CLICKED(IDC_BUTTON1,处理函数)MFC重要概念——消息映射模式自定义消息映射:ON_MESSAGEMFC允许用户自己定义消息,自定义消息必须在WM_USER的基础上定义,且自定消息的消息映射使用ON_MESSAGE。自定义消息的一般格式:#defineCUSMSGWM_USER+N;N最大可以是0x7FFF。ON_MESSAGE的原型:ON_MESSAGE(<msgID>,<func>)如:#defineBEGINADDWM_USER+5MFC重要概念——消息映射模式自定义消息映射:ON_MESSAGEON_MESSAGE的消息处理函数原型:afx_msgLRESULTFuncName(WPARAM,LPARAM)实际上是一个long实际上是一个unsignedint,主要用作一些特殊参数的传送。自定义消息一般需要通过发送消息传递,原型为:LRESULT
CWND::SendMessage(
UINT
message,
WPARAM
wParam
=
0,
LPARAM
lParam
=
0
);
MFC重要概念——消息映射模式例:一个加法的自定义消息处理,以前面的对话框程序为基础第一步:定义一个自己的消息第二步:申明消息处理函数第三步:消息映射第四步:消息处理MFC重要概念——消息映射模式第五步:当按钮按下的时候发送消息MFC重要概念——资源文件MFC生成的代码中包括了两个文件:Resource.h和xxx.rc,这两个文件实际上包含了当前应用程序所使用的所有MFC的资源。.rc文件
xxx.rc文件包含了整个工程的所有资源信息,包括对话框、位图、菜单、图标、工具栏以及字符串等资源;他们的大小,风格,字体等属性信息,都包含在其中;一般情况下不用去写和修改,由MFC自动维护MFC重要概念——资源文件Resource.h文件
Resource.h文件包含了整个工程的所有资源信息的常量定义:ID的命名规则MFC重要概念——消息处理3、填充消息映射以及定义消息处理函数填充消息映射以及定义消息处理函数实际上是为了形成消息循环基类结构基类结构CFrameWndCMyWndmsgHandler1msgHandler2msgHandler1msgHandler2基类结构CWndmsgHandler1msgHandler2
形成这样的消息循环的最大的好处是:消息可以在循环中流动,某些派生类处理不了或不愿处理的消息可以交由基类处理。MFC重要概念——消息处理MFC存在的消息循环示例深入阅读:《深入浅出MFC》MFC重要概念——绘制(CDC)WINDOWS采用了GraphicsDeviceInterface(GDI,图形设备接口)来进行图形输出,其基本机制是设备描述表(DC,DeviceContext)。而MFC将GDI利用面向对象进行了重新封装,从而形成了CDC类,使用系统提供的DC进行图形输出和绘制。CDC的使用在MFC应用程序中使用CDC进行绘图一般有三种模式,第一种:在普通程序中
CDC*pDC=GetDC();//Drawsomething;
ReleaseDC(pDC);必须成对出现MFC重要概念——绘制(CDC)CDC的第二种使用方式:在WM_PAINT消息对应的消息处理函数afx_msgvoidOnPaint()中。PAINTSTRUCTps;CDC*pDC=BeginPaint(&ps);//DrawsomethingEndPaint(&ps);必须成对出现WM_PAINT消息:WM_PAINT消息是一个重要的初始化消息,一个窗口在产生的时候所有的绘制工作都由该消息处理(对话框由OnDraw处理),并且当窗口刷新的时候,都会产生WM_PAINT消息进行重绘。如果想对窗口进行自定义绘制,都应该覆盖来自基类的WM_PAINT消息对应的处理函数OnPaint()进行绘制。MFC重要概念——绘制(CDC)CDC的第三种使用方式:如果不想仅在当前窗口绘图,而想在整个窗口的任意地方绘图。这时候应该使用CWnd::GetWindowDC()代替CWnd::GetDC(),并继续使用ReleaseDC()释放。由于CDC有多种使用方式,为了减轻记忆负担,MFC对这三种方式进行了重新的封装,类图如下:CObject除OnPaint外的绘制向GDI文件绘图OnPaint专用在窗口任意位置绘图MFC重要概念——绘制(CDC)例1:在前例手动生成的MFC程序中加入以下功能,点击窗口出现自动画两条对角线,在整个窗口的左上角画圆。实现步骤:第一步:添加WM_PAINT和WM_LBUTTONDOWN消息映射提示:和WM_LBUTTONDOWN类似的鼠标消息还有WM_L/R/MBUTTONUP,WM_R/MBUTTONDOWN/UP,WM_L/R/MBUTTONDBCLICKMFC重要概念——绘制(CDC)针对第一个功能:在非OnPaint画图CRect是一个矩形类voidCDC::MoveTo(intx,inty);将DC移动到某一个位置voidCDC::LineTo(intx,inty);DC从上一位置开始画一条线到传入的(x,y)坐标。MFC重要概念——绘制(CDC)客户窗口(ClientWindow)和窗口的概念。窗口,可以理解为桌面或者屏幕客户窗口,即当前运行的程序的窗口(0,0)(0,0)voidCWnd::GetWindowRect(LPRECTlpRect)voidCWnd::GetClientRect(LPRECTlpRect)MFC重要概念——绘制(CDC)父窗口和子窗口的概念:CWnd*CWnd::GetParent()CWnd*CWnd::GetParent()获取父窗口的大小CWnd*pWnd=GetParent();pWnd->GetClientRect(&rect);MFC重要概念——绘制(CDC)针对功能2:假设鼠标右键点击窗口后,在左上角画一个圆第一步:添加消息映射第二步:实现Ellipse,画圆的原型MFC重要概念——绘制(CDC)设备描述表的属性:
设备描述表(DC)可以看做是一个绘制工具,我们可以根据需要,设置该工具的属性,从而完成相应功能。MFC重要概念——绘制(CDC)例3:文本和背景颜色设置文本颜色可以使用CDC::SetTextColor(COLORREFref)COLORREF实际上是一个RGB一般用法RGB(X,X,X)红色:RGB(255,0,0)绿色:RGB(0,255,0)蓝色:RGB(0,0,255)常用颜色:MFC重要概念——绘制(CDC)上例的实现代码:基于手动生成的MFC框架//inOnPaintCDC::DrawText原型intDrawText(
constCString&str,
LPRECTlpRect,
UINTnFormat
);
这是一个排版模式,一般使用DT_CENTER(水平居中)|DT_VCENTER(垂直居中)MFC重要概念——绘制(CDC)将上例代码进行修改:MFC重要概念——绘制(CDC)画笔(CPen)和画刷(CBrush)的使用例4:矩形绘制:当鼠标点击窗口的某个位置时,以这个位置为起点,画一个长为200,宽为100的矩形。MFC重要概念——绘制(CDC)例4的部分代码展示:调用Crect的构造函数构造BOOL
Rectangle(
int
x1,
int
y1,
int
x2,
int
y2
);
BOOL
Rectangle(
LPCRECT
lpRect
);
函数原型:MFC重要概念——绘制(CDC)更改例4的要求为画一个带有红色边框的矩形:修改后的代码:MFC重要概念——绘制(CDC)例4修改后的代码解析:CPen*pPen=newCPen(PS_SOLID,2,RGB(255,0,0));构造了一个CPen的对象,CPen的构造函数有如下原型:CPen(
int
nPenStyle,
int
nWidth,
COLORREF
crColor
);
笔的属性,可以是PS_SOLID(实线),PS_DASH(虚线),PS_DOT(点线)等。笔的宽度,以像素为单位。MFC重要概念——绘制(CDC)例4修改后的代码解析:CPen*pOldPen=dc.SelectObject(pPen);设备描述表选择使用pPen作为当前的画笔,并返回之前使用的画笔。CPen*
SelectObject(
CPen*
pPen
);
CBrush*
SelectObject(
CBrush*
pBrush
);
virtual
CFont*
SelectObject(
CFont*
pFont
);
CBitmap*
SelectObject(
CBitmap*
pBitmap
);
int
SelectObject(
CRgn*
pRgn
);
CGdiObject*SelectObject(
CGdiObject*pObject
);
CDC::SelectObject的功能就是为当前设备描述表选择一种“工具”来进行绘制,并返回之前使用的“工具”所以使用完后要恢复原“工具”:MFC重要概念——绘制(CDC)更改例4的要求为画一个红色的矩形:修改后的代码:MFC重要概念——绘制(CDC)代码解析:CBrush*pBr=newCBrush(RGB(255,0,0));构造了一个CBrush的对象,CBrush的构造函数有如下原型:nIndex所有取值的样式CBrush(
COLORREF
crColor
);
CBrush(
int
nIndex,
COLORREF
crColor
);explicitCBrush(CBitmap*pBitmap);
MFC重要概念——绘制(CDC)补充,CBitmap的使用VC++可以很方便的显示图片,特别是BMP格式。要显示一张图片一般有如下的步骤。1、准备一张大小合适的BMP图片。2、在资源视图里,利用导入资源导入该图片。3、构建一个CBitmap的对象,利用CBitmap::LoadBitmap(UINT)读取该图片。4、利用画刷就可以将图片“刷”到屏幕的特定位置。MFC重要概念——绘制(CDC)例:CBitmap的使用1、准备一张217x221的图片。2、导入该图片3、导入完成后会自动取名为IDB_BITMAPX补充—资源与资源文件为当前代码加入资源文件,绘制一个图标:切换到资源视图后:补充—资源与资源文件VS会为每个添加的资源按照一定的命名规则进行ID的设置也可以自行设置,右键,属性在ID一栏进行修改,同时注意Filename一栏,有一个icon1.ico标注,该文件存放位置为:当前项目名\项目名\这是一个相对路径,当前项目名类似于程序安装文件夹,因此,为了统一管理资源,可以在当前项目名\项目名下建立不同的资源文件夹管理资源。游戏程序设计—资源与资源文件注意:资源ID也可以是字符串加载资源往往使用LoadXXX函数,对应参数一般为(以Cbitmap为例)://资源字符串名//资源ID名另外:有些函数要求传入资源ID的字符串形式,这时候可以使用MAKEINTRASOURCE宏MFC重要概念——绘制(CDC)4、创建CBitmap对象,LoadBitmap,并构造位图画刷在CView及派生类中要实现画图功能,不需要处理WM_PAINT,而只需要重载CView::OnDraw函数MFC重要概念——绘制(CDC)例4:经过两次修改以后的结果是:有一个黑色的边框,什么原因?怎么去除呢?主要原因是:边框的线使用CPen来画,所以应该创建一支红色的笔。MFC重要概念——绘制(CDC)拓展训练:利用鼠标写字。MFC重要概念——绘制(CDC)代码展示(基于无向导生成的MFC程序):第一步:为窗口类添加成员变量,以保存当前鼠标位置,并添加BOOL变量记录是否开始绘制第二步:添加消息映射,处理WM_MOUSEMOVE(鼠标移动)和WM_LBUTTONDOWN消息第三步:在WM_LBUTTONDOWN的消息处理函数中:操作系统会将鼠标点击的位置传到这个point里。MFC重要概念——绘制(CDC)第四步:在WM_MOUSEMOVE的消息处理函数中:其基本逻辑是:如果目前处于画线状态,首先移动到上一个起点A,然后从点A画一条到当前点B的线,并且保存当前点B位下一次绘制的起点。MFC重要概念——绘制(CDC)绘制的映射模式:简单的说,映射模式是设备描述表(DC)的一个属性,用于确定逻辑坐标值到设备坐标值的一个转换。如:dc.Rectangle(CRect(0,0,200,100));我们知道这是画了一个长为200,宽为100的矩形,但是单位是多少呢?是厘米还是英寸还是像素呢?这时候可以使用CDC::SetMapMode(UINTmode)来设置。但是SetMapMode还有一个功能是设置起点坐标和坐标轴方向。MFC重要概念——绘制(CDC)常用的映射模式及坐标轴对应:映射模式一个逻辑单位对应的距离X轴和Y轴的方向MM_TEXT1像素左上角(0,0)+x+yMM_LOMETRIC0.1MM+x-yMM_HIMETRIC0.01MM+x-yMM_LO/HIENGLISH0.1/0.01IN+x-yMFC重要概念——绘制(CDC)例5:基于前例没有用向导生成的MFC框架,以鼠标点击为起点画一个长为200mm,宽为30mm的具有蓝色边框的绿色矩形。实例代码:(省略消息映射)//创建一个蓝色画笔和一个绿色画刷//使用创建的画笔和画刷并保存原工具//1逻辑单位对应0.1mm//设置映射模式后,y轴向下为负,所以-300运行结果不正常MFC重要概念——绘制(CDC)例5结果运行不正常的原因:
由于我们平时使用坐标系的时候是逻辑坐标系,而不是物理坐标。而在设置映射模式后,原本鼠标点下的位置point的坐标代表的单位却不再是逻辑坐标而是以0.1毫米为单位的坐标,这就造成了运行的不正常。因此,应该将point转换为逻辑坐标。使用:voidCDC::DPtoLP(
LPPOINT
lpPoints,
int
nCount
=
1
)
const;
voidCDC::DPtoLP(
LPRECT
lpRect
)
const;
voidCDC::DPtoLP(
LPSIZE
lpSize
)
const;
MFC重要概念——绘制(CDC)例5的正常代码:将鼠标点击位置的设备(物理)坐标转换为逻辑坐标。MFC重要概念——绘制(CDC)绘图模式:例6.1:橡皮筋线的绘制
基本思路:和用鼠标写字的例子类似,但不同的是我们需要保留一开始的起点,以便鼠标左键放开后,能绘制一条从原始起点到开始起点的线。同时,需要保留当前鼠标移动到的位置,以绘制一条从起点到当前鼠标位置的线。鼠标按下的起点鼠标移动时的点鼠标放开时的终点MFC重要概念——绘制(CDC)第一步:添加一个保存鼠标点击起点的变量第二步:在OnLButtonDown消息处理函数中保存起点坐标。第三步:在OnMouseMove消息处理函数中画线。MFC重要概念——绘制(CDC)运行结果:有问题鼠标按下的起点鼠标移动时的点鼠标放开时的终点问题的关键是原来画的线没有被删
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 综合服务单项合同范本
- 专业定制代理记账服务合同
- 银行贷款续借合同范例分析
- 幼儿园转让合同协议范本
- 五金配件供应商购销合同
- 个人借款合同的还款指南
- 珠宝首饰经销商合同
- 标准砂石材料购销合同
- 股权转让持股协议样本
- 大额借款合同范本
- 2024版年度树立正确就业观课件
- 2024年心理咨询师考试题库附参考答案(满分必刷)
- GB/T 44111-2024电化学储能电站检修试验规程
- 买车挂别人名下协议书范本
- 初中历史七上第一单元作业设计
- 01467-土木工程力学(本)-国开机考参考资料
- 2024年沧州市金融控股有限公司招聘笔试冲刺题(带答案解析)
- 护士延续注册体检表
- 泌尿科一科一品汇报课件
- 西湖生死学智慧树知到期末考试答案章节答案2024年浙江传媒学院
- 不同地区城镇化的过程和特点(第1课时)高中地理中图版(2019)必修二
评论
0/150
提交评论