友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
深入浅出MFC第2版(PDF格式)-第58部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
#0007 // 第9章「消息映射与命令绕行」可以解决这个疑惑。
#0008 class CMainFrame : public CMDIFrameWnd
#0009 {
#0010 DECLARE_DYNAMIC(CMainFrame)
#0011 CStatusBar m_wndStatusBar;
#0012 CToolBar m_wndToolBar;
#0013 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
#0014 DECLARE_MESSAGE_MAP()
#0015 };
#0016
#0017 class CChildFrame : public CMDIChildWnd
#0018 {
425
…………………………………………………………Page 488……………………………………………………………
第篇 湷觥 FC 程式設計
#0019 DECLARE_DYNCREATE(CChildFrame)
#0020 DECLARE_MESSAGE_MAP()
#0021 };
#0022
#0023 class CScribbleDoc : public CDocument
#0024 {
#0025 DECLARE_DYNCREATE(CScribbleDoc)
#0026 virtual void Serialize(CArchive& ar);
#0027 DECLARE_MESSAGE_MAP()
#0028 };
#0029
#0030 class CScribbleView : public CView
#0031 {
#0032 DECLARE_DYNCREATE(CScribbleView)
#0033 CScribbleDoc* GetDocument();
#0034
#0035 virtual void OnDraw(CDC* pDC);
#0036 DECLARE_MESSAGE_MAP() // MFC 內部
#0037 };
Int AfxAPI AfxWinMain(!K)
#0038
{
#0039 class CAboutDlg : public CDialog
CWinApp* pApp = AfxGetApp();
#0040 {
AfxWinInit(!K);
#0041 DECLARE_MESSAGE_MAP()
pApp…》InitApplication();
#0042 };
#0043 pApp…》InitInstance();
nReturnCode = pApp…》Run();
#0044 //………………………………………………………………………………………………………………………………………………………………………………
#0045
}
#0046 CScribbleApp theApp;
#0047
#0048 BEGIN_MESSAGE_MAP(CScribbleApp; CWinApp)
#0049 ON_MAND(ID_APP_ABOUT; OnAppAbout)
#0050 ON_MAND(ID_FILE_NEW; CWinApp::OnFileNew)
#0051 ON_MAND(ID_FILE_OPEN; CWinApp::OnFileOpen)
#0052 ON_MAND(ID_FILE_PRINT_SETUP; CWinApp::OnFilePrintSetup)
#0053 END_MESSAGE_MAP()
#0054
#0055 BOOL CScribbleApp::InitInstance()
#0056 {
#0057 。。。
#0058 CMultiDocTemplate* pDocTemplate;
#0059 pDocTemplate = new CMultiDocTemplate(
#0060 IDR_SCRIBTYPE;
#0061 RUNTIME_CLASS(CScribbleDoc);
#0062 RUNTIME_CLASS(CChildFrame);
#0063 RUNTIME_CLASS(CScribbleView));
#0064 AddDocTemplate(pDocTemplate);
426
…………………………………………………………Page 489……………………………………………………………
第7章 簡單而完整:MFC 骨幹程式
#0065
#0066 CMainFrame* pMainFrame = new CMainFrame;
#0067 pMainFrame…》LoadFrame(IDR_MAINFRAME);
#0068 m_pMainWnd = pMainFrame;
#0069 ! K // MFC 內部
#0070 pMainFrame…》ShowWindow(m_nCmdShow); CFrameWnd::Create
#0071 pMainFrame…》UpdateWindow();
#0072 return TRUE;
#0073 } CWnd::CreateEx
#0074
#0075 BEGIN_MESSAGE_MAP(CAboutDlg; CDialog)
::CreateWindowEx
#0076 END_MESSAGE_MAP()
#0077
#0078 void CScribbleApp::OnAppAbout()
#0079 {
#0080 CAboutDlg aboutDlg;
#0081 aboutDlg。DoModal();
#0082 }
#0083
#0084 IMPLEMENT_DYNAMIC(CMainFrame; CMDIFrameWnd)
WM_CREATE
#0085
#0086 BEGIN_MESSAGE_MAP(CMainFrame; CMDIFrameWnd) wm_cre
#0087 ON_WM_CREATE()
#0088 END_MESSAGE_MAP()
#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 的动态
生成是怎么一回事儿,现在正是复习第3章的时候。我将在第8章带你实际看看
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!