在本章中我将为你示范怎么在C++Builder中编写一个完整的绘图程式。藉由这个程式的编写,你会更加了解C++Builder的 Canvas 绘图精神,而在编写这个程式的同时,我们也可将相关的技术做一个整体的检阅。此绘图程式的执行结果如下:
点击查看大图 在此程式中我会以循序渐进的方式一步一步地带领你完成整个程式,基础上这个程式和C++Builder内附的范例程式有几分类似,但我必须要说明的是:在 C++Builder中所附的范例程式是直接由原先在Delphi内以 Object Pascal 所编写的范例程式修改而成,所以有部份程式的写法大为违反C++ 式物件导向精神,在迈入C++Builder 的新世纪之後,我们当然希望写出的程式是『系出名门,血统纯正』的C++ 式的物件导向程式。而这就是我在本章中希望带领你完成的程式。 XX-01 关於滑鼠事件(Mouse Event) 编写绘图程式,首先要了解滑鼠事件,在Windows中定义了许多的滑鼠讯息(Message),而这些滑鼠讯息在BCB中就成为滑鼠事件了,为了要处理滑鼠事件,我们必须要选写滑鼠事件处理程式: 在Windows中定义的滑鼠讯息列表 WM_CAPTURECHANGED WM_LBUTTONDBLCLK WM_LBUTTONDOWN WM_LBUTTONUP WM_MBUTTONDBLCLK WM_MBUTTONDOWN WM_MBUTTONUP WM_MOUSEACTIVATE WM_MOUSEMOVE WM_NCHITTEST WM_NCLBUTTONDBLCLK WM_NCLBUTTONDOWN WM_NCLBUTTONUP WM_NCMBUTTONDBLCLK WM_NCMBUTTONDOWN WM_NCMBUTTONUP WM_NCMOUSEMOVE WM_NCRBUTTONDBLCLK WM_NCRBUTTONDOWN WM_NCRBUTTONUP WM_RBUTTONDBLCLK WM_RBUTTONDOWN WM_RBUTTONUP 表XX-01 Windows内滑鼠相关 Message。 虽然在Windows作业系统中定义了非常多的讯息,但是在C++Builder 中已经把庞大的讯息系统作适度的简化了,并且不再以讯息的方式存在,而改以事件 (Event)的处理方式,在本章的绘图程式中,我们只要处理以下的几个事件就可以了: OnMouseDown 滑鼠键按下事件 OnMouseMove 滑鼠移动事件 OnMouseUp 滑鼠键放开事件 OnClick 任何滑鼠的点取 在此,你可以很明显地发现,在C++Builder的事件中并未将左右滑鼠键分别定义,而是以合并处理的方式,因此在收到以上滑鼠事件时,若你要分辨左右滑鼠事件时,必须在事件处理程式中判定左右键。 具备了基础的滑鼠事件认知後,我们开始进行後续的程式探索吧! 为了让你实际了解程式的细节,我希望将程式编写的步骤细节交代楚,在往下进行之前,我们先建立一个新的专案档,并将其命名为 DrawMain,同时将Form的Color性质设为黑色(clBlack),以便直接在上面画图。 XX-02滑鼠事件的处理 当C++ Builder应用程式侦测到物件滑鼠事件时,它会检查你是否定义该物件相对应的滑鼠事件处理程式,然後呼叫该函数,将相关参数传给它。以OnMouseDown事件为例,它的事件处理程式模版如下: void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { } 它总共接收了以下几个参数: Sender 引发该事件的软体元件。 Button 表示滑鼠的按键。它的值可为mbLeft(左键),mbRight(右键),mbMiddle(中间键)。 Shift 用以表示事件发生的同时Alt,Shift及Ctrl叁键的状态。 X,Y 用以表示事件发生时之座标位置。 在大多数的情况下,滑鼠事件的(X,Y)座标值是我们最为感爱好的项目,不过,有时候我们也需要靠Button键来判定滑鼠的按键,或是需要利用Shift来取得非凡键的状态,而做一些额外的程式处理。 XX-02-01 OnMouseDown事件的处理 首先我们先以一个最基础的画线程式来说明OnMouseDown事件的处理,当使用者按下滑鼠时,我们希望将笔移至事件发生时的坐标,因此我们可将程式写成如下: void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { Canvas->MoveTo(X,Y); } XX-02-03 OnMouseUp事件的处理 同样地,我们可以再为这个Form加上OnMouseUp的事件处理函式,在收到OnMouseUp事件时,由滑鼠点下的坐标,画一条直线至现在的坐标。
void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { Canvas->LineTo(X,Y); } 在写完了以上两个事件处理函式之後,我们就可以在Form上面作画了,你可以用滑鼠在Form上面拖戈出一条条直线。其执行结果大致如图XX-01:

图XX-01 XX-02-02 OnMouseMove事件的处理 在加上了OnMouseDown及OnMouseUp处理函式之後,我们只能画出一条条直线,若是我们想要以滑鼠画出不规则线段时,就必须再处理OnMouseMove事件,利用OnMouseMove事件,我们可以追纵到滑鼠移动的位置,简单的OnMouseMove事件处理函式如下: void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { Canvas->LineTo(X,Y); } 此程式的意义即在於将滑鼠所经过的每个点,以线条连接起来,在加上OnMouseMove 事件处理函式之後