设为首页 加入收藏

TOP

14.4.3 使用鼠标绘图(3)
2013-10-07 16:12:28 来源: 作者: 【 】 浏览:78
Tags:14.4.3 使用 鼠标 绘图

14.4.3  使用鼠标绘图(3)

使用完全相同的过程可以添加其他元素类。因为其他元素类把CElement而不是MFC类作为基类,所以应当把类类别选作C++(www.cppentry.com),把模板选作C++(www.cppentry.com) class。选择Virtual destructor选项。对于CLine类,Class Wizard窗口应当如图14-14所示。
 

默认情况下,Class Wizard为头文件和.cpp文件提供的名称分别是Line.h和Line.cpp,不过可以修改这些名称,对这些文件使用不同的名称,或者把代码添加到已有的文件中。在基类定义中给CElement.h添加一个#include指令。在创建了CLine类定义以后,对CRectangle、CCircle和CCurve进行相同的操作。当完成这些工作以后,在.h文件中应当看到CElement类的所有4个子类的定义,针对每个子类都声明了一个构造函数和一个虚析构函数。

在视图中存储临时元素

在前面讨论如何绘制形状时已经介绍过,按下鼠标左键以后,拖动鼠标将创建和绘制一系列临时元素对象。所有元素的基类都是CElement,就可以添加std::shared_ptr<CElement>类型的智能指针,来指向这个视图类,用以存储临时元素的地址。可以把unique_ptr看作它的替代项,但我们最终需要在鼠标事件处理函数中访问指向元素的指针,而这个指针存储在文档对象的一个容器中,而unique_ptr不允许这么做。

首先,在#pragma once指令的后面给memory头文件和Element.h添加#include指令。再右击CSketcherView类,选择Add | Add Variable选项。m_pTempElement变量的类型应当是std::shared_ ptr<CElement>,和以前添加的两个数据成员一样,它应当是protected。可以在WM_MOUSEMOVE消息处理程序中使用m_pTempElement指针,测试以前的临时元素是否存在,因为在没有临时元素时,将这个指针安排为空。

3. CElement类

现在可以逐步填写这个元素类的定义,为Sketcher应用程序添加越来越多的功能-- 不过现在需要做什么呢?有些数据项(如颜色和位置)显然对于所有类型的元素都是通用的,所以可以把它们放在CElement基类中,以便在每个派生类中继承它们。但是,在定义特定元素属性的类中,有些数据成员却极其不同,所以需要在它们所属的特定派生类中声明这些成员。

CElement类包含要在派生类中实现的虚函数,以及在所有派生类中都相同的数据和函数成员。虚函数是通过CElement*指针自动为特定对象选择的函数。这时可以使用Add Member Wizard在CElement类中添加这些成员,但需要手动修改。目前,可以把CElement类定义修改为:
 

  1. class CElement: public CObject  
  2. {  
  3. protected:  
  4. CPoint m_StartPoint;                                                    // Element position  
  5. int m_PenWidth;                                                                 // Pen width  
  6. COLORREF m_Color;                                                           // Color of an element  
  7. CRect m_EnclosingRect;                                          // Rectangle enclosing an element  
  8. public:  
  9. virtual ~CElement();  
  10. virtual void Draw(CDC* pDC) {} // Virtual draw operation  
  11. // Get the element enclosing rectangle  
  12. const CRect& GetEnclosingRect() const { return m_EnclosingRect; }  
  13. protected:  
  14. // Constructors protected so they cannot be called outside the class  
  15. CElement();  
  16. CElement(const CPoint& start, COLORREF color, int penWidth = 1);  
  17. };  

这段代码把构造函数CElement的访问方式从public修改为protected,以防止从CElement类的外部调用这个函数,新构造函数只能在派生类中调用,它有3个参数,笔宽使用默认值,因为笔宽大多为1。现在,派生类继承的成员是存储元素的位置、颜色和笔宽的数据成员,以及界定元素占用区域的边界矩形。

在类中还有两个成员函数定义:

GetEnclosingRect()返回m_EnclosingRect,需要使元素占用的区域失效时,就使用这个函数。

虚函数Draw()在派生类中实现,用于绘制元素。Draw()函数要求将一个指向CDC对象的指针传递给它,以访问需要在设备环境中绘图的函数。

您可能想把Draw()成员声明为CElement类中的纯虚函数,让派生类定义它-- 毕竟,它在这个类中没有任何有意义的内容。虽然通常可以这么做,但是CElement类将从CObject继承一个称为序列化的工具,以后在文件中存储元素对象时将使用它。序列化要求,CElement不是抽象类,以便创建这种类型的实例。如果想使用MFC的序列化能力,那么类一定不能是抽象的,还必须有无参数的构造函数。

可以在Element.cpp中添加新构造函数的定义:

  1. CElement::CElement(const CPoint& start, COLORREF color, int penWidth) :  
  2. m_StartPoint(start), m_PenWidth(penWidth), m_Color(color) {}  

所有成员都在初始化列表中定义了,所以构造函数体中不需要任何代码。
 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇14.4.3 使用鼠标绘图(2) 下一篇14.4.3 使用鼠标绘图(4)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·数据库:推荐几款 Re (2025-12-25 12:17:11)
·如何最简单、通俗地 (2025-12-25 12:17:09)
·什么是Redis?为什么 (2025-12-25 12:17:06)
·对于一个想入坑Linux (2025-12-25 11:49:07)
·Linux 怎么读? (2025-12-25 11:49:04)