📄 chap09.htm
字号:
</FONT><FONT SIZE=2><P>// 1. </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>判断旗标是否为</FONT><FONT SIZE=2>True</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>。若是则进行以下动作。</P></FONT><FONT SIZE=2><P>// 1. </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>将旗标设为</FONT><FONT SIZE=2> False</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>。</P></FONT><FONT SIZE=2><P>// 2. </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>画线并记录原点位置(非必要)。</P></FONT><FONT SIZE=2><P>void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button,</P></FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2><P>	</FONT><FONT SIZE=2>TShiftState Shift, int X, int Y)</P></FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2><P>{</P></FONT><FONT SIZE=2><P> if (m_bDraw)</P><P> {</P><P> m_bDraw=FALSE;</P><P> 	Canvas->MoveTo(m_nOrgX,m_nOrgY);</P><P> Canvas->LineTo(X,Y);</P><P> m_nOrgX = X;</P><P> m_nOrgY = Y;</P></FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2><P>	}</P><P>}</P><P> </P><P>将滑鼠事件处理函式做以上的修改之後,我们就完成了一个基本的涂鸦程式的雏形了。我将此表格的背景设为黑色,笔的状态设为</FONT><FONT SIZE=2>2</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>单位宽度的红色笔,就得到以下的输出结果:</P><P> </P><P><IMG SRC="Image10.gif" WIDTH=463 HEIGHT=356></P><P> </P></FONT><FONT SIZE=2><P>XX-03	</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>绘图物件的定义</P><P> </P><P>至目前为止,我们已经完成了一个简单的涂鸦程式,接下来,我希望将程式扩充为一个一般的绘图程式,它必须具备基本的画线、画圆、画方等功能。为了要实作出这些功能,我们必须先定义我们的绘图物件。</P><P> </P></FONT><FONT SIZE=2><P>XX-03-01	</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>绘图物件之始</FONT><FONT SIZE=2>CShape</P><P> </P><P>class CShape</P><P>{</P><P>protected:</P><P>	TCanvas*	m_pCanvas;</P><P>	TColor 		m_Color;</P><P>	int 	 	m_nWidth;</P><P>public:</P><P>	CShape(TCanvas* pCanvas)	 {m_pCanvas = pCanvas;}</P><P> virtual ~CShape() {}</P><P>virtual void OnMouseMove(int,int)=0;</P><P>virtual void OnMouseDown(int,int)=0;</P><P>virtual void OnMouseUp(int,int)=0;</P><P>};</P><P> </P></FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2><P>我们首先定义一个</FONT><FONT SIZE=2>CShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>类别,它是所有绘图物件之始,也因此它定义了一个绘图物件的基本行为。在此绘图程式中我希望它可以处理叁个不同的滑鼠事件并加以处理之,所以我在</FONT><FONT SIZE=2>CShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>中定义了叁个相对应的成员函式,而且它们都是纯虚拟函式,表示所有继承自</FONT><FONT SIZE=2>CShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>的类别都必须改写此叁个成员函式。</FONT><FONT SIZE=2> </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>(关於物件导向的关念请参阅</FONT><FONT SIZE=2> <</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>必要的</FONT><FONT SIZE=2>C++ </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>基础章节</FONT><FONT SIZE=2>> </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>或是相关书籍,在此尽作简短的解释)。这叁个函式名称称如下:</P><P> </P></FONT><FONT SIZE=2><P>virtual void OnMouseMove(int,int)=0;</P><P>virtual void OnMouseDown(int,int)=0;</P><P>virtual void OnMouseUp(int,int)=0;</P><P> </P></FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2><P>另外我们再定义一般性的绘图物件都会用到的基本特性,如颜色及线条宽度,再加上绘图时所需要的</FONT><FONT SIZE=2> Canvas</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>,如此就组成了</FONT><FONT SIZE=2>CShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>的类别定义:</P><P> </P><P>	</FONT><FONT SIZE=2>TCanvas*	m_pCanvas; // </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>绘图所需的</FONT><FONT SIZE=2>Canvas </P><P>	TColor 		m_Color; // </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>颜色</P><P>	</FONT><FONT SIZE=2>int 	 	m_nWidth; // </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>宽度</P><P> </P><P>至於</FONT><FONT SIZE=2>CShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>的解构函式为何也设成</FONT><FONT SIZE=2>virtual</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>呢?这关系到继承物件的毁灭方法。若是基础类别的解构函式没有定义成虚拟函式时,会造成特定情况下,子类别的解构函式没有被呼叫到的情形:</P><P>如:</P><P> </P></FONT><FONT SIZE=2><P>CLine *pLine = new Line;</P><P>CShape* pShape=pLIne;</P><P>delete pShape;</P><P> </P></FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2><P>上述的例子因为</FONT><FONT SIZE=2>CLine</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>为</FONT><FONT SIZE=2>CShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>的子类别,因此可以直接将</FONT><FONT SIZE=2>pShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>指标指向</FONT><FONT SIZE=2>pLine</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>,然而在後面</FONT><FONT SIZE=2>delete pShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>时,若是</FONT><FONT SIZE=2>pShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>的解构函式不为虚拟函式,会造成</FONT><FONT SIZE=2>pLine</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>的解构函式不被呼叫到。这是一般</FONT><FONT SIZE=2>C++ </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>程式设计时很容易犯的错误。</P><P> </P><P>我们可以将以上的经验法则归纳成一个原则,即是:只要该类别有可能被继承,就必须将其解构函式设为虚拟函式。如此就有了以下的定义了:</P><P> </P><P>	</FONT><FONT SIZE=2>CShape(TCanvas* pCanvas)	 {m_pCanvas = pCanvas;}</P><P> virtual ~CShape() {}</P><P> </P><P>CShape</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>的建构函式必须传入</FONT><FONT SIZE=2>Canvas</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>以便绘图,而解构函式则不做任何事,只将其定义为虚拟函式。</P><P> </P></FONT><FONT SIZE=2><P>XX-03-02 CLine</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>类别定义及实作 画直线的类别</P><P> </P></FONT><FONT SIZE=2><P>class CLine : public CShape</P><P>{</P><P>public:</P><P> POINT m_ptMove;</P><P>	 POINT	m_ptOrigin;</P><P>public:</P><P>		CLine(TCanvas* pCanvas):CShape(pCanvas)	{}</P><P> virtual ~CLine() 				{}</P><P>virtual void OnMouseMove(int,int);</P><P>virtual void OnMouseDown(int,int);</P><P>virtual void OnMouseUp(int,int);</P><P>};</P><P> </P></FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2><P>我们将</FONT><FONT SIZE=2>CLine</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>定义为一个画直线的类别,而我们希望在画直线时可以在拖弋滑鼠时将原先的线条擦去,并画出新的线,因此我们必须宣告两个点来记载滑鼠按下的点及上次的点以便擦去原来的线条。</P><P>以下就是</FONT><FONT SIZE=2>CLine</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>对於叁个滑鼠事件的处理函式:</P><P> </P></FONT><FONT SIZE=2><P>//	</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>滑鼠按下的事件处理函式</P></FONT><FONT SIZE=2><P>// 	1. </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>设定原点及上个启始点为目前所在点。</P></FONT><FONT SIZE=2><P>//	2. </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>移动至目前所在点。</P></FONT><FONT SIZE=2><P>void CLine::OnMouseDown(int x,int y)</P><P>{</P><P>	m_ptOrigin.x = m_ptMove.x = x;</P><P> m_ptOrigin.y = m_ptMove.y = y;</P><P>	m_pCanvas->MoveTo(x,y);</P><P>}</P><P> </P><P>//	</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>滑鼠移动事件处理函式</P></FONT><FONT SIZE=2><P>//	1.</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>将画笔模式设为</FONT><FONT SIZE=2>XOR</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>模式,以便擦去上一条线。</P></FONT><FONT SIZE=2><P>//	2.</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>擦去原来的线(以</FONT><FONT SIZE=2>XOR</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>模式再画一次就会擦去了)</P></FONT><FONT SIZE=2><P>//	3.</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>在目前的位置画出一条新线。</P></FONT><FONT SIZE=2><P>//	4.</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>更新坐标并改变画笔模式。</P></FONT><FONT SIZE=2><P>void CLine::OnMouseMove(int x,int y)</P><P>{</P><P> m_pCanvas->Pen->Mode = pmXor;</P><P> m_pCanvas->MoveTo(m_ptOrigin.x,m_ptOrigin.y);</P><P> m_pCanvas->LineTo(m_ptMove.x,m_ptMove.y);</P><P> m_pCanvas->MoveTo(m_ptOrigin.x,m_ptOrigin.y);</P><P> m_pCanvas->LineTo(x,y);</P><P> m_ptMove.x = x;</P><P> m_ptMove.y = y;</P><P> m_pCanvas->Pen->Mode = pmCopy;</P><P>}</P><P> </P><P>//	</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>滑鼠放开事件处理函式</P></FONT><FONT SIZE=2><P>//	1.</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>画出原点至目前点的直线。</P></FONT><FONT SIZE=2><P>void CLine::OnMouseUp(int x,int y)</P><P>{</P><P> m_pCanvas->MoveTo(m_ptOrigin.x,m_ptOrigin.y);</P><P>	m_pCanvas->LineTo(x,y);</P><P>}</P><P> </P></FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2><P>这就是画直线类别的定义及实作内容。</P><P> </P></FONT><FONT SIZE=2><P>XX-03-03 CPolyline</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>类别定义及实作</FONT><FONT SIZE=2> </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>画随意线的类别</P><P> </P></FONT><FONT SIZE=2><P>class CPolyline : public CShape</P><P>{</P><P>public:</P><P>	 POINT	m_ptOrigin;</P><P>public:</P><P>		CPolyline(TCanvas* pCanvas):CShape(pCanvas)	{}</P><P> virtual ~CPolyline() 				{}</P><P>virtual void OnMouseMove(int,int);</P><P>virtual void OnMouseDown(int,int);</P><P>virtual void OnMouseUp(int,int);</P><P>};</P><P> </P><P>CPolyline</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>类别其实和我们前面所写的涂鸦程式的行为模式极为类似,所以我就简单带过好了。</P></FONT><FONT SIZE=2><P>void CPolyline::OnMouseDown(int x,int y)</P><P>{</P><P>	m_ptOrigin.x = x;</P><P> m_ptOrigin.y = y;</P><P>	m_pCanvas->MoveTo(x,y);</P><P>}</P></FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2><P> </P></FONT><FONT SIZE=2><P>void CPolyline::OnMouseMove(int x,int y)</P><P>{</P><P>	m_pCanvas->LineTo(x,y);</P><P>}</P><P> </P><P>void CPolyline::OnMouseUp(int x,int y)</P><P>{</P><P>	m_pCanvas->LineTo(x,y);</P><P>}</P><P> </P><P>XX-03-04 CPolygon</FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>类别定义及实作</FONT><FONT SIZE=2> </FONT><FONT FACE="新细明体" LANG="ZH-TW" SIZE=2>画多边形的类别</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -