⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap8_3.htm

📁 VC++编程实例。非常详细
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html>

<head>
<title>8.3 绘图程序</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<link rel="stylesheet" href="../../../cpcw.css"></head>

<body link="#3973DE" alink="#3973DE" background="../../bg.gif">
<div align="center"><center>
    <table width="85%" border="0">
      <tr bgcolor="#FFFFFF"> 
        <td> 
          <div align="center"> </div>
          <p align="CENTER"><b><font color="red">8.3 绘图程序</font></b></p>
          <p> 在了解GDI的一些基本知识之后,我们就可以着手编写绘图程序了。这个绘图程序可以让读者用鼠标器在窗口内任意涂写,并可以保存所画的内容。这里我们参考了Visual 
            C++的例子Scribble,并作了一些修改和简化。</p>
          <p> 8.3.1 MDI应用程序框架</p>
          <p> 首先用AppWizard生成绘图程序的基本框架:</p>
          <p> 选择File-&gt;New,弹出New对话框,选择MFC 
            AppWizard(exe),并指定项目文件名为Draw。</p>
          <p> 在MFC 
            AppWizard-Step1对话框中指定框架类型为Multiple 
            Document(多文档,这是缺省设置)。</p>
          <p> Step2,3按缺省值。在MFC AppWizard Step 4 of 6对话框中,点“Advanced...”按钮,弹出Advanced 
            Options对话框。在File Extension编辑框中指定文件名后缀为.drw,按OK关闭Advanced 
            Options对话框。</p>
          <p> Step5按缺省设置。在MFC 
            AppWizard Step 6 of 6中,在应用程序所包含的类列表中选择CDrawView,并为其指定基类为CScrollView,因为绘图程序需要卷滚文档。现在点Finish按钮生成绘图所需的应用程序框架。</p>
          <p> 在往框架里添加代码实现绘图程序之前,先看看多文档框架与单文档框架的差别。</p>
          <p> AppWizard为多文档框架创建了以下类: 
            </p>
          <p> CAboutDlg:“关于”对话框</p>
          <p> CChildFrame:子框架窗口,用于容纳视图</p>
          <p> CDrawApp:应用程序类</p>
          <p> CDrawDoc:绘图程序视图类</p>
          <p> CDrawView:绘图视图类</p>
          <p> CMainFrame:主框架窗口,用来容纳子窗口,它是多文档应用程序的主窗口。</p>
          <p> 在生成的类上,MDI比SDI多了一个CChildFrame子框架窗口类,而且CMainFrame的职责也不同了。</p>
          <p> 另外,MDI和SDI在初始化应用程序实例上也有所不同。MDI应用程序InitInstance函数如清单8.2定义。</p>
          
          <p> <b>清单</b><b>8.2 
            多文档程序的InitInstance成员函数定义</b></p>
           
          <p>BOOL CDrawApp::InitInstance()</p>
          <p>{</p>
          
          <p>//一些初始化工作......</p>
           
          <p>// Register the application's document templates. Document templates</p>
          <p>// serve as the connection between documents, frame windows and views.</p>
          <p>CMultiDocTemplate* pDocTemplate;</p>
          <p>pDocTemplate = new CMultiDocTemplate(</p>
          <p>IDR_DRAWTYPE,</p>
          <p>RUNTIME_CLASS(CDrawDoc),</p>
          <p>RUNTIME_CLASS(CChildFrame), // custom MDI child frame</p>
          <p>RUNTIME_CLASS(CDrawView));</p>
          <p>AddDocTemplate(pDocTemplate);</p>
          <p>// create main MDI Frame window</p>
          <p>CMainFrame* pMainFrame = new CMainFrame;</p>
          <p>if (!pMainFrame-&gt;LoadFrame(IDR_MAINFRAME))</p>
          <p>return FALSE;</p>
          <p>m_pMainWnd = pMainFrame;</p>
          <p>// Enable drag/drop open</p>
          <p>m_pMainWnd-&gt;DragAcceptFiles();</p>
          <p>// Enable DDE Execute open</p>
          <p>EnableShellOpen();</p>
          <p>RegisterShellFileTypes(TRUE);</p>
          <p>// Parse command line for standard shell commands, DDE, file open</p>
          <p>CCommandLineInfo cmdInfo;</p>
          <p>ParseCommandLine(cmdInfo);</p>
          <p>// Dispatch commands specified on the command line</p>
          <p>if (!ProcessShellCommand(cmdInfo))</p>
          <p>return FALSE;</p>
          <p>// The main window has been initialized, so show and update it.</p>
          <p>pMainFrame-&gt;ShowWindow(m_nCmdShow);</p>
          <p>pMainFrame-&gt;UpdateWindow();</p>
          <p>return TRUE;</p>
          <p>}</p>
          
          <p>在注册文档模板时,首先创建一个CMultiDocTemplate类型(在SDI下是CSingleDocTemplate)的模板对象,然后用AddDocTemplate()把它加入到文档模板链表中去。</p>
          <p> CMultiDocTemplate构造函数带四个参数,第一个参数是文档使用的资源ID定义。第二个是文档类型,第三个是子窗口类型,第四个是视图类型。</p>
          <p> 与SDI不同,由于MDI的主框架窗口并不直接与文档相对应,因此无法通过创建文档来创建主框架窗口,而需要自己去创建。</p>
          <p> //定义一个主窗口类指针,并创建一个窗口的空的实例</p>
           
          <p>CMainFrame* pMainFrame = new CMainFrame;</p>
          
          <p>//从资源文件中载入菜单、图标等信息,并创建窗口</p>
           
          <p>if (!pMainFrame-&gt;LoadFrame(IDR_MAINFRAME))</p>
          <p>return FALSE;</p>
          
          <p>//将应用程序对象的主窗口指针数据成员设为当前创建的窗口</p>
           
          <p>m_pMainWnd = pMainFrame;</p>
          
          <p><b> </b></p>
          <p><b> </b>8.3.2 设计绘图程序的文档类</p>
          <p> Draw需要保存用户在屏幕上涂写的每一个笔划。一副画由许多笔划组成,可以把它看作是笔划组成的链表。每一个笔划可以看作一个对象,它由许多点组成。这样,我们可以把绘图文档的数据看作是笔划对象CStroke组成的链表。另外,我们还需要一些数据成员表示当前画图所使用的画笔和画笔的宽度。</p>
          <p> 修改后的文档类声明文件如清单8-1:</p>
          
          <p> <b>清单</b><b>8.3文档类声明</b></p>
           
          <p>// DrawDoc.h : interface of the CDrawDoc class</p>
          <p>//</p>
          <p>/////////////////////////////////////////////////////////////////////////////</p>
          <p>#if !defined(AFX_DRAWDOC_H__143330AE_85BC_11D1_9304_444553540000__INCLUDED_)</p>
          <p>#define AFX_DRAWDOC_H__143330AE_85BC_11D1_9304_444553540000__INCLUDED_</p>
          <p>#if _MSC_VER &gt;= 1000</p>
          <p>#pragma once</p>
          <p>#endif // _MSC_VER &gt;= 1000</p>
          
          <p> </p>
           
          <p>class CDrawDoc : public CDocument</p>
          <p>{</p>
          <p>protected: // create from serialization only</p>
          <p>CDrawDoc();</p>
          <p>DECLARE_DYNCREATE(CDrawDoc)</p>
          <p>// Attributes</p>
          
          <p><b> </b></p>
          <b> 
          <p>public:</p>
          <p>UINT m_nPenWidth; // current user-selected pen width</p>
          <p>CPen m_penCur; // pen created according to</p>
          <p>// user-selected pen style (width)</p>
          <p>public:</p>
          <p>CTypedPtrList&lt;CObList,CStroke*&gt; m_strokeList; </p>
          
          <p>//获取当前使用的画笔,为视图所使用</p>
           
          <p>CPen* GetCurrentPen() { return &amp;m_penCur; }</p>
          <p>protected:</p>
          <p>CSize m_sizeDoc;</p>
          <p>public:</p>
          <p>CSize GetDocSize() { return m_sizeDoc; }</p>
          <p>// Operations</p>
          <p>public:</p>
          
          <p>//往链表里增加一个笔划</p>
           
          <p>CStroke* NewStroke();</p>
          <p>// Operations</p>
          
          <p>//用于初始化文档</p>
           
          <p>protected:</p>
          <p>void InitDocument();</p>
          </b> 
          <p>// Overrides</p>
          <p>// ClassWizard generated virtual function overrides</p>
          <p>//{{AFX_VIRTUAL(CDrawDoc)</p>
          <p>public:</p>
          <p>virtual BOOL OnNewDocument();</p>
          <p>virtual void Serialize(CArchive&amp; ar);</p>
          <p>//}}AFX_VIRTUAL</p>
          <p>// Implementation</p>
          <p>public:</p>
          <p>virtual ~CDrawDoc();</p>
          <p>#ifdef _DEBUG</p>
          <p>virtual void AssertValid() const;</p>
          <p>virtual void Dump(CDumpContext&amp; dc) const;</p>
          <p>#endif</p>
          <p>protected:</p>
          <p>// Generated message map functions</p>
          <p>protected:</p>
          <p>//{{AFX_MSG(CDrawDoc)</p>
          <p>// NOTE - the ClassWizard will add and remove member functions here.</p>
          <p>// DO NOT EDIT what you see in these blocks of generated code !</p>
          <p>//}}AFX_MSG</p>
          <p>DECLARE_MESSAGE_MAP()</p>
          <p>};</p>
          
          <p> </p>
          <p> 这里我们使用 
            指针链表模板来保存指向每个笔划的指针:</p>
           
          <p>CTypedPtrList&lt;CObList,CStroke*&gt; m_strokeList; </p>
          
          <p>其中“&lt;&gt;”第一个参数表示链表基本类型,第二个参数代表链表中所存放的元素的类型。</p>
          <p> 为了使用模板,还要修改stdafx.h,在其中加入afxtempl..h头文件,它包含了使用模板时所需的类型定义和宏:</p>
           
          <p>//.........</p>
          <p>#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers</p>
          <p>#include &lt;afxwin.h&gt; // MFC core and standard components</p>
          <p>#include &lt;afxext.h&gt; // MFC extensions</p>
          
          <p><b> </b></p>
          <b> 
          <p>#include &lt;afxtempl.h&gt; // MFC templates</p>
          </b> 
          <p>#include &lt;afxdisp.h&gt; // MFC OLE automation classes</p>
          <p>#ifndef _AFX_NO_AFXCMN_SUPPORT</p>
          <p>#include &lt;afxcmn.h&gt; // MFC support for Windows Common Controls</p>
          <p>#endif // _AFX_NO_AFXCMN_SUPPORT</p>
          <p>//......</p>
          
          <p>由于绘图程序需要卷滚文档,因此象前面的编辑那样,增加一个m_sizeDoc数据成员存放文档的大小。另外,还需要提供一个GetDocSize()来访问它。NewStroke()用于往链表里增加一个笔划。</p>
          <p> 现在,开始设计CStroke类。笔划可以看作由一系列点组成,这样CStroke可以用一个点的数组来表示。另外,还需要一些成员函数来访问这个数组。我们还希望笔划能够自己绘制自己,并用串行化机制保存自己的数据。</p>
          <p> CStroke类定义清单如8.4,我们把它在CDrawDoc类定义之前。</p>
          
          <p> <b>清单</b><b>8.4 
            CStroke类定义</b></p>
           
          <p>class CStroke : public CObject</p>
          <p>{</p>
          <p>public:</p>
          
          <p>CStroke(UINT nPenWidth);//用笔的宽度构造一个画笔</p>
          <p> //用于串行化笔划对象</p>
           
          <p>protected:</p>
          
          <p>CStroke(); //串行化对象所需的不带参数的构造函数</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>//用数组模板类保存笔划的所有点</p>
           
          <p>CArray&lt;CPoint,CPoint&gt; m_pointArray; // series of connected 
            points</p>
          
          <p>//包围笔划所有的点的一个最小矩形,关于它的作用以后会提到</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&amp; GetBoundingRect() { return m_rectBounding; }</p>
          
          <p>//结束笔划,计算最小矩形</p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -