Delphi教程VCL高级组件编程第2讲之文字作图作者:金海龙(软件工程师)本文免费下载地址:VCL高级组件编程第2讲.doc作为一名软件工程师,我知道什么是必备的编程技术,对于研发第三方组件的个人开发者,或者刚开始学习Delphi2010的人来说,最重要的是学会:如何在Canvas上写字。因此需要编写一个函数,能够在所有的控件表面写多行文字,并能能够任意对齐。Delphi的Canvas提供了写文字的函数,但是对于写多行文字(且对齐排列)的支持不是很好,Win32API中也有个关于写字的函数,但也不好用,所以我编写了一个专门用来写多行文字的函数,并且能够按照以下方式对齐:1、垂直方向靠上对齐,水平方向靠左对齐;2、垂直方向靠上对齐,水平方向靠中间对齐;3、垂直方向靠上对齐,水平方向靠右对齐;4、垂直方向靠中间对齐,水平方向靠左对齐;5、垂直方向靠中间对齐,水平方向靠中间对齐;6、垂直方向靠中间对齐,水平方向靠右对齐;7、垂直方向靠下对齐,水平方向靠左对齐;8、垂直方向靠下对齐,水平方向靠中间对齐;9、垂直方向靠下对齐,水平方向靠右对齐。下面是实例程序运行时的图片:说明:其中有两个文本框,第一个文本框用来控制垂直方向的对齐方式,数字1代表靠上对齐,数字2代表靠中间对齐,数字3代表靠下对齐;第二个文本框用来控制水平方向的对齐方式,数字1代表靠左对齐,数字2代表靠中间对齐,数字3代表靠右对齐;下面的图片演示了“在Form2中以各种对齐方式输出多行文字”的情况:当按钮“Draw”被单击时,就会调用下面的过程:procedureTForm2.Button1Click(Sender:TObject);beginRepaint;//擦掉旧的图形drawlabelfacetext(canvas,clientrect,form1.Memo1.Lines,strtoint(edit1.text),strtoint(edit2.text),false,clwhite,nottrue);//上面一句代码的意思是:在Form2的clientrect区域写form1.Memo1中的文字。canvas.Brush.Style:=bsclear;canvas.Rectangle(clientrect);end;通过上面的代码,不难发现这个写字的函数叫:DrawLabelFaceText();为何取这么个名字?因为类似“drawtext,textout”等函数名都已经被广泛使用,为了避免混淆,所以重新取了个函数名。FaceText的意思是:表面文字;“DrawLabelFaceText”的意思就是:画Label控件表面的文字。这个函数就在Form2中,下面会给出完全源代码。但在此之前,先看看这个函数的参数的意义:procedureDrawLabelFaceText(Canvas:TCanvas;R1:TRect;S:TStrings;TopAlign:integer=1;LeftAlign:integer=1;Enabled:boolean=true;DisabledColor:TColor=$00FEFEFE;ShowAccelChar:Boolean=true);“Canvas:TCanvas;R1:TRect;S:TStrings;”这三个函数的意思是:把S中的文字写到Canvas的R1区域;TopAlign:integer=1;LeftAlign:integer=1;这两个参数指定了文字在R1区域中的对齐方式,用数字代表对齐的方式。Enabled:boolean=true;DisabledColor:TColor=$00FEFEFE;如果你细心观察过控件,那么就会发现每个控件都有一个Enabled属性,如果这个属性不是真,那么就无法进行单击操作,并且表面的文字就会显示出阴影。这两个参数就是用于控制文字是否有阴影。只有当Enabled=false时,DisabledColor才起作用,DisabledColor指定了阴影的颜色,一般情况下设置成白色就行了。ShowAccelChar:Boolean=true;有时候S中要包含“&”字符,当这个参数等于true,那么这个字符就不会被显示,且这个字符后的那个字符会带下划线显示。如果要在Label、Button等控件表面写文字,那么就需要把这个参数设置成true;如果要在edit、memo等控件表面写文字,那么就需要把这个参数设置成false;下面是Form2源代码(至于所涉及到的Form1,可以替换成你自己的,你可以从下面找出所需的函数,Form1不是很重要):unitUnit2;interfaceusesWindows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls;typeTForm2=class(TForm)Button1:TButton;Edit1:TEdit;Edit2:TEdit;procedureButton1Click(Sender:TObject);private{Privatedeclarations}public{Publicdeclarations}end;varForm2:TForm2;implementationusesUnit1;{$R*.dfm}functionCalculateTStringsHeight(Canvas:TCanvas;S:TStrings):Integer;begin//把s写到画布canvas上,若要垂直居中对齐,需要计算文字的高度,这个函数用来计算S里文字的高度Result:=S.Count*Canvas.TextHeight('金');end;functionVertAlignRct(R1:TRect;RctHeight:integer;setop:boolean=true):TRect;vari:integer;r:TRect;begin//计算居中对齐的区域R:=r1;i:=abs(R1.Bottom-R1.Top);ifRctHeightithenifsetopthenR:=Rect(r1.Left,r1.Top+round((i-RctHeight)/2),r1.Right,r1.Bottom)elseR:=Rect(r1.Left,r1.Bottom-RctHeight,r1.Right,r1.Bottom);result:=r;end;functionCalculateTStringsWidth(Canvas:TCanvas;S:TStrings):Integer;vari,co,ii,r:integer;begin//把s写到画布canvas上,若要垂直居中对齐,需要计算文字的Width,这个函数用来计算S里文字的Widthco:=s.Count-1;r:=0;fori:=0tocodobeginii:=Canvas.TextWidth(s[i]);ifiirthenr:=ii;end;//overforresult:=r;end;functionHorzAlignRct(R1:TRect;RctWidth:integer;seleft:boolean=true):TRect;vari:integer;r:TRect;begin//计算居中对齐(水平)的区域R:=r1;i:=abs(R1.Right-R1.Left);ifRctWidthithenifseleftthenR:=Rect(r1.Left+round((i-RctWidth)/2),r1.Top,r1.Right,r1.Bottom)elseR:=Rect(r1.Right-RctWidth,r1.Top,r1.Right,r1.Bottom);result:=r;end;procedureDrawLabelFaceText(Canvas:TCanvas;R1:TRect;S:TStrings;TopAlign:integer=1;LeftAlign:integer=1;Enabled:boolean=true;DisabledColor:TColor=$00FEFEFE;ShowAccelChar:Boolean=true);varuFormat:cardinal;R2,R22,R3:TRect;C:TColor;B:TBrush;P:TPen;begin{以对齐方式写字符串,多余的将被隐藏;参数TopAlign指定:在垂直方向的对齐方式,TopAlign=1=上对齐TopAlign=2=中对齐TopAlign=3=下对齐参数LeftAlign指定:在水平方向的对齐方式,LeftAlign=1=左对齐LeftAlign=2=中对齐LeftAlign=3=下对齐如果Enabled等于false,那么参数disabledcolor就会起作用,显示的文字将会带有阴影,阴影的颜色由disabledcolor决定。}uFormat:=DT_LEFT;ifShowAccelChar=falsethenuFormat:=uFormat+DT_NOPREFIX;B:=TBrush.Create;P:=TPen.Create;B.Assign(Canvas.Brush);P.Assign(Canvas.Pen);R2:=R1;iftopalign=1thenuFormat:=uFormat+DT_TOPelseiftopalign=2thenbeginR2:=VertAlignRct(R1,CalculateTStringsHeight(Canvas,S),true);endelseiftopalign=3thenbeginR2:=VertAlignRct(R1,CalculateTStringsHeight(Canvas,S),false);end;ifleftalign=2thenR2:=HorzAlignRct(R2,CalculateTStringsWidth(Canvas,S),true)elseifleftalign=3thenR2:=HorzAlignRct(R2,CalculateTStringsWidth(Canvas,S),false);ifnotEnabledthenBeginC:=Canvas.Font.Color;Canvas.Font.Color:=DisabledColor;R3:=Rect(R2.Left+1,R2.Top+1,R2.Right,R2.Bottom);Canvas.Brush.Style:=bsclear;DrawText(Canvas.Handle,PChar(S.Text),-1,R3,uFormat);Canvas.Font.Color:=C;End;Canvas.Brush.Style:=bsclear;DrawText(Canvas.Handle,PChar(S.Text),-1,R2,uFormat);//这是Win32API提供的函数//Canvas.Brush.Assign(B);Canvas.Pen.Assign(P);end;procedureTForm2.Button1Click(Sender:TObject);beginRepaint;//擦掉旧的图形drawlabelfacetext(canvas,clientrect,form1.Memo1.Lines,strtoint(edit1.text),strtoint(edit2.text),false,clwhite,nottrue);canvas.Brush.Style:=bsclear;canvas.Rectangle(clientrect);end;End.下面是Form1中的图片,演示了Enabled不同值时的情况:感谢我主天主使我写出