Delphi语言参考指南(1)语言概览

Delphi Version 11.3

From RAD Studio

Delphi 语言参考指南 是同名原始Delphi7手册的修订和更新版本。


Delphi 是一种高级、编译、强类型语言,支持结构化和面向对象设计。基于 Delphi编程,其优点包括易于阅读的代码、快速编译以及使用多个单元文件进行模块化编程。Delphi 具有支持RAD Studio组件框架和环境的专属功能。在大多数情况下,本语言指南中的描述和示例假定您正在使用 Embarcadero 开发工具。

大多数使用Embarcadero软件开发工具的开发人员在集成开发环境(IDE)中编写和编译代码。Embarcadero开发工具处理设置项目和源文件的许多细节,例如维护单元之间的依赖信息。该产品还对程序组织施加了严格来说不是Delphi 语言规范一部分的约束。例如,Embarcadero 开发工具强制实施某些文件和程序命名约定,如果在 IDE 外部编写程序并从命令提示符编译它们,则可以避免这些约定。

本语言指南通常假定您正在使用 IDE,并且正在构建使用可视组件库 (VCL) 的应用程序。然而,有时Delphi 特定的规则与适用于所有Delphi 编程的规则是有区别的。

本节涵盖以下主题:

  • 程序组织。介绍允许您将应用程序划分为单元和命名空间(units and namespaces)的基本语言功能。
  • 示例程序。显示了控制台和 GUI 应用程序的小示例,以及有关从命令行运行编译器的基本说明。

0.IDE 安装

2023年4月26日版本信息可参考:

https://blogs.embarcadero.com/delphi-11-and-cbuilder-11-community-editions-released/
https://blogs.embarcadero.com/new-rad-studio-11-3-inline-build/

社区版注册后免费,KeyPatch可参考:

https://www.2ccc.com/

Delphi有桌面开发的开源替代品,所以如果是为了开发桌面APP可以完全放心去学习 Delphi:

1.程序组织

Delphi程序通常由多个为称为单元Unit 的源代码模块构成。大多数程序都以 program 标题开头,该标题指定程序的名称。program 标题后跟一个可选的uses 子句,然后是一个声明和语句块。uses 子句列出了链接到 program 的 units ;这些 units 可以由不同的program共享,通常有自己的uses 子句。

uses 子句为编译器提供有关模块之间依赖关系的信息。由于此信息存储在模块本身中,因此大多数 Delphi 语言程序不需要 makefile、头文件或预处理器“include”指令。

1.1Delphi 源文件

编译器预期在三种文件中找到 Delphi 源代码:

  • unit源文件(以 .pas 扩展名结尾)
  • 项目文件(以 .dpr 扩展名结尾)
  • package源文件(以 .dpk 扩展名结尾)

unit 源文件通常包含应用程序中的大部分代码。每个应用程序都有一个项目文件和多个unit文件;项目文件对应于传统Pascal中的program文件,将unit文件组织到应用程序中。Embarcadero开发工具自动为每个应用程序维护一个项目文件。

如果要从命令行编译程序,则可以将所有源代码放入单元 (.pas) 文件中。如果使用 IDE 生成应用程序,它将生成一个项目 (.dpr) 文件。

package源文件类似于项目文件,但它们用于构造称为package的特殊动态可链接库。

1.2用于构建应用的其他文件

除了源代码模块,Embarcadero产品还使用几个非Pascal文件来构建应用程序。这些文件由 IDE 自动维护,包括

  • VCL form 文件(在 Win32 上具有 .dfm 扩展名)
  • 资源文件(以 .res 结尾)
  • 项目选项文件(以 .dof 结尾)

VCL form文件包含窗体的属性及其拥有的组件的说明。每个窗体文件表示单个窗体,该窗体通常对应于应用程序中的窗口或对话框。IDE 允许您以文本形式查看和编辑form文件,并将form文件另存为文本(一种非常适合版本控制的格式)或二进制文件。尽管默认行为是将表单文件另存为文本,但通常不会手动编辑它们,使用Embarcadero的视觉设计工具更为常见。每个项目至少有一个form,每个form都有一个关联的unit (.pas) 文件,默认情况下,该文件与form文件具有相同的名称。

除了 VCL 样式文件之外,每个项目还使用资源 (.res) 文件来保存应用程序的图标和其他资源(如字符串)。默认情况下,此文件与项目 (.dpr) 文件同名。

项目选项 (.dof) 文件包含编译器和链接器设置、搜索路径信息、版本信息等。每个项目都有一个与项目 (.dpr) 文件同名的关联项目选项文件。通常,此文件中的选项是从“项目选项”对话框中设置的。

