因此,当您双击按钮并自动完成按钮单击过程时,我很好奇编译器如何知道该函数链接到哪个按钮。例如,它会使
TForm1.Button1Click(Sender: TObject);
那么编译器如何知道链接的是哪个按钮呢?它只是解析过程名称来查看它是什么按钮吗?
您可以将方法命名为任何名称,Delphi 不会解析或使用方法名称来标识关联的组件或事件。
如果您在设计时执行此操作,则事件与事件处理程序的关联将存储在 DFM 文件中,您可以在其中找到类似以下内容:
object Button1: TButton
Left = 104
Top = 64
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
OnClick = Button1Click
使您的程序在创建表单时,在运行时将方法(也称为事件处理程序)与对象的事件(一种特殊类型的属性)相关联。
您还可以在运行时将事件关联到任何兼容方法,例如使用以下代码:
type
TForm1 = class(TForm)
Button1: TButton;
private
procedure MyClick(Sender: TObject);
procedure MyOtherClick(Sender: TObject);
....
procedure TForm1.AssociateClickHandler;
begin
Button1.OnClick := MyClick;
end;
procedure TForm1.MyClick(Sender: TObject);
begin
Button1.OnClick := MyOtherClick; //from now, the other method with handle the event.
end;
在设计时,您可以直接在ObjectInspector中编写您想要的事件处理程序的名称,然后按Enter键,Delphi将为您创建具有该名称的方法。 如果您不提供名称,Delphi 将使用组件名称以及不带“On”的事件名称自动生成方法名称。 如果该方法已经存在,IDE 只会将该事件与该方法关联起来。
写下所需的方法名称:
按回车键:
您可以将同一方法关联到同一对象的不同事件,或者关联到不同对象的同一事件。
例如,您可以将上面显示的 MyOwnMethodName 与任意数量的按钮的 OnClick 相关联。通常,Sender 参数包含对触发事件的对象的引用。
编译器不参与任何这一切。 IDE 正在处理所有事情。
当您在设计时双击控件时,表单设计器知道正在单击哪个控件,因为它是内存中的活动对象。
表单设计器使用控件的 RTTI 和注册的
TComponentEditor
实现(如果未注册用户定义的实现,VCL 提供默认实现)来确定该类类型的哪个事件是默认事件(在 TButton
的情况下)
,即 OnClick
事件),然后使用 RTTI 检查该事件是否已分配有处理程序。
如果尚未分配处理程序,表单设计器将使用 RTTI 读取控件的
Name
属性和事件的声明名称,将它们连接在一起(删除事件名称的 On
部分),并查找过程控件的源代码中的该名称 Owner
。 如果找不到该过程,则会在那时创建它。
表单设计器找到该过程后,它会使用 RTTI 来验证该过程是否与事件签名匹配,然后根据需要将该过程分配为新的事件处理程序,然后最终跳转到代码编辑器中的过程实现。
如果您在对象检查器中单击控件的事件并重命名处理程序,源代码中的相应过程将被重命名以匹配新名称,并且链接到同一过程的任何其他事件(甚至在其他组件中)也将被重命名。通过 RTTI 进行更新以匹配新名称。
编译项目时,IDE 首先利用 RTTI 和注册的组件流例程来创建包含所有各种组件属性/事件值的 .DFM 文件。 然后它调用编译器,编译源代码并将 .DFM 文件作为二进制资源链接到最终的可执行文件中。
在运行时,RTL 使用 RTTI 和注册的自定义组件流例程来解析 DFM 资源,以定位各种组件并根据需要连接其属性/事件值。