在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
仅以我有限的项目经验总结Delphi学习中需要注意到问题。由于我有C#基础,故此会涉及C#和Pascal语法不同之处,通用的程序套路就不多说了。该文章涉及内容深度较浅,适合初学者阅读。如有错漏请包涵。 需要注意Delphi是一个IDE,它不是一个语言,它的性质和Visual Studio、Eclipse是一样的,是用来做开发的。Delphi是用Pascal做为开发语言,确切说是Object Pascal--支持面向对象的Pascal语言,当然Delphi可以用C++做开发,名字就换成了C++ Builder。无论用哪个语言,Delphi和C++ Builder提供的开发接口基本一致。 一、语法 1.变量定义 在Pascal语法中,变量必须先定义再使用,而且变量必须定义在类定义中或过程/函数体的var变量下。不允许变量定义在执行语句之间,这在程序设计时有好有坏。好在定义清晰,产看类定义和var就可以知道有多少变量,什么变量;不好在撰写程序时不方便。 变量定义举例如下: type TUltiBase = class(TObject) public ... private AVariable:String; BVariable:Integer; procedure GetAVariable(); end; ... procedure TUltiBase .GetAVariable(); var A:String; B:Integer; begin ... end;
2.变量赋值 变量赋值使用:=运算符,初学者看来这个比较特别的,必须与=区分开。 在C#中,空类型使用null,在Pascal中使用nil。 注意,Pascal中不使用双引号,字符串是通过单引号括起来。 3.变量初始化和释放 用Delphi编写C/S程序册时候必须注意,大部分的控件或类型需要初始化和释放。如 procedure HandleDelete; var arrName:TStringList; begin arrName:=TStringList.Create; ... arrName.Free; end; 使用类型的Create构造函数初始化变量。类似于C#的 ArrayList arrName = new ArrayList(); 但是C#有自动回收资源机制,所以一般情况下不需要释放资源,当然也可以手动释放 arrName.Dispose(); 也可以通过 using(arrName){ ... } 自动让系统使用完后自动释放 比较Pascal和C#初始化变量,做个列表会更清晰:
由于Pascal变量初始化后必须释放,而且为了避免中间出错,会形成这样一种结构: CommentForm:= TCommentForm.Create(Self,humanID,commentID); try CommentForm.ShowModal; finally CommentForm.Free; end; 4.运算符及变量比较 l 赋值 := l 比较相等 = l 比较不等于 <> l 比较大于 > l 比较小于 < l 逻辑与 and l 逻辑或 or l 逻辑非 not 需要说明:尽量在比较表达式外加括号(),以使条件表达更清晰 5.流程控制 a) IF Then Else End 需要说明:if、then 和end缺一不可。类似于C#的if、{ 和 }。 if (condition) then begin ... end else if (condition2) then begin ... end else ... end; b) While Do while (condition) do begin ... end; c) Repeat Until repeat ... until (condition) d) Case Of case index of 0: Result:= "AAAA"; 1: Result:= "BBBB"; else raise Exception.Create('超出索引'); end; 6.属性 属性的使用需要2~3部分:私有变量、写过程和属性定义。 type TUnitManager = class(TObject) private FYunmenHR:TYunmenHR; procedure SetYunmenHR(value:TYunmenHR); property YunmenHR: TYunmenHR read FYunmenHR write SetYunmenHR; end; ... procedure TUnitManager.SetYunmenHR(value:TYunmenHR); begin FYunmenHR:=value; end; ... property 属性名:属性类型 read 私有变量 write 写过程 如果需要只读或只写的属性,保留read 或write 即可。 7.函数 注意Pascal中的函数是function,具有返回值的。procedure不同,没有返回值。然而在C#中,过程procedure和函数function都是方法method,没有返回值则使用void,有返回值直接使用返回类型即可。 function GetItem(Index: Integer): TYunmenBase; ... function TUnitManager.GetItem(Index: Integer): TYunmenBase; begin case index of 0: Result:= YunmenHR; else raise Exception.Create('超出索引'); end; end; function 函数名(参数定义):返回类型 返回值通过跟函数同名的变量或Result来传递如: Result:= YunmenHR; 或者 GetItem:= YunmenHR; 8.过程 又称作过程,没有返回值。 procedure SetYunmenHR(value:TYunmenHR); ... procedure TUnitManager.SetYunmenHR(value:TYunmenHR); begin FYunmenHR:=value; end; procedure 过程名(参数体); 过程定义时如果没有参数,则可省略括号(),调用的时候也可以省略括号。如 procedure HandleDelete(); procedure HandleGet; ... procedure TUnitManager.HandleDelete(); begin ... end; procedure TUnitManager.HandleGet; begin ... end; 9.委托 Delphi的控件提供了很多事件,这些事件是通过委托实现的。如按钮的OnClick事件是定义在系统的按钮类中的一个委托过程。提供了参数和返回类型,其动作是预先定制好的。事件带来了很多好处,而且使用起来非常方便: procedure Act_SaveExecute(Sender: TObject); procedure TMainFrm.Act_SaveExecute(Sender: TObject); begin ... end; 调用起来很方便 Act_Save.OnClick = Act_AddPictureExecute; 在Delphi中动态绑定事件十分常见。 10.异常处理 跟C#类似,可以使用try捕获异常,但捕获异常的关键字和语法有些区别: try ... except on E: Exception do begin ... end end; 不允许使用try except finally end;的语法,而必须通过嵌套实现如: try try ... except on E: Exception do begin ... end end; finally ... end; 二、OO特性 跟其他语言类似,只能继承一个类,但可以继承多个接口。但是delphi中没有抽象类,只能够采取折中方案,在类中声明虚拟的抽象过程/函数。 type TYunmenBase = class(TObject) public procedure AddObject;virtual;abstract; procedure DeleteObject(ID:Integer);virtual;abstract; procedure RefreshGridData;virtual; end; AddObject和DeleteObject都是抽象过程,通过关键字abstract标识,而且是虚拟的virtual,允许继承类复写。过程RefreshGridData不是抽象过程,但允许在继承类中复写。 type TYunmenHR = class(TYunmenBase) public procedure AddObject;override; procedure DeleteObject(ID:Integer);override; procedure RefreshGridData;override; end; TYunmenHR 继承类TYunmenBase,复写过程AddObject、DeleteObject和RefreshGridData,通过关键字override标识。 实现了类继承和过程复写后,就可以实现OO中的多态。 type TYunmenBase = class(TObject) public procedure AddObject;virtual;abstract; procedure DeleteObject(ID:Integer);virtual;abstract; end;
type TYunmenHR = class(TYunmenBase) public procedure AddObject;override; procedure DeleteObject(ID:Integer);override; end;
type TYunmenEdu = class(TYunmenBase) public procedure AddObject;override; procedure DeleteObject(ID:Integer);override; end;
type TYunmenEvent = class(TYunmenBase) public procedure AddObject;override; procedure DeleteObject(ID:Integer);override; end; 实现多态: function GetItem(Index: Integer): TYunmenBase; property Item[Index: Integer]: TYunmenBase read GetItem; ... function TUnitManager.GetItem(Index: Integer): TYunmenBase; begin case index of 0: Result:= YunmenHR; 1: Result:= YunmenEdu; 2: Result:= YunmenEvent; else raise Exception.Create('超出索引'); end; end; 使用TUnitManager的时候只需要使用不同索引Item即可访问不同的继承类。 var util:TUnitManager; begin util:=TUnitManager.Create; util.Item[0].AddObject; util.Item[1].DeleteObject(1); util.Free; end; 三、常用过程/函数 1.字符串操作 a) Trim、 TrimLeft 和 TrimRight Delphi中没有类似C#的 string s = " More important than what is when. "; string s2 = s.Trim(); // s2 : "More important than what is when." 这种直接在字符串后使用Trim()或其他函数的功能。 不过它提供Trim的全局过程: string s := " More important than what is when. "; string s2 := Trim(s); // s2 : "More important than what is when." Trim()是去除字符串前后的空格和不可见字符,同理TrimLeft()是去除字符串左边的空格和不可见字符,TrimRight()去除字符串右边的空格和不可见字符。 b) Pos/PosEx function Pos(Substr: string; S: string): Integer; 返回字符串S中子字符串Substr的索引,如果没找到,则返回0。 var S: string; begin S := ' 123.5'; { Convert spaces to zeros } while Pos(' ', S) > 0 do S[Pos(' ', S)] := '0'; end; function PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer; 从指定位置Offset开始,返回字符串S中子字符串Substr的索引,如果没找到,则返回0。如果开始位置是1,则功能和Pos一样。 c) Copy function Copy(S; Index, Count: Integer): string; function Copy(S; Index, Count: Integer): array; 从指定位置Index开始,返回字符串S中Count个字符。 d) Delete procedure Delete(var S: string; Index, Count:Integer); 从指定位置Index开始删除字符串S中的Count个字符。 var s: string; begin s := 'Honest Abe Lincoln'; Delete(s,8,4); { 'Honest Lincoln' } end; e) UpperCase 和 LowerCase function UpperCase(const S: string): string; 转换字符串为大写或小写。 var I: Integer; begin for I := 0 to ListBox1.Items.Count -1 do ListBox1.Items[I] := UpperCase(ListBox1.Items[I]); ListBox1.Items[I] := LowerCase(ListBox1.Items[I]); end; 2.类型转换 a) StrToInt 和 StrToIntDef function StrToInt(const S: string): Integer; 将字符出转换为数字,如果转换失败,则抛出EConvertError 异常。 function StrToIntDef(const S: string; const Default: Integer): Integer; 带默认值的StrToInt ,如果转化失败,则返回默认值 b) StrToBool 和 StrToBoolDef function StrToBool(const S: string): Boolean; 将字符串转换为布尔值,如果转换失败则抛出EConvertError异常。 function StrToBoolDef(const S: string; const Default: Boolean): Boolean; c) IntToStr function IntToStr(Value: Integer): string; overload; function IntToStr(Value: Int64): string; overload; 将数字转化为字符串。 3.应用程序信息 获取应用程序所在路径:ExtractFilePath(Application.ExeName) 获取应用程序文件名:ExtractFileName(Application.ExeName); 4.全局过程 a) Close、Halt和Application.Terminate都可以退出程序。但有些区别,当Close是一个主窗体时,程序会退出. Close会发生FormClose事件,FormCloseQuery事件. Halt会发生FormDestory事件, Application.Terminate以上三个事件都不会发生。 b) Exit,从当前过程退出。相当于C#的return。 2.控件常用事件 a) OnClick,控件点击事件 b) OnChange,控件的焦点改变事件 c) OnExecute,TAction中的触发事件 d) FormCreate,窗体创建时的事件 e) FormShow,窗体显示时的事件 f) FormClose,窗体关闭时的事件 g) AfterScroll,TADOQuery改变记录行触发的事件 h) OnGetDataText,TcxGridDBColumn显示到屏幕时触发的事件 i) OnPageChange,TPageControl页面切换触发的事件 j) OnKeyUp,键盘释放触发的事件,可用于判断输入的字符 k) OnCellClick,TcxGridDBTableView单元格点击事件 四、软件部署 1.命名 生成的程序以项目名命名。 2.发布位置 项目->选项->目录/条件->输出目录,方便部署软件。 3.软件版本及其详细信息 项目->选项->版本信息,填写软件版本信息 4.软件包 多个项目可以通过软件包管理。当时每个项目仍然对应一个程序。当设定“发布位置”后,所有程序都可以发布到同一个目录下,更便于部署。 5.异常调试 在需要调试的行左边添加断点(或按F5),运行程序(F9),当程序运行到断点时,程序进入中断状态,可使用执行到下一行(F8),跳过当前断点(F9)切换至不同断点或退出调试。调试过程中,按Ctrl+F7进入实时查看变量窗口,输入变量可返回当前值;按Ctrl+F5进入监视窗口,Ctrl+a添加监视点用以监视当前变量的值。 五、第三方控件 1.正则表达式 类:RegExpr.pas 引用:RegExpr 调用 var RegExpr:TRegExpr; FileNameAff:string; begin RegExpr:=TRegExpr.Create; try RegExpr.Expression :='http://www\.(\w*?)\.(.*)'; if RegExpr.Exec(edt_Url.Text) then FileNameAff:= RegExpr.Match[1] else FileNameAff:= 'untitled'; finally FreeAndNil(RegExpr); end; 调用多次: var RegExpr:TRegExpr; Input:string; begin RegExpr:=TRegExpr.Create; Input:=memo1.Text; try RegExpr.Expression :='<option value="(\d{3})" >(.*?)</option>'; RegExpr.Exec(Input); repeat ... until not RegExpr.ExecNext; finally FreeAndNil(RegExpr); end; 2.XML解析 类:MSXML2_TLB.pas 引用:MSXML2_TLB 使用XPATH解析XML,迭代每个节点: var ResponseDomXml : TDOMDocument30; ResponseDomNodeList:IXMLDOMNodeList; strName:string; begin ResponseDomXml := TDOMDocument30.Create(nil); ResponseDomXml.DefaultInterface.async := False; ResponseDomXml.DefaultInterface.setProperty('SelectionLanguage', 'XPath'); ResponseDomXml.DefaultInterface.loadXML(memo1.text); ResponseDomNodeList:=ResponseDomXml.DefaultInterface.documentElement .selectNodes('//FieldInfo'); for i := 0 to ResponseDomNodeList.length-1 do begin strName:= ResponseDomNodeList[i].selectSingleNode('FieldName').text; ... end; ResponseDomXml.Free; end; TDOMDocument30通过DefaultInterface接口对XML访问,进而用selectNodes和selectSingleNode查询指定的节点。 3.图像显示(ImageEn) 将控件拖到窗体,除了可以设置各种属性之外,它可以很方便加载不同类型的图片,包括本地的和远程的。主要使用IO接口: ImageEnView1.IO.LoadFromFile(sFileName); ImageEnView1.IO.LoadFromURL(sUrl); 更多的访问接口请查看TImageEnIO。 4.表单显示(DevExpress) 这套控件非常强大,当然使用起来也不容易。每个控件基本有普通和数据库两种版本,普通的就手动指定值,数据库的就绑定到数据源的字段。需要认真学习这套控件的使用。 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论