IDE 中的各种工具将数据存储在其他类型的文件中。桌面设置 (.dsk) 文件包含有关窗口排列和其他配置选项的信息;桌面设置可以是特定于项目的,也可以是环境范围的。这些文件对编译没有直接影响。

1.3编译器生成的文件

首次生成应用程序或包时,编译器会为项目中使用的每个新unit生成一个已编译的unit文件(Win32 上的 .dcu);然后链接项目中的所有 .dcu 文件以创建单个可执行文件或共享包。首次生成包时,编译器会为包中包含的每个新unit生成一个文件,然后创建 .dcp 和包文件。如果使用 GD 编译器开关,链接器将生成映射文件和 .drc 文件;包含字符串资源的 .drc 文件可以编译为资源文件。

生成项目时,除非自上次编译以来其源 (.pas) 文件已更改,找不到其 .dcu/.dpu 文件,显式告诉编译器重新处理它们,或者单元的接口依赖于已更改的另一个单元,否则不会重新编译单个单元。事实上,unit的源文件根本不需要存在,只要编译器可以找到已编译的unit文件,并且该unit不依赖于其他已更改的unit。

2.示例程序

下面的示例说明了 Delphi 编程的基本功能。这些示例显示了通常不会从 IDE 编译的简单应用程序;您可以从命令行编译它们。

2.1简单的命令行程序

下面的程序是一个简单的控制台应用程序,您可以从命令提示符编译和运行:

 program Greeting;

 {$APPTYPE CONSOLE}

 var
   MyMessage: string;

 begin
   MyMessage := 'Hello world!你好世界!';
   Writeln(MyMessage);
 end.

