[工学]delphi教程22
Delphi数据库程序设计(3)\nObjectPascal语言基础ObjectPascal的语句ObjectPascal的数据类型变量与常量过程与函数面向对象的程序设计单元文件的结构异常与异常处理程序调试简介Delphi第二部分ObjectPascal语言基础\n2.5过程与函数过程与函数都是能够完成某个(或某些)特定功能的程序段,它们在语法功能上相当于一个简单语句,即凡是语法要求简单语句的地方,都可以使用过程或函数。所不同的是,过程与函数都是独立的程序块。在开发Delphi应用程序时,所需的大部分代码都编写在事件处理过程中,但有时仍然需要编写不是事件处理过程的函数或过程。例如,可以把在多个事件处理过程中用得到的语句编写成过程,然后任何事件处理过程、过程、函数都可以象调用已经存在的系统函数一样直接调用它。这样做有两个好处:一是只需编写一次代码,二是程序代码会比较简洁。另外,还可以将由一个工程或多个工程共享的过程与函数封装在一个单元里,供其他单元和项目调用。这些共享的过程与函数的调用格式在单元的接口中(interface)需要说明。\n2.5.1过程与函数的定义DelphiProcedure过程名(参数及其类型说明)Var变量说明begin过程体语句end;function函数名(参数及其类型说明):函数返回值的类型Var变量说明begin过程体语句result:=返回的函数值;end;区别一:区别二:\n(1)关于参数参数位于括号里面,每一个参数以分号分隔。例如:procedurevalidateDate(Day:Integer;month:Integer;Year:Integer);也可以将相同类型的参数组合在一起,则上述过程写作:procedureValidateDate(Day,Month,Year:Integer);函数在标题中还多了一项:返回值的类型。下面是一个返回值为Double型的函数标题:functionCalculateInterest(principal,InterestRate:Double):Double;(2)过程和函数中的类型说明一个过程或函数程序模块也含有说明部分和语句部分。说明部分可以包括类型说明、变量说明、常量说明等。一般来讲,在过程和函数中,任何类型说明都在变量说明之前,而任何变量说明都在常量之前。但是,只要遵从说明必须在过程与函数的标题之后,而且在程序代码之前,即是有效的。\nDelphi过程或函数的语句部分由begin开始,end结束。函数需要一个返回值。可以将返回值赋给函数名称,也可以将返回值赋给Result变量。下面的例程将返回值赋给函数名称:functionCalculateInterest(Principal,InterestRate:Double):Double;beginCalculateInterest:=Principal*InterestRate;end;将返回值赋给Result变量也是可以的,则上面的程序改为:Result:=Principal*InterestRate;下面是这个函数的调用方法:InterestEarned:=CalculateInterest(2000,0.012);(3)过程和函数的语句部分\n2.5.2参数传递在调用过程和函数时,实参与形参的结合有两种方式:值传送与地址传送。所谓值传送,就是实参与形参各分配不同的内存单元,在调用子程序时,仅仅是把实参的值复制到对应的形参中。无论形参变量的值在子程序中是否改变,都不会影响实参变量值。如果在定义子程序时,在形参变量之前加上var,就是采用地址传送方式。在执行子程序时,形参本身并不分配独立的内存单元,而只是指向实参。换句话说,实参向形参传递的不是它的值,而是其内存地址。由于实参与形参实际上共用一个内存单元,所以形参的值在子程序中的改变也就是改变了实参的值。Procedureexchange(a,b:integer);Procedureexchange(vara,b:integer);值传递地址传递\n在开发Delphi应用程序时,所需的大部分代码都编写在事件处理过程中,但有时仍然需要编写不是事件处理过程的函数或过程。例如,可以把在多个事件处理过程中用得到语句编写成过程,然后任何事件处理过程、过程、函数都可以象调用已经存在的系统函数一样直接调用它。这样做有两个好处:一是只需编写一次代码,二是程序代码会比较简洁。这个练习中,将制做一个简单的密码校验界面。程序将判断用户输入的用户名和密码是不是预设的值,如果输入为空,程序将出现相关提示。其中“判断用户输入是否为空”即是“一个不是事件处理过程的函数”。通过这个练习,我们将了解delphi中的自定义函数及自定义过程的编写,同时还将学习屏蔽密码输入的方法。应用程序一启动,第一个出现在用户面前的界面一般是用户权限检查。用于输入用户名和密码的编辑框采用了Edit构件。用户输入的几位密码全显示为*号,其实现方法是将Edit组件的PasswordChar属性设置为*(默认值为#0)。如果符合,则允许用户进入后面的操作界面。否则给出出错信息,退出应用程序。例2.7简单密码校验,用于过程与函数的练习\n例2.7“判断用户输入是否为空”的“非事件处理过程的函数”FunctionNovalue(aneditbox:Tedit):Boolean;beginifaneditbox.Text=''thenbeginaneditbox.Color:=clRed;aneditbox.Text:=‘请输入';result:=true;endelsebeginaneditbox.Color:=clWindow;result:=false;end;end;(1)函数定义(2)形参变量(3)函数返回值\n“为Button1加入如下的OnClick”的“事件处理过程”procedureTForm1.Button1Click(Sender:TObject);beginifnovalue(edit1)ornovalue(edit2)thenexit;if(edit1.text='abcde')and(edit2.text='12345')thenshowmessage(‘注册成功!')elseshowmessage(‘用户名与密码不符,请重新输入!');end;(1)事件处理过程(2)函数调用(3)实参(4)showmessage函数例2.7\n“为两个Edit框加入如下的OnClick”的“事件处理过程”procedureTForm1.Edit1Click(Sender:TObject);beginedit1.Text:='';edit1.Color:=clwindow;end;procedureTForm1.Edit2Click(Sender:TObject);beginedit2.Text:='';edit2.Color:=clwindow;end;例2.7(1)事件处理过程(2)清空两个Edit框实习要求:1、修改“为Button1加入如下的OnClick”的“事件处理过程”部分,使得只许输入三次用户名与密码,若超过三次则自动退出。2、编写一个用于清空edit框的过程(非事件处理过程),procedureClearEdit(AnEditBox:Tedit);然后,在两个Edit框的OnClick事件处理过程中调用。\n2.5.3常用系统函数与过程(1)时间及其转换函数①Date日期函数,该函数返回系统当前日期,定义格式为:functionDate:TDateTime;TDateTime类型在Delphi语法中表示一个“日期-时间”值。②Time时间函数.该函数返回系统当前时间,定义格式为:functionTime:TDateTime;③Now时间函数.该函数返回系统当前日期和时间,定义格式为:functionNow:TDateTime;\n2.5.3常用系统函数与过程(1)时间及其转换函数④类型转换函数:datetostrtimetostrdatetimetostr⑤FormatDateTime格式化日期和时间函数,该函数按照参数Format指定的格式输出DateTime的日期和时间信息。定义格式为:functionFormatDateTime(constFormat:string;DateTime:TdateTime):string;例:FormatDateTime('yyyy.mmmm.dd.dddd""hh:mm:ssAM/PM',now);\nprocedureTForm1.Button3Click(Sender:TObject);varpresent:tdatetime;year,month,day,hour,min,sec,msec:word;temp:string;beginpresent:=now;decodedate(present,year,month,day);temp:=inttostr(year)+'.'+inttostr(month)+'.'+inttostr(day)+'/';decodetime(present,hour,min,sec,msec);label1.caption:=temp+''+inttostr(hour)+':'+inttostr(min);end;静态时钟\n2.5.3常用系统函数与过程(2)字符串型及转换函数①Chr该函数返回指定的ASCII码的字符,定义格式为:functionChr(x:Byte):Char;例如:Chr(97)函数值为“a”②CompareStr字符串比较函数.定义格式为:functionCompareStr(consts1,s2:String):Integer;如果s1>s2,函数返回值为正整数;如果s1
<常量、类型、变量、过程及函数声明部分>implementationuses<引用单元列表><常量、类型、变量、过程及函数声明部分><过程与函数实现部分>Initialization<单元初始化代码部分>finalization<单元后处理代码部分>end.单元总体结构如下:(2)单元接口部分(3)单元实现部分(4)初始化部分(可选)(5)结束部分(可选)(1)单元标识Delphi6\ninterface是unit单元的接口部分,它决定了本单元对其他任何单元或程序的可见(可访问)部分。可以在接口部分说明变量、常量、数据类型、过程和函数等等。Delphi在设计窗体的单元中,将窗体数据类型、窗体变量和事件处理过程都说明在这一部分。interface标志单元接口部分的开始。在interface中的说明对要使用这些说明的其他单元或应用程序是可见的。一个单元可以使用其他Unit的说明,只需要在uses子句中指明那些单元即可。例如,在单元A中编写程序代码,且想调用UnitB于interface部分说明的程序。可以把单元B的名称加入到A的interface部分的uses子句中,则任何A中的程序都可以调用B中说明的程序。而且,如果B中interface部分的uses子句中出现C单元,尽管A中未曾出现C,A同样可以调用B、C单元在interface中说明的程序。但如果B出现在A的interface部分的uses子句中,那么单元A便不能出现在B的interface的uses子句中。因为这样会产生对单元的循环访问。当试图编译时,会产生出现错误信息。unit单元的接口部分\ninterfaceusesWindows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls;typeTForm1=class(TForm)Label1:TLabel;Edit1:TEdit;Label2:TLabel;Edit2:TEdit;Button1:TButton;Button2:TButton;procedureButton1Click(Sender:TObject);procedureButton2Click(Sender:TObject);private{Privatedeclarations}public{Publicdeclarations}end;varForm1:TForm1;unit单元的接口部分Uses语句告诉程序最终的执行代码中需要哪个函数和过程。Delphi会自动把一些必须的单元包括进来,例如本程序的Windows,Messages,SysUtils。对于程序员自己编写的单元,如果程序中使用了该单元的函数或代码,则需要将其加在uses部分中。Type这部分用来给编程人员定义自己的类型。此处定义了一个从Tform派生出来的TForm1类,它包含二个edit、二个label和二个button对象,还包括二个处理按钮单击事件的过程。注意:在interface区列出了过程和函数和调用格式即说明格式,而它们的实现部分(代码)则位于单元的实现部分(implementation)区。Var这部分用来定义变量和对象部分。在这部分定义的变量不仅可在本单元中使用,而且是可供其他单元引用公共变量。\nunit单元的实现部分实现部分implementation中包含interface中说明的过程、函数、事件处理过程的具体实现程序代码。这一部分可以有自己的额外说明,但这些说明是私有的,外部程序不能调用这些说明。在interface中说明的函数实体必须在implementation部分出现,可以使用标题简写:只输入procedure或function保留字,后面跟过程或函数的名称即可,其后则是程序的实现部分了。实际上,这部分也可以定义变量、过程、函数等,但只能被本单元局部访问;也可以在这部分增加一个uses语句来访问其他单元。“实现部分”顾名思义就是代码的实现,程序员编写的事件处理程序、过程和函数的源代码都在该区中。\nimplementation{$R*.dfm}procedureTForm1.Button1Click(Sender:TObject);vargrade:integer;begingrade:=strtoint(edit1.Text);if(grade>=85)and(grade<=100)thenedit2.Text:=‘优秀'elseif(grade>=60)thenedit2.Text:=‘通过'elseif(grade>=0)thenedit2.Text:=‘不通过'elseedit2.Text:=‘成绩有误';end;procedureTForm1.Button2Click(Sender:TObject);beginclose;end;unit单元的实现部分\nunit单元的初始化部分初始化当前单元所使用的数据,或是通过interface部分将数据提供给其他应用程序、库单元使用时,可以在单元中加入一个initialization部分。当一个应用程序使用一个unit单元时,unit单元中的initialization部分会先于其他的代码执行。如果一个应用程序使用了多个unit单元,则每一个unit单元的初始化部分都会在所有的程序代码前执行。这部分是可选的。unit单元的结束部分应用程序结束时,如果需要单元完成一些后处理工作,如释放Initialization区中分配的资源等,就需要再增加一个finalization区,把执行扫尾工作的代码放进去。应用程序结束时,用与初始化相反的顺序依次执行各单元的finalization区。这部分是也可选的。\n2.8异常与异常处理在应用程序开发中如何检测、处理程序的运行错误是一个很重要的问题。在Delphi的集成开发环境中提供了一个完善的内置调试器,可以帮助程序员发现大部分程序错误。但并不是所有的错误都可以被发现,而且当程序涉及到与外设的数据交换或操作外设,如要求用户输入、读写磁盘等时,错误的发生是程序无法控制的,如输入非法字符、磁盘不能读写等。这些情况不仅会导致应用程序异常终止而且可能引起系统的崩溃。针对这些问题,Delphi同时提供了一套强大的异常处理机制。巧妙地利用它,可以使程序更为强健,使用更为友好。Delphi异常处理机制建立在保护块(ProtectedBlocks)的概念上。所谓保护块是用保留字try和end封装的一段代码。保护块的作用是当应用程序发生错误时自动创建一个相应的异常类(Exception)。程序可以捕获并处理这个异常类,以确保程序的正常结束以及资源的释放和数据不受破坏。2.8.1Delphi异常处理机制与异常类\n异常实际上是一些对象,可以是任何类的一个实例。但是通常是用户自己定义的一个从Exception类派生出的异常类,定义方法与普通类的定义方法基本一致。Exception类是在SysUtils单元中定义的。如果一个程序的uses语句中包含了SysUtils单元,发生运行错误时就会抛出异常。可以利用类的继承性将一组异常组合成一个系列。使用raise语句可调用一个异常类的构造函数,并抛出一个异常。通常,raise语句的形式如下:raiseobjectataddress其中object和ataddress是可选项,address通常是一个指向过程或函数的指针。一个抛出的异常在处理过后自动地被删除,一般不去主动地删除一个异常对象。\n2.8.2异常处理结构1、Try…Excepttry…except结构用于捕获异常,然后有选择地对捕获到的异常进行“处理”,try…except结构将释放异常对象实例,并继续正常的程序处理。Try…except结构有一个可选的扩展语法,它允许用户判断所发生的异常的类型。这个可选的语法形式为on…do。try{…}exceptonErrorclass1do…;onErrorclass2do…;……else{otherhandle…};end;\n假设整型变量ResultNum的范围在0~100之间。如果小于0,则抛出一个EResultTooSmall错误;如果大于100,则抛出一个EResultTooBig错误。programProject1;{$APPTYPECONSOLE}usesSysUtils;typeEResultTooBig=class(Exception)//异常类1Num:Integer;constructorCreate(N:Integer);//异常类1的构造函数end;EResultTooSmall=class(Exception)//异常类2Num:Integer;end;constructorEResultTooBig.Create(N:Integer);beginNum:=N;end;1、Raise和Try…Except\nvarResultNum:Integer;beginResultNum:=-2;try//尝试运行ifResultNum>=100then//如果数据太大,抛出异常raiseEResultTooBig.Create(ResultNum)elseifResultNum<=-1then//如果数据太小,抛出异常raiseEResultTooSmall.CreateFmt('数据不可以小于0。',[]);exceptonEResultTooBigdoWriteln('错误:返回值不可以大于100。');onEResultTooSmalldoWriteln('错误:返回值不可以小于0。');elseWriteln('错误:其它运行时错误。');//其他异常end;Readln;end.\n2.8.2异常处理结构2、Try…FinallyTry…Finally用于在全局的异常处理程序或下一级的错误检查处理异常前,执行一些清除操作。Try…Finally结构并不释放异常对象示例,因此并不处理错误。例如,如果使用完文件之后,不管是否出现了异常,都需要打开已经打开了的文件。这时,就要以把关闭文件的过程放在Try…Finally语句的Finally部分,不管try部分的操作是否正常,都要进行finally部分的操作。TryStatementlist1finallyStatementlist2End;\n这个练习,将做一个简单计算器并有一些实用功能,它们包括:(1)能够自动判断输入字符是不是合法的数字字符,如果不是,将中止运行,并给出提示信息;(2)能够判断用户是否选择了某个运算符,如果没有,则中止程序,并给出提示信息。(3)如果两个数无法除尽时,将给出所得的余数,这个功能是可选的。使用CheckBox组件。例2.8简单计算器,用于异常处理练习\n例2.8procedureTForm1.BitBtn1Click(Sender:TObject);varx,y,z:integer;begintryx:=strtoint(N1.text);y:=strtoint(N2.Text);exceptmessagedlg(‘输入有误!',mtwarning,[mbok],0);exit;end;caserg1.ItemIndexof-1:beginmessagedlg(‘请选择运算符!',mterror,[mbOK],0);exit;end;0:z:=x+y;1:z:=x-y;2:z:=x*y;3:beginify=0thenbeginshowmessage('除数不能为0!');N3.text:='';exit;end;z:=xdivy;end;end;//caseN3.Text:=inttostr(z);if((cb2.checked=true)and(rg1.itemindex=3)and(xmody<>0))thenN3.Text:=N3.Text+‘余'+inttostr(xmody);end;tryx:=strtoint(N1.text);y:=strtoint(N2.Text);exceptmessagedlg('输入有误!',mtwarning,[mbok],0);exit;end;(1)正常执行部分(2)异常执行部分函数:显示一个提示对话框showmessage('除数不能为0!');\n2.9程序调试简介Delphi提供了一个功能强大的内置调试器(IntegratedDebugger),因而对程序的调试不用离开集成开发环境(IDE)就可以进行。程序错误基本可以分为:(1)语法错误:编译器可以检查出来的错误。(2)运行错误:在执行具体代码时才会出现的错误,如除数为0等。(3)逻辑错误:设计错误。在程序开发过程中程序编码和调试是一个持续的循环过程,只有在你对程序进行了彻底的测试后才能交付最终用户使用。为了保证调试的彻底性,在调试前应制定一个详细的调试计划。一般说来应该把程序划分为几个相对独立的部分,分别进行调试,以利于错误的迅速定位,确保每一部分程序都按设计的要求运行。在程序调试过程中,程序的执行完全在你的控制之中。你可以在任何位置暂停程序的执行去检查变量和数据结构的值,去显示函数调用序列,去修改程序中变量的值以便观察不同值对程序行为的影响。\n为了便于调试,系统提供了两种程序运行控制方式:设置断点和单步执行2.9.1程序运行的控制(1)设置断点设置断点首先在CodeEditor中选定你想设置断点的代码行,而后进行如下的任一种操作:●单击选定代码行左边的空白●按F5●选择CodeEditor快捷菜单的Debug|ToggleBreakPoint项断点必须位于可执行代码行上,凡设置在注释、空白行、变量说明上的都是无效的。另外,断点既可以在设计状态下设置也可以在运行调试状态下设置。通过合理布置屏幕显示,使应用程序运行窗口和CodeEditor(代码编辑器)互不重叠,可以让用户在它们间方便地切换以观察代码执行的效果。\n2.9.1程序运行的控制(2)单步执行单步执行可以控制程序逐条语句执行,每执行完一条语句,程序都会停下来,等待用户发出执行下一条语句的命令。在程序暂停期间,程序员可以分析程序执行的情况。①“Traceinto”按钮:每按一次按钮,程序执行一条语句。当遇到一条调用子程序的语句时,系统会跟踪到子程序内部,在子程序中也是采用逐条语句执行方式,当从子程序返回到调用程序后,仍保持单步执行状态。②“Stepover”按钮:它与“Traceinto”按钮的区别在于:当遇到一条调用子程序的语句时,并不进入到子程序内部去跟踪,而是把它当成是一条普通语句一样,接着就执行调用语句的下一条语句。\n2.9.2查看变量的当前值(1)利用LocalVariables窗口View|DebugWingdow|LocalVariables窗口,会显示出各变量的当前值。(2)利用自动查看功能当一个已执行的程序暂停时,只要将mouse放在代码编辑器窗口中的变量名、对象属性名、参数名及表达式上,就会出一个显示框,显示它们的当前值。\n实习3:1.简单密码校验,用于过程与函数的练习。2.简单计算器(二),用于异常处理练习。3.熟悉程序调试的简单方法:设置断点、单步执行,及变量等当前值的查看方法。DelphiObjectPascal语言基础(二)例2.7例2.8\n练习2:第二章习题4~19、21、22、23第三章习题9DelphiObjectPascal语言基础\n课堂练习:1.计算表达式的值:(第二章习题7)(1)(5+8*2)mod4(2)3*6+23div5(3)5>3AndNot3=3(4)'Windows'+'2000'+'NT5'Delphi\n课堂练习:2.计算下列函数的值:(第二章习题8)(1)Int(Abs(-16.8))(2)FloatToStr(-268.98)(3)Length(‘jiayin’)3.第二章习题23(可用控制台程序实现)设水仙花数是一个三位整数,每一位的立方之和恰好等于此数本身,求水仙花数。Delphi\n第二章习题23programProject1;{$APPTYPECONSOLE}//usessysutils;vara,b,c,m:integer;begin//功能代码end.\n第二章习题24硬币问题:由5分、2分、1分的硬币共50枚组成1元钱,问5分、2分、1分的硬币各多少枚?(列出所有组成方式)