delphi的函数
发布时间:2025-05-21 00:28:12 发布人:远客网络
一、delphi的函数
与过程一样,函数的程序代码也执行特定的工作。它和过程的差别为:函数执行时会返回一个值,而过程则没有返回值。函数可以用来赋给一个属性或变量;也可以使用返回值来决定程序的流程。前文中实际上已经接触过了函数。在讲述变量时,曾用到过下面的程序段:Edit1.Text:=IntToStr(X+Y);其中,IntToStr(Value)把一个LongInt类型的数值转化为字符串的值,Value是IntToStr唯一的参数,它可以是一个整形的值、变量、属性或产生整形值的表达式。调用函数,必须把返回值赋给和此返回值类型兼容的变量或属性。
有些函数返回一个True或False的布尔量,用户的程序可以根据返回值来决定跳转。下文的例程讲述了函数返回值为Boolean的判断用法:
在窗体中加入一个ColorDialog对象和一个Name属性为ChangeColor的按钮。为按钮的OnClick事件建立事件处理过程如下:
procedureTForm1.ChangeColorClick(Sender:TObject);
Form1.Color:=ColorDialog1.Color
此事件处理过程使用一个返回Boolean值的Execute方法。按动按钮,并在颜色对话框中选择一个颜色。如果按动OK按钮,ColorDialog.Execute方法将返回True,则Form1.Color将被赋值为ColorDialog1.Color,窗体显现您选用的颜色;如果按动颜色对话框的Cancel按钮,方法将返回False值,窗体将变为红色。
ObjectPascal的跳转语句有if和case两个。
if语句会计算一个表达式,并根据计算结果决定程序流程。在上文的例程中,根据ColorDialog.Execute的返回值,决定窗体的背景颜色。if保留字后跟随一个生成Boolean值True或False的表达式。一般用“=”作为关系运算符,比较产生一个布尔型值。当表达式为True时,执行then后的语句。否则执行else后的代码,if语句也可以不含else部分,表达式为False时自动跳到下一行程序。
if语句可以嵌套,当使用复合语句表达时,复合语句前后需加上begin…end。else保留字前不能加“;”,而且,编译器会将else语句视为属于最靠近的if语句。必要时,须使用begin…end保留字来强迫else部分属于某一级的if语句。程序代码在调用一个过程或函数时,通常用参数传递数据到被调用的过程或函数中。最常用的参数有数值参数、变量参数和常量参数三种。由被调用过程或函数定义的参数为形参,而由调用过程或函数指明的参数叫实参。在NoValue函数中,说明函数体中的AnEditBox是形参,而调用时在ifNoValue(Edit1)…中,Edit1是实参。
数值参数在运行过程中只改变其形参的值,不改变其实参的值,即参数的值不能传递到过程的外面。试看下面的例程:
procedureCalculate(CalNo:Integer);
Number接受由编辑框1输入的数值,经Calculate过程运算。它是一个数值型实参。在进入Calculate函数后,会把Number实参拷贝给形参CalNo,在过程中CalNo增大十倍,但并未传递出来,因此Number值并未改变,在编辑框2中显示仍然是编辑框1中的输入值。形参和实参占用不同的内存地址,在过程或函数被调用时,将实参的值复制到形参占用的内存中。因此出了过程或函数后,形参和实参的数值是不同的,但实参的值并不发生变化。如果您想改变传入的参数值,就需要使用变量参数,即在被调用程序的参数表中的形参前加上保留字var。例如:procedureCalculate(varCalNo:Integer);
则CalNo并不在内存中占据一个位置,而是指向实参Number。当一个变参被传递时,任何对形参所作的改变会反映到实参中。这是因为两个参数指向同一个地址。将上一个例程中过程头的形参CalNo前面加上var,再以同样的程序调用它,则在第二个编辑框中会显示计算的结果,把第一个编辑框中的数值放大十倍。这时形参CalNo和实参Number的值都是Nnmber初始值的10倍。
如果当过程或函数执行是要求不改变形参的值,最保险的办法是使用常量参数。在参数表的参数名称前加上保留字const可以使一个形参成为常量参数。使用常量参数代替数值参数可以保护您的参数,使您在不想改变参数值时不会意外地将新的值赋给这个参数。
二、从TurboPascal到Delphi
1、我是在高一接触pascal语言因为参加NOI的需要顺理成章的要使用Turbo Pascal来写程序了半年后我开始想着如何编写Windows程序又理所当然的找上Delphi初见Delphi除了begin end让我觉得倍感亲切外 Object Pascal里的增加的面向对象的语法却让我很是吃惊当时的我可根本不懂什么叫面向过程面向对象最可恶的是国内那些教育家们除了会拿着清华的那本精简的不能再精简的pascal教材照本宣科外似乎再也没有什么实质性的工作了传说中的《Turbo Pascal大全》更是无处可寻所以关于unit interface这些Delphi里随处可见的关键字我也很不明白所幸其后不久我得到一本名为《计算机反病毒技术》的书里面统统都是用Turbo Pascal编写的源代码通过它我迅速明白了早已存在于Turbo Pascal中unit interface等关键字的含义和用法又以Delphi中的Help文档为扶手开始蹒跚学步了
2、印象中国内Delphi作家似乎更偏爱编写应用实例类的技术书籍至于语法这种东西没有几个人愿意多去涉及即使书中必须谈及也是寥寥数笔匆匆带过或者干脆与某本书类似对Object Pascal语法讲解最好最权威的恐怕就算《Delphi开发人员指南》了这本书至今也是备受推崇的但与如今泛滥的C++书籍相比 Delphi仍然逊色许多也难怪很多新手特别是从来没有接触过pascal语言的新手在学习Object Pascal时会遇到不少困难自己的感觉是在从Turbo Pascal向Delphi过渡的过程中由于没有正确的指引走了很多弯路由于没有正确的桥梁必须要一步实现大跨越所以在这里我提出自己曾经遇见的沟壑路标性给出我自己的认识和总结希望给入门的同学们一些帮助我不打算详细介绍语法知识并假设你已经有一点pascal语言和面向对象概念的基础要想学习相关详细知识我推荐各位一定要阅读《Delphi开发人员指南》和Delphi Help文档中的相关章节
3、习惯了在一个Program模块内写完所有面向过程代码的我有几天的时间一直未能彻底明白在非Unit模块中非继承的自定义类的框架语法是如何的 VCL源代码虽然经典却过于繁杂不能让我迅速掌握根本我需要一个最简单又最能说明问题完整的可运行的代码苦于无处寻求答案只好亲自动手探索对应关系终成其下两段代码
4、 program TP;{本代码在Turbo Pascal下编译通过}typeMyRecord= record{}end;
5、 varMR: MyRecord;procedure Procedure;begin{Procedure Code}end;{=========== main===========}begin{以这个begin为标志主程序开始其作用相当于C/C++中的main函数}Procedure;end
6、上面是一段及其简单的包含记录类型声明和过程声明的代码二者基本规则如下用户自定义的数据类型需要放在以保留字 type开头的代码段中过程(procedure)和函数(function)要放在以保留字 var开头的代码段中最后一个夹在begin和end间的代码段是主程序的开始也就是整个程序的入口作用相当于C/C++里的main函数请注意只有在以program保留字开头的代码模块中这个begin和end才具有程序入口的作用
7、另外在Turbo Pascal中已经支持原始的面向对象它的声明关键字是Object与现在我们常见的Class不同语法如下 objectField;Field; Method;Method;end;
8、 Method允许以下几种形式 procedure MethodName(:type);
9、或者function MethodName(:type):type;
10、或者constructor MethodName(: type [;:type]); [virtual];
11、或者destructor MethodName[(: type)];[virtual];
12、不错的构造函数和析构函数都支持virtual在构造函数中还有一个有用的东西是Fail函数当构造函数的初始化失败时它可以用来释放已经分配的资源遗憾的是 Object里面还没有区分私有共有接下来的代码是Turbo Pascal的Help文档中关于Fail函数的演示代码可以让大家对此有个较深的认识 Turbo Pascal却是是很强大和优秀的
13、 typePBase= ^TBase;TBase= object(TObject){在这里就已经出现Tobject了是不是很亲切?}constructor Init(FailMe: Boolean);end;
14、 PDerived= ^TDerived;TDerived= object(TBase)constructor Init(FailMe: Boolean);end;
15、 constructor TBase Init(FailMe: Boolean);begininherited Init;if FailMe then Fail;end;constructor TDerived Init(FailMe: Boolean);beginif not inherited Init(FailMe) then{判断父类的初始化是否成功}{ Ancestor failed to construct we must fail too}Fail;{ Otherwise proceed with construction}{}end;varP: PObject;X: Boolean;beginfor X:= False to True dobeginP:= New(PDerived Init(X));if P<> nil thenbeginwriteln( Object constructed sucessfully);Dispose(P Done);endelsewriteln( Object failed to construct);end;end回到Delphi中再看下面的代码 program Delphi;{代码在Delphi下编译通过}{$APPTYPE CONSOLE}usesSysUtils;typeTMyClass= class(TObject)publicconstructor Create;procedure PrintClassName;privateClassName: string;end;varMyClass: TMyClass;constructor TMyClass Create;beginClassName:= TMyClass;end;procedure TMyClass PrintClassName;beginwriteln(ClassName);end;{=========== main===========}beginMyClass:= TMyClass Create;MyClass PrintClassName;MyClass Free;readln;end
16、类作为用户自定义的一种数据类型其声明的规则成员函数过程的实现方法都符合经典 Pascal的基本规则唯一不同的是保留字变了从记录体变成了类(详细比较代码结构和语法规则)这也说明Object Pascal是在经典Pascal的基础上进行了面向对象内容的语法扩充当然内部的运行机制并没有表面语法扩充这么轻松可那是编译器的事情在这里我们完全不用理会差点忘记告诉读者怎么调试上面的代码了在IDE环境主菜单里选择 File| New| Other在New Item项里选择Console Application这时出现了代码编辑框再将上面的代码贴入 F完成!代码内的{$APPTYPE CONSOLE}是一个编译开关它告诉编译器这是控制台程序在格式上它与注释的差别就是那个$符号 TMyClass= class(TObject)可以简写为
17、 TMyClass= class表示TMyClass类从TObject类继承而来 TObject是Delpi中所有对象的祖先这也是为什么我在代码中没有声明Destroy过程却仍然能够使用的原因 Delphi中类的构造很有趣请注意MyClass:= TMyClass Create这一句这与C++不同 readln使程序停顿下来直到用户按下回车键才结束程序退出更多详细内容请参考《Delphi开发人员指南》节
18、上面两段代码相互对应虽然很简单不过我却认为他们在某种程度上很容易让同学发现由经典Pascal向Object Pascal过渡的一些方法对Object Pascal的类定义语法有个初步了解这是很重要的一步当初我要是能够看到这两段代码或许能少浪费很多时间了
19、在Turbo Pascal的Help文档里是这样说明unit功能的 Units are the basis of modular programming inBorland Pascal You use units to createlibraries and to divide large programs into logically related modules传统上我们都将所有代码集中在一个program模块中可是面对更加复杂的功能代码正确的划分功能封装功能对代码管理和以后的维护有着重要的作用而使用unit模块正好解决了这些问题其语法规则如下
20、 unit identifier;{ Heading}interface{ Public symbols}:uses{ Uses clause}const{ Constants}type{ Types}var{ Variables}procedure{ Procedures}function{ Functions}implementation{ Private symbols}:uses{ Uses clause}label{ Labels}const{ Constants}type{ Types}var{ Variables}procedure{ Procedures}function{ Functions}begin{ Initialization}statement;{ Statements}statementend
21、 Interface部分用来声明对外接口也就是可以被外部引用该文件的程序使用的函数和过程 implementation部分包含接口部分声明的各种函数过程具体实现的代码 begin一直到最后的end之间都是初始化部分可以为本unit内的各种变量过程函数初始化如果没有内容需要初始化那么begin可以省略但end必须存在
22、在Delphi下经典Pascal中的unit部分有了变动请看来源于Delphi Help文档的说明 unit Unit;interfaceuses{ List of units goes here}{ Interface section goes here}implementationuses{ List of units goes here}{ Implementation section goes here}
23、 initialization{ Initialization section goes here}finalization{ Finalization section goes here}end可见Initialization部分的关键字begin被Initialization取代了并且增加了一个finalization部分 Initialization部分的代码可以这样写 initializationbegin{do something…}end;也可以这样写 initialization{do something…}finalization部分的功能有点类似于析构函数它主要针对本unit模块中initialization部分初始化的资源进行释放并且是在程序结束时运行如果程序以Halt过程结束了该部分的程序将不能执行
24、 Unit模块中的interface等关键字和结构初看似乎有些限制程序员的自由度但也正是这种语法规定体现出Pascal语言的严谨和优美为减少程序出错的几率做出保证 program相当文章的提纲挈领 unit则是文章的各个段落 Delphi里 program模块包含在 prj文件中 unit模块包含在传统的 pas文件中这就是为什么在Delphi中我们经常面对的是为各个窗口服务的unit模块而非在一个program中写完所有代码不过我在Delpi的Help中看到这样一句话 In traditional Pascal programming all source code including the main program is stored in pas files不知道这算思考角度不同还是算bug毕竟这种语法并非Delphi中才有 Turbo Pascal程序员也一直在采用这种方法组织程序结构给出一个简单的initialization例子在菜单中选择File| New| Application再在窗体上放置一个按钮双击该按钮编写它的Click事件处理代码完整代码如下
25、 unit Unit;interfaceusesWindows Messages SysUtils Variants Classes Graphics Controls Forms Dialogs StdCtrls;typeTForm= class(TForm)Button: TButton;procedure Button Click(Sender: TObject); private{ Private declarations}public{ Public declarations}end;
26、 varForm: TForm;Msg: string;implementation{$R* dfm}procedure TForm Button Click(Sender: TObject);beginShowMessage(Msg);Msg:= second;end;initializationMsg:= first;end
27、以上所述是过渡中两个基本的重要问题弄懂它们方可初步明白自己为什么要这样编写代码该在哪里编写代码如何扩展代码功能推荐的参考书籍
28、《Delphi开发人员指南》机械工业出版社
29、《Inside VCL》李维电子工业出版社
30、《Delphi深度历险》陈宽达科学出版社
31、《Pascal精要》网络下载电子版Windows参考书籍
32、《Programming Windows》Charles Petzold
33、《Windows开发人员指南》中国水利水电出版社
34、 Delphi组件参考书我暂时没有发现特别好的平时我主要依靠论坛源代码 Delphi自带的Demo和文档来学习组件的使用
35、现在有一些大学取消了Pascal语言课程去年的ACM大赛也取消了Pascal语言的使用不禁心寒启蒙教育没有人做了这些都使得Delphi在学生中的处境更加艰难在国内的Delphi论坛上常常见到许多半吊子程序员在享受Delphi的快速开发的时候嘴巴里还在责备Delphi功能太弱不能搞什么底层开发甚至直接责怪Pascal语言殊不知在Dos年代有多少著名软件使用Pascal开发出来的呢有多少底层控制程序有着Pascal的身影呢?现在我手头上还有Pascal编写的病毒代码反病毒代码 IC芯片控制代码
36、或许正是Delphi的RAD能力降低了程序开发的门槛让很多半吊子进入了程序界 RAD开发蒙蔽了许多半吊子编程者(称呼他们为程序员或许稍欠火候)的眼睛但是国内的教育界同样有着不可推卸的责任选修课开VB的不少讲Delphi的很少我曾经还遇到过一个从心底里就瞧不起Delphi不啻谈论的老师而事实上他根本就没有用过Delphi我现在常去外国网站发现国内被争论不休的问题在国外早就有人在做并且做的非常棒
三、delphi中format函数详解
format('%*.* f',[10,4,num]);
解析:返回num变量格式化后的字符。整数位为10位,小数后为4位。
例如:num=1234567890.123456,处理后为“1234567890.1234”的字符串。
format函数,返回一个指定格式的字符。
function Format(const Format: string; const Args: array of const): string;
const Fromat:string:格式信息
格式化信息主要有以下元素组成:
"%"+ [索引":"]+ ["-"]+ [宽度]+ ["."摘要]+类型
Format('x=%d', [12]);//'x=12'//最普通
Format('x=%3d', [12]);//'x= 12'//指定宽度
Format('x=%f', [12.0]);//'x=12.00'//浮点数
Format('x=%.3f', [12.0]);//'x=12.000'//指定小数
Format('x=%8.2f'[12.0])//'x= 12.00';
Format('x=%.*f', [5, 12.0]);//'x=12.00000'//动态配置
Format('x=%.5d', [12]);//'x=00012'//前面补充0
Format('x=%.5x', [12]);//'x=0000C'//十六进制
Format('x=%1:d%0:d', [12, 13]);//'x=1312'//使用索引
Format('x=%p', [nil]);//'x=00000000'//指针
Format('x=%1.1e', [12.0]);//'x=1.2E+001'//科学记数法
Format('x=%%', []);//'x=%'//得到"%"
S:= Format('%s%d', [S, I]);//S:= S+ StrToInt(I);//连接字符串
index":"]这个要怎么表达呢,看一个例子
Format('this is%d%d',[12,13]);
其中第一个%d的索引是0,第二个%d是1,所以字符显示的时候是这样 this is 12 13
Format('this is%1:d%0:d',[12,13]);
那么返回的字符串就变成了this is 13 12。现在明白了吗,[index":"]中的index指示Args中参数显示的顺序还有一种情况,如果这样
Format('%d%d%d%0:d%d', [1, 2, 3, 4])
如果你想返回的是1 2 3 1 4,必须这样定:
Format('%d%d%d%0:d%3:d', [1, 2, 3, 4])
但用的时候要注意,索引不能超出Args中的个数,不然会引起异常如
Format('this is%2:d%0:d',[12,13]);
由于Args中只有12 13两个数,所以Index只能是0或1,这里为2就错了[width]指定将被格式化的值占的宽度,看一个例子就明白了
Format('this is%4d',[12]);
输出是:this is 12,这个是比较容易,不过如果Width的值小于参数的长度,则没有效果。
Format('this is%1d',[12]);
["-"]这个指定参数向左齐,和[width]合在一起最可以看到效果:
Format('this is%-4d,yes',[12]);
["." prec]指定精度,对于浮点数效果最佳:
Format('this is%.2f',['1.1234]);
Format('this is%.7f',['1.1234]);
而对于整型数,如果prec比如整型的位数小,则没有效果反之比整形值的位数大,则会在整型值的前面以0补之
Format('this is%.7d',[1234]);
对于字符型,刚好和整型值相反,如果prec比字符串型的长度大则没有效果,反之比字符串型的长度小,则会截断尾部的字符
Format('this is%.2s',['1234']);
输出是 this is 12,而上面说的这个例子:
Format('this is%e',[-2.22]);
返回的是:this is-2.22000000000000E+000,怎么去掉多余的0呢,这个就行啦
Format('this is%.2e',[-2.22]);