Delphi的单元文件详解

来源:互联网 发布:韶关网络问政平台 编辑:程序博客网 时间:2024/04/30 11:27

Delphi的单元文件详解

  Delphi单元文件

1.库单元文件头:其中声明了库单元的名字.
2.Interface部分:
  由保留字interface开始,结束于保留字implementation,它用来声明引用的单元,常量,数据类型,变量,过程和函数.在Interface部分声明的变量,常量,数据类型,过程,函数都可以供外部引用,对整个程序而言是共有的.也就是说,对于所有引用该单元的单元来说,这些声明都是可见和可访问的. 在Interface部分,只需写出过程和函数的首部,具体的定义是在下面的implementation部分给出的.Interface部分又可分为多个可选部分,分别为单元引入部分(uses),常量说明部分,类型说明部分,变量说明部分,过程和函数声明部分.
3.Implementation部分:
  Implementation部分分为两部分.一部分是声明部分,包括单元引用,常量,类型,变量,过程和函数的声明,这一点和Interface部分相似.区别有两点:
  (1):在Implementation部分声明的只对本单元是公共的,可见的,其他单元即使引用了该单元,也不能访问它们.
  (2):在Implementation部分声明的过程和函数,不需要遵循先声明后定义的规则,而可以直接写出过程和函数的定义.另一部分是在Interface部分声明的过程和函数的定义.
4.Initialization部分:
  用于初始化该库单元,此处的代码最先执行.如果多个库单元中包含Initialization部分那么它们的执行顺序就和Program的uses部分引用单元的出现顺序是一致的.
5.Finalization部分:
  通常用于释放Initialization部分分配的资源.如果多个库单元中包含Finalization部分,其执行顺序和Initialization部分正好相反.

unit MainFrm; {库单元文件头}

interface     {接口部分}

uses        
  Windows, Forms, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    procedure MyButtonClick(sender:TObject);
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation  {实现部分}

//uses

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  MyButton : TButton;
begin
  MyButton := TButton.Create(self);
  MyButton.Parent := self;
//告诉创建方法在Form1中显示MyButton
  MyButton.Caption := '测试一';
  MyButton.OnClick := MyButtonClick;
  MyButton.Show;
end;

procedure TForm1.MyButtonClick(sender:TObject);
begin
  Application.MessageBox(PAnsiChar(TButton(sender).Caption)
                        ,'Test Component');
  TButton(sender).Caption := '测试二';
end;

initialization  {可选的初始化部分}
  //
finalization    {结束部分}
  //

end.            {End结束符}

6.Sender参数:
  看上面程序代码发现事件处理程序的参数中,至少含有一个参数Sender,它代表触发事件处理程序的组件,有了Sender参数,可以使多个组件共用相同的事件处理程序.
7.Self参数:
  Self是指所编的程序范围是在哪一个类中,Delphi中大都在窗体范围内编程,因此,Self即指窗体,如果在编写一个类或是一个组件,则Self指该类或该组件.我们在过程和函数的声明中可以看出Self是代表哪个组件,即Self代表"."号之前的组件.另外应注意,Self只能用在类方法中,而不能用在过程或函数中.如下列是错误的:
Function a1(B:Integer):Integer;
begin
...
Button := TButton.Create(self);
...
end;
8.Parent和Owner的区别:
  (1):Parent属性是指组件的包容器,组件只能在此范围内显示和移动.
  (2):Owner属性是指组件的所有者,它负责组件的创建和释放.Create方法应带有表示组件
所有者的参数.
  (3):它们都是运行阶段的属性,只能通过代码设置.

chenju 的图片
chenju 的图片
chenju发表:

Delphi 应用程序中的单元,或说程序模块可谓老道精深。实际上,单元是程序模块化的基础,类是继它之后才有的。在Delphi 应用程序中,每个窗体都有一个相对应的单元。用相应的工具按钮, 或File > New Form 菜单命令,在工程中添加一个新窗体,实际上是增加了一个新单元,也就是建立了该新窗体的类。

单元

虽然所有窗体都在单元中定义,但反之则不然。除窗体外,单元中还可以定义一系列能访问的例程。选择File > New菜单命令,然后在Object Repository的New 页中选择Unit 图标,随即当前工程中就会加入一个空白单元。单元代码分区存放,空白单元的代码如下:

unit Unit1; interface implementation end.

单元的概念比较简单,单元名与文件名相同,而且必须唯一。单元包括界面区(interface)及实现区(implementation),界面区用于声明其它单元能看到的部分;实现区存放界面的实现代码及外部不可见的声明。此外还有两个可选的区,即初始化区及结束区,其中初始化区存放初始化代码,当程序加载到内存时执行;结束区存放程序终止时执行的代码。

单元总体结构如下:

unit unitName; interface // other units we need to refer to uses A, B, C; // exported type definition type newType = TypeDefinition; // exported constants const Zero = 0; // global variables var Total: Integer; // list of exported functions and procedures procedure MyProc; implementation uses D, E; // hidden global variable var PartialTotal: Integer; // all the exported functions must be coded procedure MyProc; begin // ... code of procedure MyProc end; initialization // optional initialization part finalization // optional clean-up code end.

界面区头部的uses子句表示需要访问的外部单元,这些外部单元中定义了你需要引用的数据类型,如自定义窗体内所用的控件。

