📄 chap8_3.htm
字号:
<p>//}}AFX_MSG</p>
<p>DECLARE_MESSAGE_MAP()</p>
<p>};</p>
<p></font><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">这里我们使用
指针链表模板来保存指向每个笔划的指针:</font><font FACE="Times New Roman" SIZE="3"></p>
<p>CTypedPtrList<CObList,CStroke*> m_strokeList; </p>
<p></font><font SIZE="3">其中“</font><font FACE="Times New Roman" SIZE="3"><></font><font SIZE="3">”第一个参数表示链表基本类型,第二个参数代表链表中所存放的元素的类型。</p>
<p>为了使用模板,还要修改</font><font FACE="Times New Roman" SIZE="3">stdafx.h</font><font SIZE="3">,在其中加入</font><font FACE="Times New Roman" SIZE="3">afxtempl..h</font><font SIZE="3">头文件,它包含了使用模板时所需的类型定义和宏:</font><font FACE="Times New Roman" SIZE="3"></p>
<p>//.........</p>
<p>#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers</p>
<p>#include <afxwin.h> // MFC core and standard components</p>
<p>#include <afxext.h> // MFC extensions</p>
<p></font><b><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>#include <afxtempl.h> // MFC templates</b></p>
<p>#include <afxdisp.h> // MFC OLE automation classes</p>
<p>#ifndef _AFX_NO_AFXCMN_SUPPORT</p>
<p>#include <afxcmn.h> // MFC support for Windows Common Controls</p>
<p>#endif // _AFX_NO_AFXCMN_SUPPORT</p>
<p>//......</p>
<p></font><font SIZE="3">由于绘图程序需要卷滚文档,因此象前面的编辑那样,增加一个</font><font FACE="Times New Roman" SIZE="3">m_sizeDoc</font><font SIZE="3">数据成员存放文档的大小。另外,还需要提供一个</font><font FACE="Times New Roman" SIZE="3">GetDocSize()</font><font SIZE="3">来访问它。</font><font FACE="Times New Roman" SIZE="3">NewStroke()</font><font SIZE="3">用于往链表里增加一个笔划。</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">现在,开始设计</font><font FACE="Times New Roman" SIZE="3">CStroke</font><font SIZE="3">类。笔划可以看作由一系列点组成,这样</font><font FACE="Times New Roman" SIZE="3">CStroke</font><font SIZE="3">可以用一个点的数组来表示。另外,还需要一些成员函数来访问这个数组。我们还希望笔划能够自己绘制自己,并用串行化机制保存自己的数据。</font><font FACE="Times New Roman" SIZE="3"></p>
<p>CStroke</font><font SIZE="3">类定义清单如</font><font FACE="Times New Roman" SIZE="3">8.4</font><font SIZE="3">,我们把它在</font><font FACE="Times New Roman" SIZE="3">CDrawDoc</font><font SIZE="3">类定义之前。<b></p>
<p>清单</font><font FACE="Times New Roman" SIZE="3">8.4 CStroke</font><font SIZE="3">类定义</font></b><font FACE="Times New Roman" SIZE="3"></p>
<p>class CStroke : public CObject</p>
<p>{</p>
<p>public:</p>
<p>CStroke(UINT nPenWidth);//</font><font SIZE="3">用笔的宽度构造一个画笔</font><font FACE="Times New Roman" SIZE="3"></p>
<p>//</font><font SIZE="3">用于串行化笔划对象</font><font FACE="Times New Roman" SIZE="3"></p>
<p>protected:</p>
<p>CStroke(); //</font><font SIZE="3">串行化对象所需的不带参数的构造函数</font><font FACE="Times New Roman" SIZE="3"></p>
<p>DECLARE_SERIAL(CStroke)</p>
<p>// Attributes</p>
<p>protected:</p>
<p>UINT m_nPenWidth; // one pen width applies to entire stroke</p>
<p>public:</p>
<p>//</font><font SIZE="3">用数组模板类保存笔划的所有点</font><font FACE="Times New Roman" SIZE="3"></p>
<p>CArray<CPoint,CPoint> m_pointArray; // series of connected points</p>
<p>//</font><font SIZE="3">包围笔划所有的点的一个最小矩形,关于它的作用以后会提到</font><font FACE="Times New Roman" SIZE="3"></p>
<p>CRect m_rectBounding; // smallest rect that surrounds all</p>
<p>// of the points in the stroke</p>
<p>// measured in MM_LOENGLISH units</p>
<p>// (0.01 inches, with Y-axis inverted)</p>
<p>public:</p>
<p>CRect& GetBoundingRect() { return m_rectBounding; }</p>
<p>//</font><font SIZE="3">结束笔划,计算最小矩形</font><font FACE="Times New Roman" SIZE="3"></p>
<p>void FinishStroke();</p>
<p>// Operations</p>
<p>public:</p>
<p>//</font><font SIZE="3">绘制笔划</font><font FACE="Times New Roman" SIZE="3"></p>
<p>BOOL DrawStroke(CDC* pDC);</p>
<p>public:</p>
<p>virtual void Serialize(CArchive& ar);</p>
<p>};</font><font SIZE="3"><b></p>
<p></b><font color="#3973DE">文档的初始化</font></font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">文档的初始化在</font><font FACE="Times New Roman" SIZE="3">OnNewDocument()</font><font SIZE="3">和</font><font FACE="Times New Roman" SIZE="3">OnOpenDocument()</font><font SIZE="3">中完成。对于</font><font FACE="Times New Roman" SIZE="3">Draw</font><font SIZE="3">程序来说,两者的初始化相同,因此设计一个</font><font FACE="Times New Roman" SIZE="3">InitDocument()</font><font SIZE="3">函数用于文档初始化:</font><b><font FACE="Times New Roman" SIZE="3"></p>
<p>void CDrawDoc::InitDocument()</p>
<p>{</p>
<p>m_nPenWidth=2;</p>
<p>m_nPenCur.CreatePen(PS_SOLID,m_nPenWidth,RGB(0,0,0));</p>
<p>//</font><font SIZE="3">缺省文档大小设置为</font><font FACE="Times New Roman" SIZE="3">800X900</font><font SIZE="3">个逻辑单位</font><font FACE="Times New Roman" SIZE="3"></p>
<p>m_sizeDoc = CSize(800,900);</p>
<p>}</b></p>
<p>InitDocument()</font><font SIZE="3">函数将笔的宽度初值设为</font><font FACE="Times New Roman" SIZE="3">2</font><font SIZE="3">,然后创建一个画笔对象。该对象在以后绘图是要用到。最后将文档尺寸大小设置为</font><font FACE="Times New Roman" SIZE="3">800X900</font><font SIZE="3">个逻辑单位。</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">然后在</font><font FACE="Times New Roman" SIZE="3">OnNewDocument()</font><font SIZE="3">和</font><font FACE="Times New Roman" SIZE="3">OnOpenDocument()</font><font SIZE="3">中调用它:</font><font FACE="Times New Roman" SIZE="3"></p>
<p>void CDrawDoc::OnNewDocument()</p>
<p>{</p>
<p>if (!CDocument::OnNewDocument())</p>
<p>return FALSE;</p>
<p>// TODO: add reinitialization code here</p>
<p>// (SDI documents will reuse this document)</p>
<p></font><b><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>InitDocument();</b></p>
<p>return TRUE;</p>
<p>}</p>
<p>AppWizard</font><font SIZE="3">并没有生成</font><font FACE="Times New Roman" SIZE="3">OnOpenDocument()</font><font SIZE="3">的代码,因此要用</font><font FACE="Times New Roman" SIZE="3">ClassWizard</font><font SIZE="3">来生成</font><font FACE="Times New Roman" SIZE="3">OnOpenDocument()</font><font SIZE="3">的框架。生成框架后,在其中加入代码:</font><font FACE="Times New Roman" SIZE="3"></p>
<p>BOOL CDrawDoc::OnOpenDocument(LPCTSTR lpszPathName) </p>
<p>{</p>
<p>if (!CDocument::OnOpenDocument(lpszPathName))</p>
<p>return FALSE;</p>
<p></font><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>// TODO: Add your specialized creation code here</p>
<p></font><b><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>InitDocument();</b></p>
<p>return TRUE;</p>
<p>}</font><font SIZE="3"><b></p>
<p></b><font color="#3973DE">文档的清理</font></font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">在关闭文档的最后一个子窗口时,框架要求文档清理数据。文档清理在文档类的</font><font FACE="Times New Roman" SIZE="3">DeleteContents()</font><font SIZE="3">中完成。同样需要用</font><font FACE="Times New Roman" SIZE="3">ClassWizard</font><font SIZE="3">生成</font><font FACE="Times New Roman" SIZE="3">DeleteContents</font><font SIZE="3">的框架。</font><font FACE="Times New Roman" SIZE="3"></p>
<p>void CDrawDoc::DeleteContents() </p>
<p>{</p>
<p>// TODO: Add your specialized code here and/or call the base class</p>
<p></font><b><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>while (!m_strokeList.IsEmpty())</p>
<p>{</p>
<p>delete m_strokeList.RemoveHead();</p>
<p>}</b></p>
<p>CDocument::DeleteContents();</p>
<p>}</p>
<p>DeleteContents()</font><font SIZE="3">从头到尾遍里链表中的所有对象指针,并通过指针删除对象,然后用</font><font FACE="Times New Roman" SIZE="3">RemoveHead()</font><font SIZE="3">删除该指针。<b></p>
<p></b><font color="#3973DE">文档的串行化</font></font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">现在设计文档的</font><font FACE="Times New Roman" SIZE="3">Serialize</font><font SIZE="3">函数,实现文档数据的保存和载入:</font><font FACE="Times New Roman" SIZE="3"></p>
<p>void CDrawDoc::Serialize(CArchive& ar)</p>
<p>{</p>
<p>if (ar.IsStoring())</p>
<p>{</p>
<p></font><b><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>ar << m_sizeDoc;</b></p>
<p>}</p>
<p>else</p>
<p>{</p>
<p></font><b><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>ar >> m_sizeDoc;</b></p>
<p>}</p>
<p></font><b><font SIZE="3"> </font><font FACE="Times New Roman" SIZE="3"></p>
<p>m_strokeList.Serialize(ar);</b></p>
<p>}</p>
<p></font><font SIZE="3">文档的</font><font FACE="Times New Roman" SIZE="3">Serialize()</font><font SIZE="3">函数首先分别保存和载入文档大小,然后调用</font><font FACE="Times New Roman" SIZE="3">m_strokeList</font><font SIZE="3">的</font><font FACE="Times New Roman" SIZE="3">Serialize()</font><font SIZE="3">方法。</font><font FACE="Times New Roman" SIZE="3">m_strokeList.Serialize()</font><font SIZE="3">又会自动调用存放在</font><font FACE="Times New Roman" SIZE="3">m_strokeList</font><font SIZE="3">中的每一个元素</font><font FACE="Times New Roman" SIZE="3">CStroke</font><font SIZE="3">的串行化方法</font><font FACE="Times New Roman" SIZE="3">CStroke.Serialize()</font><font SIZE="3">最终实现文档的串行化即文档所包含的对象的存储和载入。</font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">在</font><font FACE="Times New Roman" SIZE="3">DrawDoc.cpp</font><font SIZE="3">的末尾加上</font><font FACE="Times New Roman" SIZE="3">CStroke::Serialize()</font><font SIZE="3">函数的定义:</font><font FACE="Times New Roman" SIZE="3"><b></p>
<p>void CStroke::Serialize(CArchive& ar)</p>
<p>{</p>
<p>if (ar.IsStoring())</p>
<p>{</p>
<p>ar << m_rectBounding;</p>
<p>ar << (WORD)m_nPenWidth;</p>
<p>m_pointArray.Serialize(ar);</p>
<p>}</p>
<p>else</p>
<p>{</p>
<p>ar >> m_rectBounding;</p>
<p>WORD w;</p>
<p>ar >> w;</p>
<p>m_nPenWidth = w;</p>
<p>m_pointArray.Serialize(ar);</p>
<p>}</p>
<p>}</b></p>
<p>CStroke</font><font SIZE="3">的</font><font FACE="Times New Roman" SIZE="3">Serialize()</font><font SIZE="3">依次保存(载入)笔划的矩形边界、线宽度以及点数组。注意</font><font FACE="Times New Roman" SIZE="3">m_nPenWidth</font><font SIZE="3">是</font><font FACE="Times New Roman" SIZE="3">UINT</font><font SIZE="3">类型的,</font><font FACE="Times New Roman" SIZE="3">>></font><font SIZE="3">和</font><font FACE="Times New Roman" SIZE="3"><<</font><font SIZE="3">操作符并不支持</font><font FACE="Times New Roman" SIZE="3">UINT</font><font SIZE="3">类型但却支持</font><font FACE="Times New Roman" SIZE="3">WORD</font><font SIZE="3">,因此要作</font><font FACE="Times New Roman" SIZE="3">UINT</font><font SIZE="3">和</font><font FACE="Times New Roman" SIZE="3">DWORD</font><font SIZE="3">之间的类型转换。点数组的串行化通过调用数组的每个</font><font FACE="Times New Roman" SIZE="3">CPoint</font><font SIZE="3">类元素的</font><font FACE="Times New Roman" SIZE="3">Serialize()</font><font SIZE="3">完成,</font><font FACE="Times New Roman" SIZE="3">CPoint</font><font SIZE="3">类是</font><font FACE="Times New Roman" SIZE="3">MFC</font><font SIZE="3">类,它本身支持串行化。</font><font FACE="Times New Roman"><b></p>
<p></b></font><font color="#3973DE" FACE="Times New Roman">8.3.3 </font><font color="#3973DE">设计绘图程序的视图类</font></p>
<p><font SIZE="3"><b> </p>
<p></b><font color="#3973DE">视图类数据成员</font></font><font FACE="Times New Roman" SIZE="3"></p>
<p></font><font SIZE="3">现在着手设计绘图程序的视图类。首先,需要在视图中增加两个数据成员:</font><font FACE="Times New Roman" SIZE="3"></p>
<p>class CDrawView : public CScrollView</p>
<p>{</p>
<p>protected: // create from serialization only</p>
<p>CDrawView();</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -