Delphi 学习笔记卢炽光 20100715

http://ce.sysu.edu.cn/hope2008/worklist/ShowArticle.asp?ArticleID=8631(转)

 

仅以我有限的项目经验总结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

C#

初始化变量

arrName:=TStringList.Create;

ArrayList arrName = new ArrayList();

带参数的初始化

win := TEditForm.Create(self);

UserData data = new UserData("OO");

释放资源

arrName.Free;  必须

arrName.Dispose();  不必

由于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)

这套控件非常强大,当然使用起来也不容易。每个控件基本有普通和数据库两种版本,普通的就手动指定值,数据库的就绑定到数据源的字段。需要认真学习这套控件的使用。

原文地址:https://www.cnblogs.com/anbylau2130/p/2807893.html