第一行声明一个名为 Greeting 的程序。{$APPTYPE CONSOLE} 指令告诉编译器这是一个控制台应用程序,要从命令行运行。下一行声明一个名为 MyMessage 的变量,该变量包含字符串。(Delphi 具有真正的字符串数据类型。然后,程序将字符串“Hello world!你好世界!”分配给变量MyMessage,并使用Writeln过程将MyMessage的内容发送到标准输出。(Writeln 在系统单元中隐式定义,编译器会自动将其包含在每个应用程序中。

您可以将此程序键入名为 greeting.pas 或 greeting.dpr 的文件中,并通过输入以下内容对其进行编译:

DCC32 greeting

以生成 Win32 可执行文件。

(社区版 Delphi11.3 不支持命令行编译)

生成的可执行文件打印消息: Hello world!你好世界!

除了简单之外,此示例在几个重要方面与您可能使用 Embarcadero 开发工具编写的程序不同。首先,它是一个控制台应用程序。Embarcadero开发工具最常用于编写具有图形界面的应用程序;因此,您通常不会调用 Writeln。此外,整个示例程序(除了 Writeln)都在一个文件中。在典型的 GUI 应用程序中,示例第一行标题的程序将放置在单独的项目文件中,该文件不包含任何实际的应用程序逻辑,除了对单元文件中定义的例程的几次调用。

2.2更复杂的例子

下一个示例显示一个分为两个文件的程序:项目文件和单元文件。可以另存为 greeting.dpr 的项目文件如下所示:

program Greeting;

 {$APPTYPE CONSOLE}

 uses
   Unit1;

 begin
   PrintMessage('Hello World!你好世界');
 end.

第一行声明一个名为Greeting 的程序,该程序又是一个控制台应用程序。使用Unit1;子句告诉编译器程序问候语依赖于名为 Unit1 的单元。最后,程序调用 PrintMessage 过程,将字符串 Hello World!打印消息过程在Unit 1 中定义。以下是Unit1的源代码,必须保存在名为Unit1.pas的文件中:

unit Unit1;

interface

procedure PrintMessage(msg: string);

 implementation

 procedure PrintMessage(msg: string);
 begin
    Writeln(msg);
 end;

 end.

Unit1 定义了一个名为 PrintMessage 的过程procedure,该过程将单个字符串作为参数,并将字符串发送到标准输出。(在 Delphi 中,不返回值的例程称为过程procedure。返回值的例程称为函数functions。)

请注意,PrintMessage 在 Unit1 中声明了两次。保留字 interface下的第一个声明使 PrintMessage 可用于使用 Unit1 的其他模块(如问候语)。第二个声明,在保留字implementation下,实际上定义了 PrintMessage。

您现在可以从命令行编译问候语,方法是输入

dcc32 greeting

以生成 Win32 可执行文件。

无需包含 Unit1 作为命令行参数。当编译器处理 greeting.dpr 时,它会自动查找geeting程序所依赖的单元文件。生成的可执行文件执行与我们的第一个示例相同的操作:它打印消息: Hello world!你好世界!

2.3一个 VCL 应用(源码示例)

下一个示例是使用 IDE 中的可视组件库 (VCL) 组件生成的应用程序。此程序使用自动生成的表单和资源文件,因此您无法仅从源代码编译它。但它说明了Delphi 语言的重要特征。除了多个单元之外,该程序还使用类和对象。

该程序包括一个项目文件和两个新的单元文件。项目文件:

program Greeting;

 uses
   Forms, Unit1, Unit2;

 {$R *.res} { This directive links the project's resource file. }

 begin
    { Calls to global Application instance }
    Application.Initialize;
    Application.CreateForm(TForm1, Form1);
    Application.CreateForm(TForm2, Form2);
    Application.Run;
 end.

我们的程序被称为greeting。它使用三个units:Froms,它是VCL的一部分;Unit1,与应用程序的主窗体 (Form1) 相关联;和Unit 2,它与另一个表单 (Form2) 相关联。

该程序对名为 Application 的对象进行一系列调用,该对象是在 Forms 单元中定义的 Vcl.Forms.TApplication 类的实例。(每个项目都有一个自动生成的应用程序对象。其中两个调用调用名为 CreateForm 的 Vcl.Forms.TApplication 方法。对 CreateForm 的第一次调用将创建 Form1,它是在 Unit1 中定义的 TForm1 类的实例。对 CreateForm 的第二次调用创建 Form2,这是在 Unit2 中定义的 TForm2 类的实例。

Unit1 看起来像这样:

unit Unit1;

 interface

 uses SysUtils, Types, Classes, Graphics, Controls, Forms, Dialogs;

 type
   TForm1 = class(TForm)
     Button1: TButton;
     procedure Button1Click(Sender: TObject);
   end;

 var
   Form1: TForm1;

 implementation

 uses Unit2;

 {$R *.dfm}

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

 end.

Unit1 创建一个名为 TForm1 的类(派生自 Vcl.Forms.TForm)和此类 Form1 的实例。TForm1 类包括一个按钮 – Button1,Vcl.StdCtrls.TButton 的一个实例 – 以及一个名为 Button1Click 的过程,当用户按下 Button1 时调用。Button1Click 隐藏 Form1 并显示 Form2(对 Form2.ShowModal 的调用)。

注意:在前面的示例中,Form2.ShowModal 依赖于使用自动创建的表单。虽然这对于示例代码很好,但强烈建议不要使用自动创建的表单。

Form2 在 Unit2 中定义:

unit Unit2;

 interface

 uses SysUtils, Types, Classes, Graphics, Controls, Forms, Dialogs;

 type
 TForm2 = class(TForm)
   Label1: TLabel;
   CancelButton: TButton;
   procedure CancelButtonClick(Sender: TObject);
 end;

 var
   Form2: TForm2;

 implementation

 uses Unit1;

 {$R *.dfm}

 procedure TForm2.CancelButtonClick(Sender: TObject);
   begin
     Form2.Close;
   end;

 end.

Unit2 创建一个名为 TForm2 的类和该类的一个实例 Form2。TForm2 类包括一个按钮(CancelButton,Vcl.StdCtrls.TButton 的实例)和一个标签(Label1,Vcl.StdCtrls.TLabel 的实例)。您无法从源代码中看到这一点,但 Label1 显示一个标题,上面写着 Hello world!标题在 Form2 的表单文件 Unit2.dfm 中定义。

TForm2 声明并定义了一个方法 CancelButtonClick,每当用户按下 CancelButton 时,就会在运行时调用该方法。此过程(以及 Unit1 的 TForm1.Button1Click)称为事件处理程序,因为它响应程序运行时发生的事件。事件处理程序由 Form1 和 Form2 的窗体文件分配给特定事件。

当问候语程序启动时,将显示 Form1,而 Form2 不可见。(默认情况下,在运行时仅对项目文件中创建的第一个窗体可见。这称为项目的主窗体。当用户按下 Form1 上的按钮时,Form2 将显示 Hello world!问候。当用户按标题栏上的“取消按钮”或“关闭”按钮时,Form2 将关闭。

2.4一个 VCL 应用(实际操作)

  • Delphi创建一个VCL程序,更改项目名字为greeting
  • 文件,新建 Form2
  • 选中Form1,双击TBotton添加组件,双击button1

代码片段:

implementation

{$R *.dfm}

uses unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
  form1.Visible :=False;
  form2.Visible :=True;
end;
  • 选中Form2,双击TBotton添加组件,双击button1
implementation

{$R *.dfm}

uses unit1;
procedure TForm2.Button1Click(Sender: TObject);
begin
form1.Visible :=True;
form2.Visible :=False;
end;

正文完