深入浅出MFC第2版(PDF格式)-第87部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
#0089
#0090 static UINT indicators'' =
#0091 {
#0092 ID_SEPARATOR;
#0093 ID_INDICATOR_CAPS;
#0094 ID_INDICATOR_NUM;
#0095 ID_INDICATOR_SCRL;
#0096 };
#0097
#0098 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
#0099 {
#0100 m_wndToolBar。Create(this);
#0101 m_wndToolBar。LoadToolBar(IDR_MAINFRAME);
#0102 m_wndStatusBar。Create(this);
#0103 m_wndStatusBar。SetIndicators(indicators;
#0104 sizeof(indicators)/sizeof(UINT));
#0105
#0106 m_wndToolBar。SetBarStyle(m_wndToolBar。GetBarStyle() |
#0107 CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
#0108
#0109 m_wndToolBar。EnableDocking(CBRS_ALIGN_ANY);
427
…………………………………………………………Page 490……………………………………………………………
第篇 湷觥 FC 程式設計
#0110 EnableDocking(CBRS_ALIGN_ANY);
#0111 DockControlBar(&m_wndToolBar);
#0112 return 0;
#0113 }
#0114
#0115 IMPLEMENT_DYNCREATE(CChildFrame; CMDIChildWnd)
#0116
#0117 BEGIN_MESSAGE_MAP(CChildFrame; CMDIChildWnd)
#0118 END_MESSAGE_MAP()
#0119
#0120 IMPLEMENT_DYNCREATE(CScribbleDoc; CDocument)
#0121
#0122 BEGIN_MESSAGE_MAP(CScribbleDoc; CDocument)
#0123 END_MESSAGE_MAP()
#0124
#0125 void CScribbleDoc::Serialize(CArchive& ar)
#0126 {
#0127 if (ar。IsStoring())
#0128 {
#0129 // TODO: add storing code here
#0130 }
#0131 else
#0132 {
#0133 // TODO: add loading code here
#0134 }
#0135 }
#0136
#0137 IMPLEMENT_DYNCREATE(CScribbleView; CView)
#0138
#0139 BEGIN_MESSAGE_MAP(CScribbleView; CView)
#0140 ON_MAND(ID_FILE_PRINT; CView::OnFilePrint)
#0141 ON_MAND(ID_FILE_PRINT_DIRECT; CView::OnFilePrint)
#0142 ON_MAND(ID_FILE_PRINT_PREVIEW; CView::OnFilePrintPreview)
#0143 END_MESSAGE_MAP()
#0144
#0145 void CScribbleView::OnDraw(CDC* pDC)
#0146 {
#0147 CScribbleDoc* pDoc = GetDocument();
#0148 // TODO: add draw code for native data here
#0149 }
图7…6 Scribble step0 执行时序。这是一张简图,有一些次要动作 ( 例如鼠
标拉曳功能、设定对话框底色) 并未列出, 但是在稍后的细部讨论中
会提到。
428
…………………………………………………………Page 491……………………………………………………………
第7章 簡單而完整:MFC 骨幹程式
以下是图7…6 程序流程之说明:
~ 动作与流程和前一章的Hello 程序如出一辙。
我们改写InitInstance 这个虚拟函数。
new 一个CMultiDocTemplate 对象,此对象规划Document 、View 以及Document
Frame 窗口三者之关系。
new 一个CMyMDIFrameWnd 对象,做为主窗口对象。
调用LoadFrame,产生主窗口并加挂菜单等诸元,并指定窗口标题、文件标题、文
件档扩展名等(关键在IDR_MAINFRAME 常数)。LoadFrame 内部将调用Create,后
者将调用CreateWindowEx,于是触发WM_CREATE 消息。
由于我们曾于CMainFrame 之中拦截WM_CREATE (利用ON_WM_CREATE 宏),
所以WM_CREATE 产生之际Framework 会调用OnCreate。我们在此为主窗口挂上工具
列和状态列。
回到InitInstance ,执行ShowWindow 显示窗口。
InitInstance 结束,回到AfxWinMain ,执行Run ,进入消息循环。其间的黑盒子已
在上一章的Hello 范例中挖掘过。
消息经由Message Routing 机制,在各类别的Message Map 中寻求其处理例程。
WM_MAND/ID_FILE_OPEN 消息将由CWinApp::OnFileOpen 函数处理。此函数由
MFC 提供,它在显示过【File Open 】对话框后调用Serialize 函数。
我们改写Serialize 函数以进行我们自己的文件读写动作。
WM_MAND/ID_APP_ABOUT 消息将由OnAppAbout 函数处理。
OnAppAbout 函数利用CDialog 的性质很方便地产生一个对话框。
429
…………………………………………………………Page 492……………………………………………………………
第篇 湷觥 FC 程式設計
Document Template 的意义
Document Template 是一个全新的观念。
稍早我已提过Document/View 的概念,它们互为表里。View 本身虽然已经是一个窗口,
其外围却必须再包装一个外框窗口做为舞台。这样的切割其实是为了让View 可以非常独
立地放置于「MDI Document Frame 窗口」或「SDI Document Frame 窗口」或「OLE Document
Frame 窗口」等各种应用之中。也可以说,Document Frame 窗口是View 窗口的一个容
器。资料的内容、资料的表象、以及「容纳资料表象之外框窗口」三者是一体的,换言
之,程序每打开一份文件(资料),就应该产生三份对象:
1。 一份Document 对象,
2。 一份View 对象,
3。 一份CMDIChildWnd 对象(做为外框窗口)
这三份对象由一个所谓的Document Template 对象来管理。让这三份对象产生关系的关
键在于CMultiDocTemplate:
BOOL CScribbleApp::InitInstance()
{
。。。
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_SCRIBTYPE;
RUNTIME_CLASS(CScribbleDoc);
RUNTIME_CLASS(CChildFrame);
RUNTIME_CLASS(CScribbleView));
AddDocTemplate(pDocTemplate);
。。。
}
如果程序支持不同的资料格式(例如一为TEXT 一为BITMAP ),那么就需要不同的
Document Template :
430
…………………………………………………………Page 493……………………………………………………………
第7章 簡單而完整:MFC 骨幹程式
BOOL CMyWinApp::InitInstance()
{
。。。
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_TEXTTYPE;
RUNTIME_CLASS(CTextDoc);
RUNTIME_CLASS(CChildFrame);
RUNTIME_CLASS(CTextView));
AddDocTemplate(pDocTemplate);
pDocTemplate = new CMultiDocTemplate(
IDR_BMPTYPE;
RUNTIME_CLASS(CBmpDoc);
RUNTIME_CLASS(CChildFrame);
RUNTIME_CLASS(CBmpView));
AddDocTemplate(pDocTemplate);
。。。
}
这其中有许多值得讨论的地方,而CMultiDocTemplate 的构造式参数透露了一些端倪:
CMultiDocTemplate::CMultiDocTemplate(UINT nIDResource;
CRuntimeClass* pDocClass;
CRuntimeClass* pFrameClass;
CRuntimeClass* pViewClass);
1。 nIDResource :这是一个资源ID ,表示此一文件类型(文件格式)所使用的资源。
本例为IDR_SCRIBTYPE,在RC 档中代表多种资源(不同种类的资源可使用
相同的ID ):
IDR_SCRIBTYPE ICON DISCARDABLE 〃resScribbleDoc。ico〃
IDR_SCRIBTYPE MENU PRELOAD DISCARDABLE
{ 。。。 }
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
IDR_MAINFRAME 〃Scribble Step0〃
IDR_SCRIBTYPE 〃nScribnScribnScribble Files (*。scb)n。SCBn
Scribble。DocumentnScrib Document〃
END
原码太长;我把它截为两半;实际上是一整行。有七个子字符串各以'n'
分隔。这些子字符串完整描述文件的类型。第一个子字符串于MDI 程序
中用不着,故本例省略(成为空字符串)。
431
…………………………………………………………Page 494……………………………………………………………
第篇 湷觥 FC 程式設計
其中的ICON 是文件窗口被最小化之后的图标;MENU 是当程序存在有任何文件
窗口时所使用的菜单(如果没有开启任何文件窗口,菜单将是另外一套,稍后再述)。
至于字符串表格(STRINGTABLE )中的字符串,稍后我有更进一步的说明。
2。 pDocClass 。这是一个指针,指向Document 类别( 衍生自CDocument)之
「CRuntimeClass 对象」。
3。 pFrameClass 。这是一个指针,指向Child Frame 类别(衍生自CMDIChildWnd)
之「CRuntimeClass 对象」。
4。 pViewClass 。这是一个指针,指向View 类别(衍生自CView)之「CRuntimeClass
对象」。
CRuntimeClass
我曾经在第3章「自制RTTI 」一节解释过什么是CRuntimeClass。它就是「类别型
录网」串行中的元素类型。任何一个类别只要在声明时使用DECLARE_DYNAMIC 或
DECLARE_DYNCREATE 或DECLARE_SERIAL 宏,就会拥有一个静态的(static )
CRuntimeClass 内嵌对象。
好,你看,Document Template 接受了三种类别的CRuntimeClass 指针,于是每当使用者
打开一份文件,Document Template 就能够根据「类别型录网」(第3章所述),动态生
成出三个对象(document 、view 、document frame window )。如果你不记得MFC 的动态
生成是怎么一回事儿,现在正是