Delphi 图形设计(2)
Windows是一个基于图形用户界面的操作系统。
若要在窗口上作图,需要调用Windows提供的应用程序接口(Application Program Interface,API),还要申请和维护句柄等资源。
Delphi将这一切都封装在TCanvas类中,通过设置TCanvas类中的属性,调用其中的方法,就可以实现画图功能。
虽然在任何组件上都可以绘制图形,但由于很多组件上都有标题之类的文字,所以通常在窗体或面板之类的容器上绘制图形。
例如,最常用的画图容器为Form和PaintBox。这些容器的空白区域称为画布(Canvas),使用画布类TCanvas的方法可在画布上绘制直线、弧线、矩形或圆形等各种图形。
Canvas是TCanvas类的一个系统定义对象,称为画布对象,通常作为其他控件的一个属性出现,不单独使用。每个控件都有Canvas属性。例如,使用Form的Canvas属性即可在窗体的工作区内绘图。由于Canvas是运行时属性,在程序运行时才能获得,所以必须写程序来完成设置。
Canvas的主要属性有Pen、Brush、Pixels、PenPos等,用于定义绘制图形的风格。
Pen画笔用于控制线条的颜色、模式、风格及宽度。
Pen的类型为TPen类,属性有Color、Mode、Style及Width。
· Color属性:控制线条的颜色。
· Mode属性:控制线条的模式,取值见表10-2。
表10-2 Canvas.Pen.Mode属性取值
值
含 义
pmBlack
总为黑色
pmWhite
总为白色
pmNop
不改变
pmNot
画布背景的相反色
pmCopy
用Color属性指定的画笔颜色
pmNotCopy
画笔颜色的相反色
pmMerge
画笔颜色与画布背景色的合成颜色
pmXor
画笔颜色与画布背景色的异或合成颜色
pmNotXor
pmXor的相反色
· Style属性:控制线条的风格,包括实线、虚线和点划线等,取值见表10-3。
表10-3 Canvas.Pen.Style属性取值
值
含 义
值
含 义
psSolid
实线
psDashDotDot
两点一划线
psDash
短划线
psClear
不划线,通常用于清除轮廓线
psDot
点线
psInsideFrame
实线,Width属性大于1时
psDashDot
点划线
· Width属性:控制线条的宽度。
Width属性的值为整型,如果所给的值小于1,则按1处理。注意,Width属性值会影响Style属性值,当Width属性值不是1时,Style属性值不能是PsDash或PsDashDot。 例如:
Form1.Canvas.Pen.Color:=clRed; //设置线条颜色为白色
Form1.Canvas.Pen.Style:=psDashDot; //设置线风格为点划线
Form1.Canvas.Pen.Width:=1; //设置线宽度为1,即细线
Brush刷子用于确定图形填充的颜色及填充方式。
Brush类型为TBrush类,属性有Color、Style。
· Color属性:确定图形的填充颜色。
· Style属性:确定图形的填充方式,取值见表10-4。
例如:
Form1.Canvas.Brush.Color:=clRed; //设置填充色为红色
Form1.Canvas.Brush.Style:=bsSolid; //设置填充方式为实填充
一般情况下,Brush为矩形、圆或多边形提供内部的填充色和填充图案,还为文本提供背景色,但它不影响线条的颜色和文本的前景色。
表10-4 Canvas.Brush.Style属性取值
取 值
含 义
取 值
含 义
bsSolid
实填充
bsCross
十字交叉线填充
bsClear
不填充
bsDiagCross
交叉线填充
bsBDiagonal
右斜线填充
bsHorizontal
水平线填充
bsFDiagonal
左斜线填充
bsVertical
垂直线填充
Pixels属性用于存储Canvas中每个像素点的颜色值。定义如下:
property Pixels(x,y;integer):TColor;
Pixels是一个二维数组,下标表示某像素点在屏幕位置的坐标,元素类型是TColor。一个绘图过程实际上就是改变画布上有关像素点颜色的过程,从而在视觉效果上得到一幅特定的图。例如:
Form1.Canvas.Pixels[100,200]:=clYellow; //将窗口内的一点涂上黄色
反之,读取Pixels数组的元素值则可取得相应坐标点的颜色值。
PenPos属性表示当前画笔的位置,类型为TPoint。例如:
i:=Form1.Canvas.PenPos.x; //获得当前画笔位置
j:=Form1.Canvas.PenPos.y;
TCanvas类提供多种用于绘图和文字输出的方法。
在组件上绘图的坐标体系与屏幕、窗口相同。
水平方向是X轴,垂直方向是Y轴,左上角起始点坐标是(0,0),区域内任意一点的坐标用(x,y)表示,右下角点的坐标值取决于屏幕分辨率,例如,屏幕分辨率为800×600,则右下角点的坐标为(799,599)。
MoveTo(x,y)将画笔当前位置设置到点(x,y)处。画笔当前位置在PenPos属性中,改变画笔当前位置使用MoveTo方法,而不要设法改变PenPos的值。
LineTo(x,y)从当前位置至(x,y)点画一条线,并把画笔当前位置移至(x,y)处。所绘直线具有已定义Pen画笔的各项属性。例如:
Canvas.MoveTo(x1,y1); //定位(x1,y1)
Canvas.LineTo(x2,y2); //在(x1,y1)和(x2,y2)之间画线
Rectangle方法用当前的Pen和Brush属性绘制一个矩形,声明如下:
procedure Rectangle(x1,y1,x2,y2:integer);
其中,(x1,y1)和(x2,y2)分别表示矩形左上角和右下角两点坐标。若|x2- x1|=|y2 - y1|,则该矩形成为正方形。
Ellipse方法在指定的矩形内画一个椭圆,声明如下:
procedure Ellipse(x1,y1,x2,y2:integer);
其中,(x1,y1)和(x2,y2)分别表示矩形左上角和右下角两点坐标。如果指定矩形为正方形时,椭圆就成为圆。
Polygon方法用当前Pen和Brush属性绘制并填充任意边数的多边形,声明如下:
procedure Polygon(Points:array of TPoint);
多边形的多个坐标点存储在数组Points中,Points数组的实际长度决定多边形的边数。一个可填充的多边形应是封闭的,即首尾两点坐标一致。
Points数组元素为TPoint,表示一个点的坐标。TPoint声明如下:
type
TPoint = packed record
X: Longint;
Y: Longint;
end;
Types单元的Point函数将两个整型值生成一个TPoint对象。Point函数声明如下:
function Point(AX,AY:Integer):TPoint;
例如,下列程序段在矩形(x1 , y1 , x2 , y2)范围内画出一个等腰三角形。
var p:array [0..3] of TPoint;
p[0]:=point(x1 +(x2-x1) div 2,y1);
p[1]:=point(x1,y2);
p[2]:=point(x2,y2);
p[3]:=p[0];
Canvas.Polygon(p);
Textout方法用当前Font属性在指定位置(x,y)显示指定字符串Text,声明如下:
procedure TextOut(x,y;integer;const Text:string);
在Windows中运行应用程序,窗口的基本操作由Windows控制执行。
当窗口启动时,Windows需要绘制窗口上全部的图形图像;当一个窗口被其他窗口覆盖后再被激活时,Windows需要重新绘制该窗口上曾被覆盖部分的图形图像。例如,窗口从最大化、最小化状态还原时,或被其他窗口覆盖、当其他窗口关闭或移开时,窗口被激活,Windows都将重画标准控件的图形图像。
Delphi的标准控件都具有重画功能,像窗体、按钮、编辑框等,它们在窗口被激活时都能够自动地、完整地显示自身。
当窗口启动或被激活时,触发窗体的OnPaint事件。如果需要在窗口上绘图,则必须在Form的OnPaint事件上写绘图程序。
当窗口启动时,Windows显示窗口及其中控件,执行窗体的OnPaint事件绘制用户设计的图形。
当窗口被激活时,Windows会向窗口发送一个WM_Paint消息。Delphi对该消息进行处理,先清除窗口上的图形,然后触发OnPaint事件,重新绘制图形。
当程序需要主动刷新图形时,可以调用Repaint方法来刷新窗口。
Repaint方法自动产生一个WM_Paint消息,先清除窗口上的图形,再产生OnPaint事件,重新绘制同样的图形。
在程序运行过程中,利用鼠标可以实现动态地作图,就像Windows的画图程序一样。
利用鼠标作图,需要在程序中识别鼠标位置和鼠标动作,鼠标有3个动作:鼠标按下、鼠标移动和鼠标松开。在Delphi中,对应3个鼠标动作有3个不同的事件:
(1)当鼠标按下时,发生OnMouseDown事件。
(2)当鼠标松开时,发生OnMouseUp事件。
(3)当鼠标移动时,发生OnMouseMove事件。
Form的OnMouseDown事件声明为:
procedure TForm1.FormMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
其中的5个参数含义如下:
· Sender:探测鼠标动作的对象。
· Button:涉及的鼠标按钮:mbLeft左键,mbMiddle中键,mbRight右键。
· Shift:鼠标动作时,Alt、Ctrl、Shift键的状态。
· X、Y:事件发生时鼠标的坐标。
OnMouseUp和OnMouseMove事件声明和参数含义类似。
【例10.1】拖动鼠标画直线并显示直线的动态变化情况。
本例通过绘制直线演示3个鼠标响应事件上语句的配合。程序运行时,随着鼠标的移动,用户可随时观测直线的变化。程序运行窗口如图10-1所示。
图10-1 拖动鼠标画直线
如果要在鼠标移动时随时观测直线的变化,则必须首先记住鼠标按下处的起始点位置。程序如下:
var Origin,MovePt:TPoint; //直线的起始点与移动点 mouse_down:Boolean; //鼠标是否按下的状态procedure TForm1.FormMouseDown(Sender:TObject; //鼠标按下事件 Button:TMouseButton;Shift:TShiftState;X,Y:Integer);begin mouse_down:=true; //鼠标已按下 Canvas.MoveTo(X,Y); Origin:=Point(X,Y); //记载直线的起始点位置 MovePt:=Origin; //记载直线的移动点位置end;procedure TForm1.FormMouseMove(Sender:TObject; //鼠标移动事件 Shift:TShiftState;X,Y:Integer);begin if mouse_down //鼠标按下时画直线 then begin Canvas.Pen.Mode:=pmNotXor; //画笔线条为异或模式 Canvas.MoveTo(origin.X,origin.Y); //擦除前一点的直线 Canvas.LineTo(MovePt.X,MovePt.Y); MovePt := Point(X, Y); Canvas.MoveTo(origin.X,origin.Y); //重画当前点的直线 Canvas.LineTo(MovePt.X,MovePt.Y); end;end; procedure TForm1.FormMouseUp(Sender:TObject; //鼠标松开事件 Button: TMouseButton; Shift: TShiftState; X, Y: Integer);begin Canvas.LineTo(X,Y); //画直线 mouse_down:= false; //鼠标已松开end;