📄 00000002.htm
字号:
另外我们再定义一般性的绘图物件都会用到的基本特性,如颜 <BR>色及线条宽度,再加上绘图时所需要的 Canvas,如此就组成 <BR>了CShape的类别定义: <BR> <BR>TCanvas* m_pCanvas; // 绘图所需的Canvas <BR>TColor m_Color; // 颜色 <BR>int m_nWidth; // 宽度 <BR> <BR>至於CShape的解构函式为何也设成virtual呢?这关系到继 <BR>承物件的毁灭方法。若是基础类别的解构函式没有定义成虚拟 <BR>函式时,会造成特定情况下,子类别的解构函式没有被呼叫到 <BR>的情形: <BR>如: <BR> <BR>CLine *pLine = new Line; <BR>CShape* pShape=pLIne; <BR>delete pShape; <BR> <BR>上述的例子因为CLine为CShape的子类别,因此可以直接将 <BR>pShape指标指向pLine,然而在後面delete <BR>pShape时,若是pShape的解构函式不为虚拟函式,会造成pLine <BR>的解构函式不被呼叫到。这是一般C++ 程式设计时很容易犯的 <BR>错误。 <BR> <BR>我们可以将以上的经验法则归纳成一个原则,即是:只要该类 <BR>别有可能被继承,就必须将其解构函式设为虚拟函式。如此就 <BR>有了以下的定义了: <BR> <BR>CShape(TCanvas* pCanvas) {m_pCanvas = pCanvas;} <BR>virtual ~CShape() {} <BR> <BR>CShape的建构函式必须传入Canvas以便绘图,而解构函式则 <BR>不做任何事,只将其定义为虚拟函式。 <BR> <BR>XX-03-02 CLine类别定义及实作-画直线的类别 <BR> <BR>class CLine : public CShape <BR>{ <BR>public: <BR>POINT m_ptMove; <BR>POINT m_ptOrigin; <BR>public: <BR>CLine(TCanvas* pCanvas):CShape(pCanvas) {} <BR>virtual ~CLine() {} <BR>virtual void OnMouseMove(int,int); <BR>virtual void OnMouseDown(int,int); <BR>virtual void OnMouseUp(int,int); <BR>}; <BR> <BR>我们将CLine定义为一个画直线的类别,而我们希望在画直线 <BR>时可以在拖弋滑鼠时将原先的线条擦去,并画出新的线,因此 <BR>我们必须宣告两个点来记载滑鼠按下的点及上次的点以便擦去 <BR>原来的线条。 <BR>以下就是CLine对於三个滑鼠事件的处理函式: <BR> <BR>// 滑鼠按下的事件处理函式 <BR>// 1. 设定原点及上个启始点为目前所在点。 <BR>// 2. 移动至目前所在点。 <BR>void CLine::OnMouseDown(int x,int y) <BR>{ <BR>m_ptOrigin.x = m_ptMove.x = x; <BR>m_ptOrigin.y = m_ptMove.y = y; <BR>m_pCanvas->MoveTo(x,y); <BR>} <BR> <BR>// 滑鼠移动事件处理函式 <BR>// 1.将画笔模式设为XOR模式,以便擦去上一条线。 <BR>// 2.擦去原来的线(以XOR模式再画一次就会擦去了) <BR>// 3.在目前的位置画出一条新线。 <BR>// 4.更新坐标并改变画笔模式。 <BR>void CLine::OnMouseMove(int x,int y) <BR>{ <BR>m_pCanvas->Pen->Mode = pmXor; <BR>m_pCanvas->MoveTo(m_ptOrigin.x,m_ptOrigin.y); <BR>m_pCanvas->LineTo(m_ptMove.x,m_ptMove.y); <BR>m_pCanvas->MoveTo(m_ptOrigin.x,m_ptOrigin.y); <BR>m_pCanvas->LineTo(x,y); <BR>m_ptMove.x = x; <BR>m_ptMove.y = y; <BR>m_pCanvas->Pen->Mode = pmCopy; <BR>} <BR> <BR>// 滑鼠放开事件处理函式 <BR>// 1.画出原点至目前点的直线。 <BR>void CLine::OnMouseUp(int x,int y) <BR>{ <BR>m_pCanvas->MoveTo(m_ptOrigin.x,m_ptOrigin.y); <BR>m_pCanvas->LineTo(x,y); <BR>} <BR> <BR>这就是画直线类别的定义及实作内容。 <BR> <BR>XX-03-03 CPolyline类别定义及实作 - 画随意线的类别 <BR> <BR>class CPolyline : public CShape <BR>{ <BR>public: <BR>POINT m_ptOrigin; <BR>public: <BR>CPolyline(TCanvas* pCanvas):CShape(pCanvas) {} <BR>virtual ~CPolyline() {} <BR>virtual void OnMouseMove(int,int); <BR>virtual void OnMouseDown(int,int); <BR>virtual void OnMouseUp(int,int); <BR>}; <BR> <BR>CPolyline类别其实和我们前面所写的涂鸦程式的行为模式极 <BR>为类似,所以我就简单带过好了。 <BR>void CPolyline::OnMouseDown(int x,int y) <BR>{ <BR>m_ptOrigin.x = x; <BR>m_ptOrigin.y = y; <BR>m_pCanvas->MoveTo(x,y); <BR>} <BR> <BR>void CPolyline::OnMouseMove(int x,int y) <BR>{ <BR>m_pCanvas->LineTo(x,y); <BR>} <BR> <BR>void CPolyline::OnMouseUp(int x,int y) <BR>{ <BR>m_pCanvas->LineTo(x,y); <BR>} <BR> <BR>XX-03-04 CPolygon类别定义及实作 - 画多边形的类别 <BR> <BR>class CPolygon : public CPolyline <BR>{ <BR>public: <BR>CPolygon(TCanvas* pCanvas):CPolyline(pCanvas){} <BR>virtual ~CPolygon() {} <BR>virtual void OnMouseUp(int,int); <BR>}; <BR> <BR>CPolygon是CPolyline的子类别,其差别仅在於它会将首尾两 <BR>点连接,使其成为一个多边形,因此我们就直接由CPolyline <BR>继承而来,只改写其OnMouseUp成员函式即可。 <BR> <BR>void CPolygon::OnMouseUp(int x,int y) <BR>{ <BR>m_pCanvas->MoveTo(m_ptOrigin.x,m_ptOrigin.y); <BR>m_pCanvas->LineTo(x,y); <BR>} <BR> <BR>XX-03-05 CRectangle类别定义及实作 - 画矩形的类别 <BR> <BR>class CRectangle : public CShape <BR>{ <BR>public: <BR>POINT m_ptMove; <BR>POINT m_ptOrigin; <BR>public: <BR>CRectangle(TCanvas* pCanvas):CShape(pCanvas) {} <BR>virtual ~CRectangle() {} <BR>virtual void OnMouseMove(int,int); <BR>virtual void OnMouseDown(int,int); <BR>virtual void OnMouseUp(int,int); <BR>}; <BR> <BR>画矩形类别其实和画线类别有些类似,它们同样必须记载上次 <BR>滑鼠移动的点,并擦掉原来的图形画出新的图形,所以我只针 <BR>对其相异的部份加以说明之: <BR> <BR>// 滑鼠移动事件处理函式 <BR>// 原理和CLine类似,只不过改成画矩形。 <BR>void CRectangle::OnMouseMove(int x,int y) <BR>{ <BR>m_pCanvas->Pen->Mode = pmXor; <BR>m_pCanvas- <BR>><I>Rectangle(m_ptOrigin.x,m_ptOrigin.y,m_ptMove.x,m_ptMo </I><BR>ve.y); <BR>m_ptMove.x = x; <BR>m_ptMove.y = y; <BR>m_pCanvas- <BR>><I>Rectangle(m_ptOrigin.x,m_ptOrigin.y,m_ptMove.x,m_ptMo </I><BR>ve.y); <BR>m_pCanvas->Pen->Mode = pmCopy; <BR>} <BR> <BR>XX-03-06 CRoundRect类别定义及实作 - 画圆矩形的类别 <BR> <BR>class CRoundRect : public CShape <BR>{ <BR>public: <BR>POINT m_ptMove; <BR>POINT m_ptOrigin; <BR>public: <BR>CRoundRect(TCanvas* pCanvas):CShape(pCanvas) {} <BR>virtual ~CRoundRect() {} <BR>virtual void OnMouseMove(int,int); <BR>virtual void OnMouseDown(int,int); <BR>virtual void OnMouseUp(int,int); <BR>}; <BR>CRoundRect的实作几乎和Crectangle相同,只不过它们呼叫 <BR>不同的API罢了,CRoundRect是以Canvas->RoundRect来画出 <BR>图形的。 <BR> <BR>void CRoundRect::OnMouseMove(int x,int y) <BR>{ <BR>m_pCanvas->Pen->Mode = pmXor; <BR>m_pCanvas- <BR>><I>RoundRect(m_ptOrigin.x,m_ptOrigin.y,m_ptMove.x,m_ptMo </I><BR>ve.y,4,4); <BR>m_ptMove.x = x; <BR>m_ptMove.y = y; <BR>m_pCanvas- <BR>><I>RoundRect(m_ptOrigin.x,m_ptOrigin.y,m_ptMove.x,m_ptMo </I><BR>ve.y,4,4); <BR>m_pCanvas->Pen->Mode = pmCopy; <BR>} <BR> <BR>XX-03-07 CEllipse 类别定义及实作 - 画圆形的类别 <BR> <BR>画圆形的处理和画矩形也大致相同,因为在Windows中是以包 <BR>围矩形来定义一个圆形,因此和CRoundRect相同的,我们只 <BR>要改写成画圆函式即可。其馀我就不多说了。 <BR> <BR>class CEllipse : public CShape <BR>{ <BR>public: <BR>POINT m_ptMove; <BR>POINT m_ptOrigin; <BR>public: <BR>CEllipse(TCanvas* pCanvas):CShape(pCanvas) {} <BR>virtual ~CEllipse() {} <BR>virtual void OnMouseMove(int,int); <BR>virtual void OnMouseDown(int,int); <BR>virtual void OnMouseUp(int,int); <BR>}; <BR> <BR>XX-03-08小结 <BR> <BR>以上就是此绘图程式中所使用的各个物件的定义,此乃血统纯 <BR>正的C++ <BR>写法的程式,不像C++Builder官方的范例是由Delphi的范例 <BR>修改而来,充满了Object Pascal的味道。 <BR> <BR>若你对C++ 尚不太熟悉的话,请你一定要细细领略以上的精神。 <BR>因为它是C++ 式的物件导向程式最基本且精要的精神所在,当 <BR>你了解了以上的精神,你就可谓掌握了C++ <BR>的封装、继承、及动态连结这三把权仗的基本精神。 <BR> <BR>至於C++ 老手,以上的定义都是很自然就可以接受的。也许有 <BR>人会质疑以上的物件定义并未考虑到物件的永续性 (Object <BR>Persistence)。没错,不过这并不是我疏忽了,而是在本章的 <BR>程式中图形的存取是以Timage来存取,因此所有向量式的物 <BR>件都已转化成点阵图了,自然不需考虑到物件的储存问题。 <BR> <BR>在後续章节,我还会再针对物件的永续性来做一讨论。现在我 <BR>们先就TImage的点阵图存取方式为平台讨论之。 <BR> <BR>最後,在完成了物件的定义之後,我们再将程式根据物件导向 <BR>的方式再加以改写之。因为我目前尚未加入选择物件的方法, <BR>所以我只能用预设物件型态的方式来展示程式的结果。 <BR> <BR>// 表格建构函式,设定m_bDraw旗标初值 <BR>__fastcall TForm1::TForm1(TComponent* Owner) <BR>∶<I> TForm(Owner) </I><BR>{ <BR>m_bDraw = FALSE; <BR>} <BR> <BR>// Form的OnCreate事件处理函式。Form建立时引发。 <BR>// 1.设定笔的颜色及宽度。 <BR>// 2.产生一个CLine绘图物件。 <BR>// 注:你可以自行修改CLine成CPolyline、CPolygon、CRect <BR>等值。 <BR> <BR>void __fastcall TForm1::FormCreate(TObject *Sender) <BR>{ <BR>Canvas->Pen->Color = clRed; <BR>Canvas->Pen->Width = 2; <BR>m_pObj = new CLine(Canvas); <BR>} <BR> <BR>// Form的OnClose事件处理函式。Form关闭时引发。 <BR>// 1.杀掉绘图物件。 <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -