• 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)

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

  • 相关阅读:
    sqlzoo练习答案--SUM and COUNT
    响应式的嵌入内容和图片
    缓存server设计与实现(五)
    编译器DIY——读文件
    [Leetcode]-Pascal&#39;s Triangle
    zoj 1562 反素数 附上个人对反素数性质的证明
    [POJ 1236][IOI 1996]Network of Schools
    POJ 3691 DNA repair [AC自动机 DP]
    POJ 1625 Censored! [AC自动机 高精度]
    51Nod 1225 余数之和 [整除分块]
  • 原文地址:https://www.cnblogs.com/anbylau2130/p/2807893.html
Copyright © 2020-2023  润新知