zoukankan      html  css  js  c++  java
  • 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}的说明:




  • 相关阅读:
    nodeName,nodeValue未知 xml 入库方案 The ElementTree iterparse Function
    如何:执行大型 XML 文档的流式转换 大XML文件解析入库的一个方法
    python curl_get-pip.py Installing with get-pip.py
    iptables List the rules in a chain or all chains
    goroutine 分析 协程的调度和执行顺序 并发写 run in the same address space 内存地址 闭包 存在两种并发 确定性 非确定性的 Go 的协程和通道理所当然的支持确定性的并发方式(
    数据库业界
    The MEAN stack is a modern replacement for the LAMP (Linux, Apache, MySQL, PHP/Python) stack
    Using Groovy To Import XML Into MongoDB
    虚拟机网络模式 桥接 网桥 交换机
    防止有内存泄漏并尽可能快地释放所有内存是内存管理的重要组成部分 长时间运行进程的内存泄漏
  • 原文地址:https://www.cnblogs.com/tulater/p/1311117.html
Copyright © 2011-2022 走看看