📄 00000002.htm
字号:
<HTML><HEAD> <TITLE>BBS水木清华站∶精华区</TITLE></HEAD><BODY><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER>发信人: life (沙加~重结晶), 信区: BCB <BR>标 题: 具体而微的绘图程式 <BR>发信站: BBS 水木清华站 (Thu Nov 19 09:00:31 1998) <BR> <BR>第XX章 具体而微的绘图程式 <BR> <BR>在本章中我将为你示范如何在C++Builder中撰写一个完整的 <BR>绘图程式。藉由这个程式的撰写,你会更加了解C++Builder <BR>的 Canvas <BR>绘图精神,而在撰写这个程式的同时,我们也可将相关的技术 <BR>做一个整体的检阅。此绘图程式的执行结果如下: <BR> <BR> <BR> <BR> <BR>在此程式中我会以循序渐进的方式一步一步地带领你完成整个 <BR>程式,基本上这个程式和C++Builder内附的范例程式有几分 <BR>类似,但我必须要说明的是:在 <BR>C++Builder中所附的范例程式是直接由原先在Delphi内以 <BR>Object Pascal 所撰写的范例程式修改而成,所以有部份程式 <BR>的写法大为违背C++ <BR>式物件导向精神,在迈入C++Builder 的新世纪之後,我们当 <BR>然希望写出的程式是『系出名门,血统纯正』的C++ <BR>式的物件导向程式。而这就是我在本章中希望带领你完成的程 <BR>式。 <BR> <BR>XX-01 关於滑鼠事件(Mouse Event) <BR> <BR>撰写绘图程式,首先要了解滑鼠事件,在Windows中定义了许 <BR>多的滑鼠讯息(Message),而这些滑鼠讯息在BCB中就成为滑 <BR>鼠事件了,为了要处理滑鼠事件,我们必须要选写滑鼠事件处 <BR>理程式: <BR> <BR>在Windows中定义的滑鼠讯息列表 <BR>WM_CAPTURECHANGED <BR>WM_LBUTTONDBLCLK <BR>WM_LBUTTONDOWN <BR>WM_LBUTTONUP <BR>WM_MBUTTONDBLCLK <BR>WM_MBUTTONDOWN <BR>WM_MBUTTONUP <BR>WM_MOUSEACTIVATE <BR>WM_MOUSEMOVE <BR>WM_NCHITTEST <BR>WM_NCLBUTTONDBLCLK <BR>WM_NCLBUTTONDOWN <BR>WM_NCLBUTTONUP <BR>WM_NCMBUTTONDBLCLK <BR>WM_NCMBUTTONDOWN <BR>WM_NCMBUTTONUP <BR>WM_NCMOUSEMOVE <BR>WM_NCRBUTTONDBLCLK <BR>WM_NCRBUTTONDOWN <BR>WM_NCRBUTTONUP <BR>WM_RBUTTONDBLCLK <BR>WM_RBUTTONDOWN <BR>WM_RBUTTONUP <BR>表XX-01 Windows内滑鼠相关 Message。 <BR> <BR>虽然在Windows作业系统中定义了非常多的讯息,但是在 <BR>C++Builder 中已经把庞大的讯息系统作适度的简化了,并且 <BR>不再以讯息的方式存在,而改以事件 <BR>(Event)的处理方式,在本章的绘图程式中,我们只要处理以 <BR>下的几个事件即可: <BR> <BR>OnMouseDown 滑鼠键按下事件 <BR>OnMouseMove 滑鼠移动事件 <BR>OnMouseUp 滑鼠键放开事件 <BR>OnClick 任何滑鼠的点取 <BR> <BR>在此,你可以很明显地发现,在C++Builder的事件中并未将 <BR>左右滑鼠键分别定义,而是以合并处理的方式,因此在收到以 <BR>上滑鼠事件时,若你要分辨左右滑鼠事件时,必须在事件处理 <BR>程式中判断左右键。 <BR> <BR>具备了基本的滑鼠事件认知後,我们开始进行後续的程式探索 <BR>吧! <BR> <BR>为了让你实际了解程式的细节,我希望将程式撰写的步骤细节 <BR>交代楚,在往下进行之前,我们先建立一个新的专案档,并将 <BR>其命名为 <BR>DrawMain,同时将Form的Color性质设为黑色(clBlack), <BR>以便直接在上面画图。 <BR> <BR>XX-02滑鼠事件的处理 <BR> <BR>当C++ <BR>Builder应用程式侦测到物件滑鼠事件时,它会检查你是否定 <BR>义该物件相对应的滑鼠事件处理程式,然後呼叫该函数,将相 <BR>关叁数传给它。以OnMouseDown事件为例,它的事件处理程式 <BR>模版如下: <BR>void __fastcall TForm1::FormMouseDown(TObject *Sender, <BR>TMouseButton Button, <BR>TShiftState Shift, int X, int Y) <BR>{ <BR>} <BR> <BR>它总共接收了以下几个叁数: <BR>Sender 引发该事件的软体元件。 <BR>Button 表示滑鼠的按键。它的值可为mbLeft(左键),mbRight <BR>(右键),mbMiddle(中间键)。 <BR>Shift 用以表示事件发生的同时Alt,Shift及Ctrl三键的状 <BR>态。 <BR>X,Y 用以表示事件发生时之座标位置。 <BR> <BR>在大多数的情况下,滑鼠事件的(X,Y)座标值是我们最为感 <BR>兴趣的项目,不过,有时候我们也需要靠Button键来判断滑 <BR>鼠的按键,或是需要利用Shift来取得特殊键的状态,而做一 <BR>些额外的程式处理。 <BR> <BR>XX-02-01 OnMouseDown事件的处理 <BR> <BR>首先我们先以一个最基本的画线程式来说明OnMouseDown事件 <BR>的处理,当使用者按下滑鼠时,我们希望将笔移至事件发生时 <BR>的坐标,因此我们可将程式写成如下: <BR> <BR>void __fastcall TForm1::FormMouseDown(TObject *Sender, <BR>TMouseButton Button, <BR>TShiftState Shift, int X, int Y) <BR>{ <BR>Canvas->MoveTo(X,Y); <BR>} <BR>XX-02-03 OnMouseUp事件的处理 <BR> <BR>同样地,我们可以再为这个Form加上OnMouseUp的事件处理 <BR>函式,在收到OnMouseUp事件时,由滑鼠点下的坐标,画一条 <BR>直线至现在的坐标。 <BR> <BR>void __fastcall TForm1::FormMouseUp(TObject *Sender, <BR>TMouseButton Button, <BR>TShiftState Shift, int X, int Y) <BR>{ <BR>Canvas->LineTo(X,Y); <BR>} <BR> <BR>在写完了以上两个事件处理函式之後,我们就可以在Form上 <BR>面作画了,你可以用滑鼠在Form上面拖戈出一条条直线。其 <BR>执行结果大致如图XX-01: <BR> <BR> <BR>图XX-01 <BR>XX-02-02 OnMouseMove事件的处理 <BR> <BR>在加上了OnMouseDown及OnMouseUp处理函式之後,我们只能 <BR>画出一条条直线,若是我们想要以滑鼠画出不规则线段时,就 <BR>必须再处理OnMouseMove事件,利用OnMouseMove事件,我们 <BR>可以追纵到滑鼠移动的位置,简单的OnMouseMove事件处理函 <BR>式如下: <BR> <BR>void __fastcall TForm1::FormMouseMove(TObject *Sender, <BR>TShiftState Shift, int X, <BR>int Y) <BR>{ <BR>Canvas->LineTo(X,Y); <BR>} <BR> <BR>此程式的意义即在於将滑鼠所经过的每个点,以线条连接起 <BR>来,在加上OnMouseMove 事件处理函式之後,它的执行结果会 <BR>变成图XX-02: <BR> <BR>图XX-02 <BR>XX-02-03 滑鼠的处理的加强 <BR> <BR>前面的程式对於滑鼠的移动处理有部份考虑的不够周详,因为 <BR>它在滑鼠移动时不分青红皂白就将线画在萤慕上,造成萤幕上 <BR>的线条混乱,这并不是正规的处理方法,正确的处理方法应该 <BR>如下: <BR> <BR>(1) 滑鼠键按下时,将记录滑鼠按下的旗标设为True.同时将 <BR>该点记录下来,谓之原点。 <BR> 滑鼠移动时,判断滑鼠按下的旗标是否设为 True,若为 <BR>True,则移动至原点,并画一条由原点至目前所在点的线。同 <BR>时更新原点位置至目前所在之点。 <BR> 滑鼠放开时,将记录滑鼠按下的旗标设为False。 <BR> <BR>以下就是关於三个滑鼠事件的处理程式码。 <BR> <BR>// 滑鼠按下的事件处理函式 <BR>// 1. 将旗标设为True <BR>// 2. 记录原点位置 <BR>void __fastcall TForm1::FormMouseDown(TObject *Sender, <BR>TMouseButton Button, <BR>TShiftState Shift, int X, int Y) <BR>{ <BR>m_bDraw = TRUE; <BR>m_nOrgX=X; <BR>m_nOrgY=Y; <BR>} <BR> <BR>// 滑鼠移动的事件处理函式 <BR>// 1. 判断旗标是否为True。若是则进行以下动作。 <BR>// 2. 移动至原点。 <BR>// 3. 画一条由原点至目前所在点的线条。 <BR>// 4. 更改原点位置。 <BR> <BR>void __fastcall TForm1::FormMouseMove(TObject *Sender, <BR>TShiftState Shift, <BR>int X, int Y) <BR>{ <BR>if (m_bDraw) <BR>{ <BR>Canvas->MoveTo(m_nOrgX,m_nOrgY); <BR>Canvas->LineTo(X,Y); <BR>m_nOrgX = X; <BR>m_nOrgY = Y; <BR>} <BR>} <BR> <BR>// 滑鼠放开的事件处理函式 <BR>// 1. 判断旗标是否为True。若是则进行以下动作。 <BR>// 1. 将旗标设为 False。 <BR>// 2. 画线并记录原点位置(非必要)。 <BR>void __fastcall TForm1::FormMouseUp(TObject *Sender, <BR>TMouseButton Button, <BR>TShiftState Shift, int X, int Y) <BR>{ <BR>if (m_bDraw) <BR>{ <BR>m_bDraw=FALSE; <BR>Canvas->MoveTo(m_nOrgX,m_nOrgY); <BR>Canvas->LineTo(X,Y); <BR>m_nOrgX = X; <BR>m_nOrgY = Y; <BR>} <BR>} <BR> <BR>将滑鼠事件处理函式做以上的修改之後,我们就完成了一个基 <BR>本的涂鸦程式的雏形了。我将此表格的背景设为黑色,笔的状 <BR>态设为2单位宽度的红色笔,就得到以下的输出结果: <BR> <BR> <BR> <BR>XX-03 绘图物件的定义 <BR> <BR>至目前为止,我们已经完成了一个简单的涂鸦程式,接下来, <BR>我希望将程式扩充为一个一般的绘图程式,它必须具备基本的 <BR>画线、画圆、画方等功能。为了要实作出这些功能,我们必须 <BR>先定义我们的绘图物件。 <BR> <BR>XX-03-01 绘图物件之始CShape <BR> <BR>class CShape <BR>{ <BR>protected: <BR>TCanvas* m_pCanvas; <BR>TColor m_Color; <BR>int m_nWidth; <BR>public: <BR>CShape(TCanvas* pCanvas) {m_pCanvas = pCanvas;} <BR>virtual ~CShape() {} <BR>virtual void OnMouseMove(int,int)=0; <BR>virtual void OnMouseDown(int,int)=0; <BR>virtual void OnMouseUp(int,int)=0; <BR>}; <BR> <BR>我们首先定义一个CShape类别,它是所有绘图物件之始,也 <BR>因此它定义了一个绘图物件的基本行为。在此绘图程式中我希 <BR>望它可以处理三个不同的滑鼠事件并加以处理之,所以我在 <BR>CShape中定义了三个相对应的成员函式,而且它们都是纯虚拟 <BR>函式,表示所有继承自CShape的类别都必须改写此三个成员 <BR>函式。 <BR>(关於物件导向的关念请叁阅 <必要的C++ 基础章节> 或是相 <BR>关书籍,在此尽作简短的解释)。这三个函式名称称如下: <BR> <BR>virtual void OnMouseMove(int,int)=0; <BR>virtual void OnMouseDown(int,int)=0; <BR>virtual void OnMouseUp(int,int)=0; <BR> <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -