MFC学习笔记窗口创建.docx
《MFC学习笔记窗口创建.docx》由会员分享,可在线阅读,更多相关《MFC学习笔记窗口创建.docx(21页珍藏版)》请在冰豆网上搜索。
MFC学习笔记窗口创建
MFC
hierarchychart(类库列表)
MFC与Win32
1win32:
函数,使用API一步一步搭建应用程序。
(常使用FileView操作)
2MFC编程:
实现仍然调用API函数,但是是用类封装API函数,使用向导自动生成应
用程序框架。
(常使用ClassView操作)
2.1需要掌握的技能
2.1.1断点调试
2.1.2堆栈调用的查看
MFC课程内容
1MFC:
MFC的六大机制,文档式架构,常用的MFC类,(10--12)。
2COM(组件对象模型):
COM的原理和应用(6)。
3ADO/Socket:
MFC访问数据库以及一些简单的网络编程。
MFC应用程序编程
1MFC的历史:
92(VC1)98(VC6)……………………….
2MFC库基础:
2.1MFC库,微软基础类库。
封装了Windows应用程序编程的各种API以及相关机制
的C++类库
3类库的相关头文件件
★afx-applicationframework(应用程序框架x)
3.1-不是类库头文件,是项目的头文件,称为VC下编译的预编译头文件,
用来提高编译速度的。
(*.pch)(头文件是不参加编译的但是他参与生成*.pch)
3.2-几乎包含了各种常用的MFC有文件
3.3-提供扩展窗口类的支持(创建工具栏,状态栏等………)
MFC应用程序的类型
1支持MFC的控制台应用程序(控制台的第四个选项)
1.1多了一个CWinApp(应用程序类,封装类应用程序启动过沉重所涉及到得相
关信息)的全局对象(必须有,而且只能有一个)
1.2主函数中多了一个AfxWinInit函数,初始化MFC库中的相关信息
2MFC库程序
2.1MFC支持的静态库
2.2MFC支持的动态库
2.2.1MFC规则库(sharedMFCDLL)-可以被各种应用程序调用(非MFC程
序,没有MFC类也可以调用)
★还是有一个CWinApp派生的CMFC_DLLApp类对象
2.2.2MFC扩展库(usingsharedMFCDLL)-只能被MFC库所编写的应用程
序所调用(对原有的MFC类扩展)
★DllMain主函数只能被MFC程序调用
3MFC应用程序-----(注意看父类,子类名字可能不一样)
3.1单文档视图应用程序
★CWinApp应用程序类
★CAboutDlg(对话框-生成关于窗口-和框架没有任何关系)
★CMainFrame(父类是:
CFrameWnd)(应用程序主框架窗口类-生成应用程
序的主框架-负责各个对象的协调工作)
★CDocument(它是父类)(文档类-看不到的很重要-管理数据)
★CView(它是父类)(视图类-显示数据并和用户进行交互)
★CSingleDocApp(父类是CWinApp)-(使用前面的3个类来创建对象)
3.2多文档视图架构
★CWinApp应用程序类
★CAboutDlg(对话框-生成关于窗口-和框架没有任何关系)
★CView(它是父类)(视图类-显示数据并和用户进行交互)
★CDocument(它是父类)(文档类-看不到的很重要-管理数据)
★CMDIChildWnd(子框架窗口类,父类)
★CMDIFrameWnd(主框架窗口类,父类)
我们看到的子窗体其实是★CView和★CMDIChildWnd叠加的
3.3基于对话框的应用程序
★CWinApp应用程序类
★CDialog(对话框窗口类)
★★m_pMainWnd保存主窗口地址
DoModal显示对话框
MFC相关类的说明
1继承自CObject
1.1CObject类:
绝大多数MFC类的父类,提供了MFC库的一些机制
1new/delete操作符,定义了与构造函数相关的内存分配函数
2assert和dump调试,堆调试的支持
★3运行时类信息-属于哪个类,还有类的层次结构
★4动态创建
★5序列化
1.2CWinThread:
线程类。
1.2CwinAPP类:
封装了类应用程序,线程等的初始化信息,是应用程序开始创建
的第一个对象,并且也是结束前最后一个执行的对象,启动时应用程序类负责创建其余的对象。
1.3CDocTemplate类:
文档模板类,应用程序打开一个文档时,文档模板定义创
建什么的框架,文档和视图
两个子类CSingleDocTemplate(单文档)和CMultiDocTemplate(多文档)(注意:
InitInstance()函数)
1.4CFramWnd类:
框架窗口类
1.5CSplitterWnd类:
拆分窗口类
1.6CControlBar类:
工具栏类
1.7CPropertySheet类:
属性表单类-一个属性表单里面有很多属性页用
CPropertyPage类创建
1.8CDialog类:
对话框类
CCommonDialog通用对话框(各种颜色,字体,什么对话框)
COlePropertyPage-页对话框
1.9CView类:
视图类
1.10控件类:
CAnimateCtrl视频类
CButton按钮类
CComboBox组合框类
CLIstBox列表框
1.11CDucument类:
文档类
1.12CException类:
异常处理类
1.13CFile类:
文件处理类和序列化结合讲解
1.14画图类:
CDC:
绘图设备上下文类-(相当于纸)
CGdiObject-(相当于笔)
5.1.15集合类
CArray动态数组-查询快-查找都是从头找,如果数组很大,查找效率低
CLIst链表-底层双向链表-删除,插入块
Cmap映射-快速查找-(key,value)
CFileFind-文件查找类-同CFile一块用
2非CObject的子类
提供了各种数据结构的相关管理。
第一个MFC程序
1设置MFC开发环境
1.1修改头文件
1.2设置工程为使用MFC库(Seeting->UseMFCinashareDLL)
以下注意:
★加上:
:
的是调用的全局Win32函数,不加调用的是该类的成员函数
★窗口类对象和窗口(句柄,内存空间标识)有很大区别,窗口类对象是
用来操作窗口的,对象创建出来并不是创建出窗口了
VC6断点调试的操作:
F9(设断点),F5(跳到下一个断点),F10(执行下一条语句),
F11(当前语句如果有函数能进入就进入,不能进入执行一条语句)
(ALT+F9)(打开断点调试列表),ALT+F8(代码自动对齐)
F12(选中宏或者类,能看原型,类型能看原型)
★堆栈工具条里面:
下面的调用上边的(有时系统调用我写的,有时我写的函数调用系统的)
2程序的编写
★2.1定义CWinApp类的子类,并且定义该类的全局变量
例:
classCMyWinApp:
publicCWinApp
{
public:
virtualBOOLInitInstance();
};
CMyWinApptheApp;
★2.2定义CFrameWnd类的子类(主框架窗口类)
例:
classCMainFrame:
publicCFrameWnd
{
virtualLRESULTWindowProc(UINTmessage,WPARAMwParam,LPARAMlParam);
};
★2.3在CWinApp类的InitInstance函数中,创建CFrameWnd窗口,并显示
例:
BOOLCMyWinApp:
:
InitInstance()
{
//创建应用程序窗口
//创建框架窗口类对象
CMainFrame*pFrame=newCMainFrame();
//创建窗口
pFrame->Create(NULL,"MFC_Wnd");
//将窗口赋值成为当前用用程序的主窗口
m_pMainWnd=pFrame;
//显示主窗口
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateData();
returnTRUE;
}
★2.4实现CFrameWnd的WindowProc函数,处理消息
★例:
LRESULTCMainFrame:
:
WindowProc(UINTmessage,WPARAMwParam,LPARAMlParam){
switch(message){
caseWM_PAINT:
PAINTSTRUCTps={0};
CDC*hDc=BeginPaint(&ps);
hDC->TextOut(hDC,100,100,"HelloMFC",9);
EndPaint(&ps);
break;
}
returnCFrameWnd:
:
WindowProc(message,wParam,lParam);
}
MFC程序的启动-(入口函数机制)
1程序的入口在哪?
(MFC的第一个机制:
入口函数机制)
★第一步:
程序启动,调用CWinApp的构造,将CWinApp的对象theApp的地址保
存到模块状态信息中,将theApp的地址保存到线程状态信息中。
★第二步:
WinMain调用AfxWinMain(内核自动调用,不是说哪个函数调用,要不
是声明了一个全局变量,它才是第一步)
★第三步:
AfxWinMain函数的执行
3.1获取当前应用程序对象theApp(CFrameWnd类的子类的对象)的地址
使用AfxGetThread()函数从线程信息中获取
使用AFxGetApp()从模块信息中获取。
3.2使用AfxWinInit()初始化MFC库
3.3使用InitApplication()函数初始化应用程序数据
3.4调用CMyWinApp:
:
InitInstance()函数创建并显示窗口
3.5调用App的Run函数进行消息循环处理
3.6结束MFC库,退出程序。
2MFC的窗口创建过程和Win32创建过程一样
3CWinApp类
应用程序封装类,父类是CWinThread,封装程序的初始化,信息,消息循环等。
InitInstance-程序的初始化函数,完成窗口的创建等初始化工作
ExitInstance-程序突出时调用的函数,完成资源释放等善后工作
Run-消息循环
OnIdle-空闲处理函数
m_pMainWnd-当前程序的主窗口
一般先创建窗口然后设置为主窗口:
m_pMainWnd=pFrame;
窗口的创建-(窗口创建机制)
1窗口的消息处理函数是AfxWndProcBase,但是窗口类设计时不是他
是wndcls.lpfWndProc=DefWindowProc
2窗口的创建过程
2.1如果有的话加载菜单
2.2调用CWnd的CreateEx创建窗口
2.2.1PreCreateWindow设计并注册窗口类
此时是将DefWindowProc设置成为窗口的处理函数
2.2.2调用AfxHookWindowCreate()创建钩子函数,在函数内部调用
SetWindowsHookEx创建WH_CBT(窗口创建就创建钩子),钩子
的处理函数是_AfxCbtFilterHook(Ctrl+F能查找到在本文件定义
的函数的位置)
2.2.3调用CreateWindowEx()函数创建窗口立即调用钩子函数
2.2.4卸载钩子,并返回。
2.3在_AfxCbtFilterHook函数中
2.3.1调用AfxGetAfxWndProc获取MFC提供的窗口处理函数的地址
2.3.2使用SetWindowLong函数将该窗口处理函数设置成MFC提供的窗口处
理函数
为什么要替换?
消息处理-(消息映射机制)
不再是所有消息走一个函数而是一个消息对应一个消息处理函数
1消息映射的使用
1.1在CMainFrame类的定义中,添加消息映射声明DECLARE_MESSAGE_MAP()(宏可没有分号)
1.2在CMainFrame类的实现中,添加消息映射实现宏
BEGIN_MESSAGE_MAP(className(实现类),baseclassName(实现类的父类))
END_MESSAGE_MAP()
1.3在类中定义并且实现消息映射的处理函数。
1.4在消息映射的实现宏中,添加消息与消息处理函数的对应关系
ON_MESSAGE(WM_CREATE(消息),OnCreate(消息处理函数的函数名称))
例:
classCMainFrame:
publicCFrameWnd
{
DECLARE_MESSAGE_MAP()//消息映射声明宏
voidOnMyCreate();
voidOnMyPaint();
};
BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)//消息映射实现宏
ON_MESSAGE(WM_PAINT,OnMyPaint)//对应关系
ON_MESSAGE(WM_CREATE,OnMyCreate)
END_MESSAGE_MAP()
宏的具体实现
★DECLARE_MESSAGE_MAP()//消息映射声明宏
***************************替换消息映射声明宏代码**************************
private:
staticconstAFX_MSGMAP_ENTRY【1】_messageEntries[];
protected:
staticAFX_DATAconstAFX_MSGMAP【2】messageMap;
staticconstAFX_MSGMAP*PASCAL_GetBaseMessageMap();
virtualconstAFX_MSGMAP*GetMessageMap()const;
★BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)//消息映射实现宏
ON_MESSAGE(WM_PAINT,OnMyPaint)//对应关系
ON_MESSAGE(WM_CREATE,OnMyCreate)
END_MESSAGE_MAP()
********************************消息映射实现宏*********************************
constAFX_MSGMAP*PASCALCMainFrame:
:
_GetBaseMessageMap()
{
return&CFrameWnd:
:
messageMap;【5】
}
constAFX_MSGMAP*CMainFrame:
:
GetMessageMap()const
{
return&CMainFrame:
:
messageMap;【6】
}
AFX_COMDATAFX_DATADEFconstAFX_MSGMAPCMainFrame:
:
messageMap=
{
&CMainFrame:
:
_GetBaseMessageMap,【3】
&CMainFrame:
:
_messageEntries[0]【4】
};
AFX_COMDATconstAFX_MSGMAP_ENTRYCMainFrame:
:
_messageEntries[]=
{
{WM_CREATE,0,0,0,AfxSig_lwl,
(AFX_PMSG)(AFX_PMSGW)
(LRESULT(AFX_MSG_CALLCWnd:
:
*)
(WPARAM,LPARAM))&OnMyCreate},
{WM_PAINT,0,0,0,AfxSig_lwl,
(AFX_PMSG)(AFX_PMSGW)
(LRESULT(AFX_MSG_CALLCWnd:
:
*)
(WPARAM,LPARAM))&OnMyPaint},
{0,0,0,0,AfxSig_end,(AFX_PMSG)0}
};
2宏代码分析
1.2.1_messageEntries[]数组(用结构保存每一个消息和其对应处理函数等消息信息,实
现消息映射机制)其类型为AFX_MSGMAP_ENTRY结构【1】
structAFX_MSGMAP_ENTRY
{
UINTnMessage;//消息ID或者标识(WM_XXXX)★
UINTnCode;//通知码或者控制码(消息的分类)
UINTnID;//空间的ID(是"0"的话代表窗口消息)
UINTnLastID;//指定一个消息的ID范围的最大值
UINTnSig;//消息处理函数的类型
AFX_PMSGpfn;//处理这个消息函数的指针★
};
1.2.2messageMap的类型AFX_MSGMAP(通过这个结构可以找到所有的相关父子类
中消息)【2】
structAFX_MSGMAP
{
//保存“获得父类的AFX_MSGMAP函数”的指针(类似链表)
constAFX_MSGMAP*(PASCAL*pfnGetBaseMap)();【3】
constAFX_MSGMAP_ENTRY*lpEntries;//当前的_messageEntries[]数组的地址【4】
};
3作用
3.1_messageEntries[]数组
静态数组,类型AFX_MSGMAP_ENTRY数组中的每个元素保存了消息ID和与之
对应的处理函数的地址。
3.2messageMap
静态变量,类型是AFX_MSGMAP,分别保存了_messageEntries[]数组的地址,以
及_GetBaseMessageMap函数的地址
3.3_GetBaseMessageMap()
静态函数,获取父类的messageMap变量的地址【5】
3.4GetMessageMap()
虚函数,获取本类的messageMap变量的地址【6】
4调用关系
CMainFrame:
:
GetMessageMap()
★|->messageMap
★|->_messageEntries[]
★|->消息ID,函数指针
★|->_GetBaseMessageMap()
☆|->CFrameWnd:
:
messageMap
☆|->CFrameWnd:
:
_messageEntries[]
☆|->CFrameWnd的消息ID,CFrameWnd的消息处理函数指针
☆|->CFrameWnd:
:
_GetBaseMessageMap()
○|->CWnd:
:
messageMap
○|->CWnd:
:
_messageEntries[]
○|->CWnd的消息ID,CWnd的消息处理函数指针
○|->CWnd:
:
GetMessageMap()
◆|->NULL(直到空结束,链表结束)
1.5执行过程
我们可以定义一些消息的处理,但是许多消息没有自己定义,根据处理机制中的链表关
系,一级一级一直向上找,直至CWnd调用默认处理函数DefWindowProc
★执行过程
1.5.1调用窗口对象的GetMessageMap()(虚函数不是静态的),获得当前类的messageMap
(静态的)地址pMessageMap
1.5.2从pMessageMap的_messageEntries[]数组中查找消息ID所对应的数组元素。
如果
找到执行goto语句。
1.5.3如果没有找到,调用pMessageMap中的pBaseMap,获得父类的pMessageMap,
继续查找
1.5.4如果直到pMessageMap为空还没有找到,结束查找,调用DefWindowProc的默
认处理函数
1.5.5使用查找到的lpEntry,根据数组元素lpEntry中的消息处理函数的类型,调用消息
处理函数。
★根据堆栈调用显示:
1首先CWnd:
:
WindowProc调用CWnd:
:
OnWndMsg
RESULTCWnd:
:
WindowProc(UINTmessage,WPARAMwParam,LPARAMlParam)
{
LRESULTlResult=0;
if(!
OnWndMsg(message,wParam,lParam,&lResult))
//直到CWnd都无这个消息,代表OnWndMsg执行失败,调用默认的DefWindowProc
lResult=DefWindowProc(message,wParam,lParam);
returnlResult;
}
2消息找到了,CWnd:
:
OnWndMsg的执行过程
//首先调用当前的GetMessageMap()
constAFX_MSGMAP*pMessageMap;pMessageMap=GetMessageMap();
//进入消息映射链表循环中
for(;pMessageMap!
=NULL;pMessageMap=pMessageMap->pBaseMap)
{
if(message<0xC000)
{
if((lpEntry=AfxFindMessageEntry(pMessageMap->lpEntries,message,
0,0))!
=NULL)
{
pMsgCache->lpEntry=lpEntry;
AfxUnlockGlobals(CRIT_WINMSGCACHE);