Button1.OnClick := Form1.Button1Click;

提出问题: 

Form1.Button1Click(form1);
Form1.Button1.Click;

1)这两种调用有什么区别
2)Procedure Button1Click(Sender: TObject); 
这个过程归属于TForm1,还是Button1?


相关原理:

1]{$R *.dfm}是什么?有什么用?
我们从Delphi 的$R编译指示符入手(这一点很重要):

Delphi帮助里的说明

,是指
1)通过$R编译指示符,从外部调入Windows资源文件;
我们这里研究的是由点击Delphi菜单 File->Application,默认生成的空白工程做为试验工程:

Unit1.pas//一开始自动生成的


通过

关于*符号的帮助解释

,我们可以得出:
2)窗口 (.dfm or xfm) 类型文件也可看作一种Windows资源文件,通过{$R *.dfm}导入,它是由Delphi自定义的特殊资源文件,。

为什么要强调这个*符号呢?因为奥秘全隐藏在这个*里。
因为在日常一般计算机操作里,*除了代表乘号外,在Word等文字编辑软件中作为任意个字符的通佩符,就是这种语议,误导了我们:
以为{$R *.dfm}是导入该工程目录下所有的 .dfm。
这样理解是错误的,大错特错的。
在Delphi里,且针对试验工程里,{$R *.dfm} 仅能替换为另外一种形式:{$R Unit1.dfm},即文件Unit1.dfm,如下:

Unit1.dfm//一开始自动生成的

显而易见,这个*.dfm/Unit1.dfm窗口资源文件里,就是对Form1这个对象的最基本属性进行设定。
好了,这些重要的原理已经被挖掘出来了,但是你会问,这跟我们开头的问题有何关系?
不急,这是药引,是铺垫基础。
经过这样说明,我们把Unit1.pas替换为

Unit1.pas//{$R *.dfm} 改为{$R Unit1.dfm}

F9一下,正常编译运行,和没修改一样:-)

2]解开button1.OnClick迷团

 

    2.1]和往常一样,从组件Standard面板点击Button图标,再在Form1窗体上点一下,一个新的Button就诞生了:Button1。

好的,现在我们来看Delphi在上面过程中为我们做了什么:

Unit1.pas//加入Button1

在Unit1.pas只是加上这么一句Button1: TButton;表明Button1已经加到TForm1类里了。
注意:
如果你在加Button1之前,TForm1类里已经有这么一句Button1: TButton;那么Delphi就会抱怨:
Error:A field or method named Button1 already exists.  
你必须手动删除TForm1类底下Button1: TButton; 这可能是你的代码是直接从网上拷进去,而不是你自己一点点敲出来。
好了,我们再来看Unit1.dfm

Unit1.dfm//加入Button1

还是那么直白,这个Unit1.dfm窗口资源文件里,就是在已有Form1这个对象下,加入了新诞生的Button1最基本属性设定。
     2.2] 对了,接下就是新建Button1.OnClick了:
 1)在上Button1双击
 2)选取Button1,在Object Inspector里选择Events选项卡,点击并且选择OnClick选项,再在右栏空白处双击
两者没什么不同,就是个人习惯不同。

Delphi 会帮我们写好:

Button1Click
Unit1.pas//加入Button1->2)新建Button1.OnClick


真的只有这些么?让我来看解答全篇的问题的答案:来看看罪魁祸首Unit1.dfm:

Unit1.dfm//加入Button1->新建Button1.OnClick


Delphi又偷偷地瞒着我们做了什么了,它只是在Button1最基本属性后,附加了这么一句:
OnClick = Button1Click
这句的作用是什么呢?
既然它是一个赋值,我们来看看赋值号左右各是什么:
Button1.OnClick->FOnClick: TNotifyEvent= procedure(Sender: TObject) of object;//method pointer
也就是说Button1.OnClick是一种以(Sender: TObject)为参数的通知过程类型的属性,可被赋为TNotifyEvent类的过程

而Button1Click呢?
  TForm1 = class(TForm)
  Button1: TButton;
  procedure Button1Click(Sender: TObject);
说明Button1Click是Form1对象的一个以(Sender: TObject)为参数的过程,这正是一种TNotifyEvent类的过程.

这样的赋值跟
var
i:integer;
i:=0;
Interger,String等Predefined预定义类型的赋值一样,不过这是面向对象里的赋值。
Button1.OnClick := Form1.Button1Click;
它把 Form1.Button1Click对应内存里的地址拷给Button1.OnClick,使得Form1和Button1都可调用Button1Click过程。如图所示:。
其实我们可以把在Unit1.dfm里删除OnClick = Button1Click这一行,其后在Form1.Create里加入
Button1.OnClick := Form1.Button1Click;

效果是一样的。

不过既然Delphi有这么一个机制,帮我们做好了,我们就不必每创建一个On事件就还得往.dfm里对应的对象里加入这一行,毕竟,Delphi就是以其RAD著称滴。

这就是为什么我们在接口部份删除

  procedure Button1Click(Sender: TObject);

时会弹出这样的询问:

Button1.Click调用Button1Click的过程:



回答问题:
  Form1.Button1Click(form1);
  Form1.Button1.Click;

1)这两种调用有什么区别?  

从结果来看,没有差异,就像新建Button1.OnClick了:
  1)在上Button1双击
 2)选取Button1,在Object Inspector里选择Events选项卡,点击并且选择OnClick选项,再在右栏空白处双击

        从执行过程来看
          1]Form1.Button1Click(form1);
              //是直接调用Button1Click过程
          2]Form1.Button1.Click;

              TButton.Click>>TControl.Click>>OnClick>>Button1Click

       从执行效率来看

           Form1.Button1Click(form1)
           优于
          Form1.Button1.Click(form1)

2)Procedure Button1Click(Sender: TObject); 这个过程归属于Form1,还是Button1?

          归属于Form1,跟button1对象是否存在没有关系,Button1只是把OnClick属性关联到Button1Click。

引出有益结论:
直接结论 
就是方法(procedure/function)作为一种类型,也可被赋给对象的某个属性。

附录1:

Delphi里关于{$R dfm}的说明:




原文地址:https://www.cnblogs.com/tulater/p/1311117.html