follow my heart...
分类:
2006-11-17 11:29:13
[单元unit在delphi编程当中用途广泛.你可以定义函数,过程等.单元的出现,便于你组织程序.]
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关键字与类单元的工作空间有关)。一个标识符(如一个变量、过程、函数或数据类型)的工作空间是指能访问标识符的代码段。基本原则是:标识符在它工作空间内才有意义,也就是说,只在其声明的代码块中才有意义,在工作空间外你不能访问这些标识符。例如:
只要程序单元的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子句特别重要,因为需要通过它来管理应用程序的编译和连接。
结束语讨论完Delphi中Pascal 应用程序的结构,本书就翻过了最后一章,至少目前是这样,欢迎来email发表你的意见和要求。