实现区头部的uses子句用于表示只在实现部分访问的单元。如果例程或方法的代码需要引用其他单元,你应该把这些单元加到实现区子句中,而不是界面区。你所引用的单元必须在工程文件目录中能找到,或在工程选项对话框的 Directories/Conditionals 页设定这些单元的搜索路径。

C++程序员应该知道uses语句和include 指令是不同的。uses语句只是用于输入引用单元的预编译界面部分,引用单元的实现部分在单元编译时才考虑。你引用的单元可以是源代码格式(PAS),也可以是编译格式(DCU),但是必须用同一版本的Delphi进行编译。

在单元的界面区中可以声明许多不同的元素,包括过程、函数、全程变量及数据类型。在Delphi 应用程序中,数据类型可能用得最频繁。每创建一个窗体,Delphi 会在单元中自动建立一个新的数据类型--类(class)。在Delphi 单元中不仅能定义窗体;还能象传统单元一样,只包含过程及函数;还可以定义与窗体和任何可视控件无关的类。

单元的工作空间

Pascal单元是封装性和可视性的关键,它很可能比类中的 private 和 public 关键字还要重要。(实际上,private关键字与类单元的工作空间有关)。一个标识符(如一个变量、过程、函数或数据类型)的工作空间是指能访问标识符的代码段。基本原则是:标识符在它工作空间内才有意义,也就是说,只在其声明的代码块中才有意义,在工作空间外你不能访问这些标识符。例如:

局部变量:如果你在例程或方法代码块内声明一个变量,那么单元外部不能访问这个变量。该标识符的工作空间就是定义标识符的整个例程,其中包括嵌套例程(除非嵌套例程内有一个同名标识符覆盖了外部定义)。当调用到例程时,其变量压入栈内存中,例程一结束,栈中的内存就自动释放。

 

全程隐藏变量:如果你在单元的实现部分声明一个标识符,那么在单元外你不能使用它,但是能在单元内任一代码块及过程中使用它。程序一启动就会为全程隐藏变量分配内存,程序终止内存释放,你可以在单元初始化区给它赋初值。

 

全程变量:如果你在单元的界面部分声明标识符,那么该标识符的工作空间就扩大了,任何Use它的单元都能访问它。这类变量的内存分配及生命周期与上类变量相同,唯一不同的是其可见性。

 

只要程序单元的uses子句中列出某一单元名,那么所列单元界面区中声明的任何标识符该程序都能访问。窗体类的变量就是这样声明的,所以你可以在其他窗体代码中访问这个窗体以及它的公共域、方法、属性和组件。当然把什么都声明为全局标识这种编程习惯并不好。除了明显的内存消耗问题外,使用全程变量使代码维护和更新变得困难。一句话,你应该尽量少用全程变量。

单元用作命名空间

uses 语句是访问其他单元工作空间的标准技术,通过该语句你能访问其它单元的定义内容。如果恰巧两个单元声明的标识符同名,也就是说你可能有两个同名的类或例程,遇到这种情况,你可以用单元名作前缀定义类型或过程名,由此进行区分。例如用Totals.ComputeTotal访问Totals 单元中的ComputeTotal 过程。不过这种情况最好不要经常遇到,因此强烈建议不要在同一程序中用同一名字表示两个不同的东西。

然而,如果查阅VCL库和Windows 文件,你会发现一些Delphi 函数和Delphi 可用的Windows API 函数同名,不过参数往往不同,下面以Beep 过程为例说明这个问题。

新建一个Delphi 程序,添加一个按钮,然后写入以下代码:

procedure TForm1.Button1Click(Sender: TObject); begin Beep; end;

执行程序,单击按钮,你会听到一个短促的声音。现在移到单元的uses语句,把原先的代码:

uses Windows, Messages, SysUtils, Classes, ...

改为下面的样式,只要把SysUtils单元移到Windows之前:

uses SysUtils, Windows, Messages, Classes, ...

现在如果重新编译这段代码,你会得到一个编译错误:”Not enough actual parameters”(实际参数不够)。问题在于Windows 单元定义了另一个带两个参数的Beep 函数。应该说uses子句中第一个单元的定义被后面单元的定义覆盖,解决方法很简单:

procedure TForm1.Button1Click(Sender: TObject); begin SysUtils.Beep; end;

不管uses子句中单元顺序如何排列,以上代码都能编译通过。在Delphi中很少有其他命名冲突的情况,因为Delphi 代码通常放在类的方法中,如果不同类中有两个同名的方法不会产生任何冲突,只是使用全程例程会产生冲突问题。

单元和程序

Delphi 应用程序源代码文件可分成两类,它们是一个或多个单元文件及一个程序文件,单元文件可以看成是次一级的文件,它被应用程序的主体——程序文件——引用。理论上如此,实际上程序文件通常是自动产生的,作用有限,程序启动并运行主窗体时才会用到它。程序文件的代码,或说Delphi 工程文件(DPR),可用手工进行编辑,也可通过工程管理器及其与应用程序、窗体相关的选项进行编辑。

程序文件的结构通常比单元文件的结构简单得多。下面是一个程序文件的源代码:

program Project1; uses Forms, Unit1 in Unit1.PAS?{Form1DateForm}; begin Application.Initialize; Application.CreateForm (TForm1, Form1); Application.Run; end.

从上可见,文件中只有一个uses区和应用程序的主体代码,主体代码包含在begin 和 end 关键字之间。程序的uses子句特别重要,因为需要通过它来管理应用程序的编译和连接。

原创粉丝点击