Lesson 04MFC骨干程序.docx
- 文档编号:5245935
- 上传时间:2022-12-14
- 格式:DOCX
- 页数:14
- 大小:101.41KB
Lesson 04MFC骨干程序.docx
《Lesson 04MFC骨干程序.docx》由会员分享,可在线阅读,更多相关《Lesson 04MFC骨干程序.docx(14页珍藏版)》请在冰豆网上搜索。
Lesson04MFC骨干程序
Lesson04MFC骨干程序
本课讲述一个完整的MFC应用程序骨干,包括工具栏、状态栏以及很重要的Document/View结构概念。
一、Document/View支撑应用程序
在程序中不论什么类型,数据总是有体有面,实际的数据数值就是体,显示在屏幕上(甚至打印机上)的画面就是面。
“数值的处理”应该使用字节、整数、浮点数、链表、数组等数据结构,而“数值的表现”应该使用绘图工具,如坐标系统、笔刷颜色、点线圆弧、字形……,如下图:
图1Document是数据的体,View是数据的面
除了负责显示外,View还负责程序与使用者之间的交谈接口。
使用者对数据的编辑、修改都需要依靠窗口上的鼠标和键盘操作才能完成,这些消息都由View接受后再通知Ducument,如下图:
图2View负责与使用者接触
Document/View的价值在于,这些MFC类已经把一个应用程序所需的“数据处理与显示”的函数空壳都设计好了,都是虚函数,所以程序员可以(也应该)在派生类中改写它们。
有关文件读写的操作在CDocument的Serialize函数中进行,有关画面显示的操作在CView的OnDraw或OnPaint函数中进行。
二、MFC骨干程序
以一个多文档程序Scribble为例,说明MFC骨干程序。
图3是一个多文档应用程序所使用的MFC类的层次结构图:
图3多文档应用程序使用的MFC类
1.Scribble程序中各类的相关数据如下:
表1MDI程序中的主要类
类名称
基类
类声明于
类定义于
CScribbleApp
CWinApp
Scribble.h
Scribble.cpp
CMainFrame
CMDIFrameWnd
Mainfrm.h
Mainfrm.cpp
CChildFrame
CMDIChildWnd
Childfrm.h
Childfrm.cpp
CScribbleDoc
CDocument
ScribbleDoc.h
ScribbleDoc.cpp
CScribbleView
CView
ScribbleView.h
ScribbleView.cpp
CAboutDlg
CDialog
Scribble.cpp
Scribble.cpp
2.骨干程序(MDI)使用的所有MFC类
表2MDI程序使用的所有MFC类
MFC类名称
用户类名称
功能
CWinApp
CScribbleApp
应用程序对象
CMDIFrameWnd
CMainFrame
MDI主窗口
CMultiDocTemplate
直接使用
管理Document/View
CDocument
CScribbleDoc
文档,负责数据结构与文件操作
CView
CScribbleView
视图,负责数据的显示与打印
CMDIChildWnd
CChildFrame
MDI子窗口
CToolBar
直接使用
工具栏
CStatusBar
直接使用
状态栏
CDialog
CAboutDlg
About对话框
3.程序中的九个对象如图4
图4Scribble程序中的九个对象
注意:
虚线框表示应用程序通常不必改写该基础类,可以直接用
4.程序流程说明如下:
(1)~(4)theApp应用程序对象:
AfxWinMain()内部执行与前一课相同。
(5)改写InitInstance虚函数。
(6)new一个CMultiDocTemplate对象,该对象规划Document、View以及DocumentFrame窗口三者之间的关系。
(7)new一个CMyMDIFrameWnd对象,作为主窗口对象。
(8)调用LoadFrame,产生主窗口并加挂菜单等元素,指定窗口标题、文件标题、文件扩展名等(关键在IDR_MAINFRAME常量)。
LoadFrame内部将调用Create,后者将调用CreateWindowEx,于是触发WM_CREATE消息。
(9)由于在CMainFrame之中拦截WM_CREATE(利用ON_WM_CREATE宏),所以WM_CREATE产生之际Framework会调用OnCreate。
在此为主窗口挂上工具栏和状态栏。
(10)回到InitInstance,执行ShowWindow显示窗口。
(11)InitInstance结束,回到AfxWinMain,执行Run,进入消息循环。
(12)消息经过MessageRouting机制,在各类的MessageMap中寻求其相应的处理程序。
WM_COMMAND/ID_FILE_OPEN消息将由CWinApp:
:
OnFileOpen函数处理,此函数由MFC提供,在显示过[FileOpen]对话框之后调用Serialize函数。
(13)改写Serialize函数进行我们自己的读写操作。
(14)WM_COMMAND/ID_APP_ABOUT消息将由OnAppAbout函数处理。
(15)OnAppAbout函数利用CDialog的性质很方便地产生一个对话框。
5.DocumentTemplate的意义
程序每打开一份文件(数据),就会产生三份对象:
(1)一份Document对象(数据内容)
(2)一份View对象(数据表象)
(3)一份CMDIChildWnd对象,其作为外框窗口(容纳数据表象)
这三份对象由DocumentTemplate对象来管理,关键在CMultiDocTemplate:
BOOLCScribbleApp:
:
InitInstance()
{
……
CMultiDocTemplate*pDocTemplate;
pDocTemplate=newCMultiDocTemplate(
IDR_SCRIBBTYPE,
RUNTIME_CLASS(CScribbleDoc),
RUNTIME_CLASS(CChildFrame),//customMDIchildframe
RUNTIME_CLASS(CScribbleView));
AddDocTemplate(pDocTemplate);
……
}
如果程序支持不同的数据格式,如TEXT和BITMAP,则需要不同的DocumentTemplate:
BOOLCMyWinApp:
:
InitInstance()
{
……
CMultiDocTemplate*pDocTemplate;
pDocTemplate=newCMultiDocTemplate(
IDR_TEXTTYPE,
RUNTIME_CLASS(CTextDoc),
RUNTIME_CLASS(CChildFrame),//customMDIchildframe
RUNTIME_CLASS(CTextView));
AddDocTemplate(pDocTemplate);
pDocTemplate=newCMultiDocTemplate(
IDR_BMPTYPE,
RUNTIME_CLASS(CBmpDoc),
RUNTIME_CLASS(CChildFrame),//customMDIchildframe
RUNTIME_CLASS(CBmpView));
AddDocTemplate(pDocTemplate);
……
}
CMultiDocTemplate的构造函数:
CMultiDocTemplate(UINTnIDResource,
CRuntimeClass*pDocClass,
CRuntimeClass*pFrameClass,
CRuntimeClass*pViewClass);
参数:
●nIDResource
SpecifiestheIDoftheresourcesusedwiththedocumenttype.Thismayincludemenu,icon,acceleratortable,andstringresources.
注意:
不同种类的资源可以使用相同的ID
IDR_SCRIBBTYPEICONDISCARDABLE"res\\ScribbleDoc.ico"
IDR_SCRIBBTYPEMENUPRELOADDISCARDABLE
……
STRINGTABLEPRELOADDISCARDABLE
BEGIN
IDR_MAINFRAME"Scribble"
IDR_SCRIBBTYPE"\nScribb\nScribb\n\n\nScribble.Document\nScribbDocument”
END
●pDocClass
PointstotheCRuntimeClassobjectofthedocumentclass.ThisclassisaCDocument-derivedclassyoudefinetorepresentyourdocuments.
●pFrameClass
PointstotheCRuntimeClassobjectoftheframe-windowclass.ThisclasscanbeaCMDIChildWnd-derivedclass,oritcanbeCMDIChildWnditselfifyouwantdefaultbehaviorforyourdocumentframewindows
●pViewClass
PointstotheCRuntimeClassobjectoftheviewclass.ThisclassisaCView-derivedclassyoudefinetodisplayyourdocuments
关于字符串资源:
以‘\n’分隔为七个子字符串
如本例中:
\nScribb\nScribb\n\n\nScribble.Document\nScribbDocument
按顺序各子字符串意义:
每个子字符串都可在程序进行过程中取得,调用CDocTemplate:
:
GetDocString并在第二个参数中指定索引值(1~7)即可。
最好以CDocTemplate所定义的七个常量代替索引值。
CDocTemplate的七个常量定义:
(文件:
AFXWIN.H)
#ifdef_AFXDLL
classCDocTemplate:
publicCCmdTarget
#else
classAFX_NOVTABLECDocTemplate:
publicCCmdTarget
#endif
{
……
enumDocStringIndex
{
windowTitle,//defaultwindowtitle
docName,//uservisiblenamefordefaultdocument
fileNewName,//uservisiblenameforFileNew
//forfilebaseddocuments:
filterName,//uservisiblenameforFileOpen
filterExt,//uservisibleextensionforFileOpen
//forfilebaseddocumentswithShellopensupport:
regFileTypeId,//REGEDITvisibleregisteredfiletypeidentifier
regFileTypeName,//Shellvisibleregisteredfiletypename
};
……
}
程序中可以象下面这样:
CStringstrDefExt,strDocName;
pDocTemplate->GetDocString(strDefExt,CDocTemplate:
:
filterExt);
pDocTemplate->GetDocString(strDocName,CDocTemplate:
:
docName);
七个子字符串的具体意义:
Index
意义
1.CDocTemplate:
:
windowTitle
主窗口标题栏上的字符串,SDI程序要指定,MDI程序不需要指定,以IDR_MAINFRAME字符串为默认值。
2.CDocTemplate:
:
docName
文件基底名,加流水号码为新文件名,未指定文件默认名称为“Untitled”
3.CDocTemplate:
:
fileNewName
文件类型名称,程序支持多文件,此字符串会显示在新建文件对话框,否则不显示,新建文件时也不会显示对话框。
4.CDocTemplate:
:
filterName
打开文件时的过滤字符串
5.CDocTemplate:
:
filterExt
文件扩展名,未指明时不能在打开文件对话框中处理该类文件
6.CDocTemplate:
:
regFileTypeId
注册表中注册的文件类型,未指明则无法注册,鼠标拖放功能受影响
7.CDocTemplate:
:
regFileTypeName
也是存储在注册表中的文件类型。
6.Document/View设计
(1)文件读写
CDocument中的Serialize函数。
(2)数据的显示与编辑等
●DocumentFrame窗口收到WM_PAINT消息,窗口内的View的OnPaint函数被调用,OnPaint又调用OnDraw。
所以为了显示数据一般要改写OnDraw。
OnPaint一般只输出到屏幕而不到打印机。
●为了接受编辑操作,一般在View中接受鼠标或键盘消息并处理。
例如:
afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);
afx_msgvoidOnLButtonUp(UINTnFlags,CPointpoint);
afx_msgvoidOnMouseMove(UINTnFlags,CPointpoint);
7.主窗口的诞生
建立MDI主窗口:
new一个CMDIFameWnd对象;调用LoadFrame函数
LoadFrame源代码如下:
(文件:
WINFRM.CPP)
BOOLCFrameWnd:
:
LoadFrame(UINTnIDResource,DWORDdwDefaultStyle,
CWnd*pParentWnd,CCreateContext*pContext)
{
//onlydothisonce
ASSERT_VALID_IDR(nIDResource);
ASSERT(m_nIDHelp==0||m_nIDHelp==nIDResource);
m_nIDHelp=nIDResource;//IDforhelpcontext(+HID_BASE_RESOURCE)
CStringstrFullString;
if(strFullString.LoadString(nIDResource))
AfxExtractSubString(m_strTitle,strFullString,0);//firstsub-string
VERIFY(AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG));
//attempttocreatethewindow
LPCTSTRlpszClass=GetIconWndClass(dwDefaultStyle,nIDResource);
LPCTSTRlpszTitle=m_strTitle;
if(!
Create(lpszClass,lpszTitle,dwDefaultStyle,rectDefault,
pParentWnd,MAKEINTRESOURCE(nIDResource),0L,pContext))
{
returnFALSE;//willselfdestructonfailurenormally
}
//savethedefaultmenuhandle
ASSERT(m_hWnd!
=NULL);
m_hMenuDefault=:
:
GetMenu(m_hWnd);
//loadacceleratorresource
LoadAccelTable(MAKEINTRESOURCE(nIDResource));
if(pContext==NULL)//sendinitialupdate
SendMessageToDescendants(WM_INITIALUPDATE,0,0,TRUE,TRUE);
returnTRUE;
}
窗口产生之际会发出WM_CREATE消息,CMainFrame:
:
OnCreate会被执行,在那里进行工具栏和状态栏的建立。
LoadFrame函数的参数(IDR_MAINFRAME)用来设定窗口所使用的资源。
IDR_MAINFRAMEICONDISCARDABLE"res\\Scribble.ico"
IDR_MAINFRAMEMENUPRELOADDISCARDABLE
{……}
IDR_MAINFRAMEACCELERATORSPRELOADMOVEABLEPURE
{……}
STRINGTABLEPRELOADDISCARDABLE
BEGIN
IDR_MAINFRAME"Scribble"(将作为主窗口的标题)
……
END
LoadFrame执行如图5所示:
图5构建MDI主窗口
8.工具栏和状态栏的产生(Toolbar&Statusbar)
(1)工具栏和状态栏对象声明
(2)OnCreate函数中与工具栏和状态栏的产生和设定有关的操作
●IDR_MAINFRAME在RC文件中代表两种与工具栏有关的资源:
BITMAP和TOOLBAR
●状态栏中有关indicators的七种定义(文件:
AFXRES.H)
//Modeindicatorsinstatusbar-theseareroutedlikecommands
#defineID_INDICATOR_EXT0xE700//extendedselectionindicator
#defineID_INDICATOR_CAPS0xE701//caplockindicator
#defineID_INDICATOR_NUM0xE702//numlockindicator
#defineID_INDICATOR_SCRL0xE703//scrolllockindicator
#defineID_INDICATOR_OVR0xE704//overtypemodeindicator
#defineID_INDICATOR_REC0xE705//recordmodeindicator
#defineID_INDICATOR_KANA0xE706//kanalockindicator
例子程序中使用的三种:
9.工具栏和状态栏的产生(Toolbar&Statusbar)
每一个派生自CCmdTarget的类都可以有自己的MessageMap用于处理消息。
先在类声明处加DECLARE_MESSAGE_MAP宏,然后在.cpp文件中使用BEGIN_MESSAGE_MAP和END_MESSAGE_MAP两个宏,宏中间的就是消息与处理函数的对应关系。
例如CScribbleApp类中的消息映射:
BEGIN_MESSAGE_MAP(CScribbleApp,CWinApp)
//{{AFX_MSG_MAP(CScribbleApp)
ON_COMMAND(ID_APP_ABOUT,OnAppAbout)
//NOTE-theClassWizardwilladdandremovemappingmacroshere.
//DONOTEDITwhatyouseeintheseblocksofgeneratedcode!
//}}AFX_MSG_MAP
//Standardfilebaseddocumentcommands
ON_COMMAND(ID_FILE_NEW,CWinApp:
:
OnFileNew)
ON_COMMAND(ID_FILE_OPEN,CWinApp:
:
OnFileOpen)
//Standardprintsetupcommand
ON_COMMAND(ID_FILE_PRINT_SETUP,CWinApp:
:
OnFilePrintSetup)
END_MESSAGE_MAP()
10.标准菜单File/Edit/View/Window/help
MDI程序一般会有两组菜单:
一种是当没有任何子窗口(文件窗口)存在时出现(本例代码是IDR_MAINFRAME),另一组是当有任何子窗口(文件窗口)存在时出现(本例代码是IDR_SCRIBTYPE)。
菜单内容
命令项ID
默认的处理函数
预有关联
File
New
ID_FILE_NEW
CWinApp:
:
OnFileNew
No
Open
ID_FILE_OPEN
CWinApp:
:
OnFileOpen
No
Close
ID_FILE_CLOSE
CDocument:
:
OnFileClose
Yes
Save
ID_FILE_SAVE
CDocument:
:
OnFileSave
Yes
SaveAs
ID_FILE_SAVEAS
CDocument:
:
OnFileSaveAs
Yes
ID_FILE_PRINT
CView:
:
OnFilePrint
No
PrintPre&view
ID_FILE_PRINT_PREVIEW
CView:
:
OnFilePrintPreview
No
PrintSetup
ID_FILE_PRINT_SETUP
CWinApp:
:
OnFilePrintSetup
No
"RecentFileName"
ID_FILE_MRU_FILE1~4
CWinApp:
:
OnOpenRecentFile
Yes
Exit
ID_APP_EXIT
CWinApp:
:
OnFileExit
Yes
Edit
Undo
ID_EDIT_UNDO
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Lesson 04MFC骨干程序 04 MFC 骨干 程序
![提示](https://static.bdocx.com/images/bang_tan.gif)