如何将自定义单元的过程分配给主窗体上的事件处理程序控件

时间:2016-08-05 12:16:34

标签: delphi eventhandler

这是真的吗? 例如,我有form1button1。我只能在button1.onClick的设计时间内指定Button26Click

  TForm1 = class(TForm)    
    procedure Button26Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

我也有单位2:

unit ProcAndFunc;
interface
uses sysutils,forms;

procedure createArrTable(Sender: TObject);

我可以设计时中将 createArrTable分配给button1.onClick吗? 感谢。

确定。 1单元

TForm1 = class(TForm)  
        myButton1 : TButton; 
        procedure Button26Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;

UNIT2

TForm2 = class(TForm) 
            myButton2 : TButton; 
            procedure ButtonClick(Sender: TObject);
          private
            { Private declarations }
          public
            { Public declarations }
          end;

只是想知道它是如何工作的。我应该unit2我应该更改ButtonClickmyButton1.OnClick的内容 How to make a separate unit for event methods, which IDE allows me to assign to component events at design time?似乎我重复了问题。但那个答案并不适合我。还有其他方法吗?

EDIT3(08.08.2016): 我创建了这个TDataModule;

unit Unit3;

interface

uses
  System.SysUtils, System.Classes,dialogs;

type
  TDataModule3 = class(TDataModule)
  procedure Click2(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  DataModule3: TDataModule3;

implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}

{$R *.dfm}

procedure TDataModule3.Click2(Sender: TObject);
begin
ShowMessage('hello world');
end;   

end.

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, unit3;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage('hello world');
end;

end.

我仍然无法在设计时将DataModule3.Click2分配给button1.onclick。 (screenshot)。我还需要做什么?

2 个答案:

答案 0 :(得分:1)

您不能将该过程指定为事件处理程序,因为它不是类的方法。因此,您可以使该过程成为另一个类的方法,并确保设计器可以看到该类的全局实例。

然而,在我看来,这将是一个非常糟糕的解决方案。最佳做法是尽可能将UI逻辑与应用程序逻辑分离。干净的解决方案是简单地从事件处理程序调用该过程。这意味着您的程序仍然可以以其当前形式提供给其他方,并且不需要看起来像一个事件处理程序。您也可以删除我怀疑您在任何情况下都不使用的response.write("Hello again"); response.end();参数。

答案 1 :(得分:1)

  

我可以在设计时将createArrTable分配给button1.onClick吗?

不是在设计时,不是。 createArrTable()不是类的成员,因此在运行时无法通过对象指针访问。因此它不满足OnClick事件处理程序通常所需的签名。 IDE将不允许您在设计时分配它。

但是,可以在运行时分配createArrTable(),并进行一些小的调整。

OnClick事件(以及一般的大多数RTL / VCL事件)是使用闭包实现的,它由2个指针组成 - 指向过程代码本身的指针和指针对象。

当在运行时触发事件时,编译的代码从闭包中提取对象指针,并使用传递给过程的Self参数的对象调用该过程。缺少Self参数会阻止您当前的createArrTable()实现用作OnClick事件处理程序。如果你按原样分配它,参数列表将在运行时被破坏。

但是,如果您向Self添加显式 createArrTable()参数,则可以避免该问题,并跳过类对象要求:

procedure createArrTable(Self: Pointer; Sender: TObject);

在调用过程时,按钮仍会尝试将对象指针从闭包传递到Self,但现在您已为对象指针创建了空间,以便正确传递并且不会损坏其他参数。对象指针本身变得无关紧要,可以设置为你想要的任何东西,甚至是零。

但是,由于createArrTable()仍然不是某个类的成员,因此您无法将直接分配给OnClick事件,但您可以使用TMethod }变量以便于分配,例如:

var
  M: TMethod;
begin
  M.Code := @createArrTable;
  M.Data := WhateverYouWantSelfToBe; 
  Button1.OnClick := TNotifyEvent(M);
end;

现在createArrTable()会在运行时触发OnClick时按预期工作。

  

我应该unit2我可以将ButtonClick分配给myButton1.OnClick

无。它已经是一个合适的事件处理程序。您只需将unit2添加到usesinterface部分的unit1子句中,以便IDE在设计时可以看到ButtonClick(),那么您就可以将Form2.ButtonClick分配给myButton1.OnClick。只需知道您必须在运行时设置项目以在 Form2之前创建Form1 ,否则当DFM流系统尝试访问{{}时,您可能会崩溃代码1}}在分配ButtonClick的值时通过无效的Form2对象。

为避免必须更改表单的创建顺序,您可以将事件处理程序放在单独的Form1.myButton.OnClick中,然后将其方法链接到表单上的事件。只需确保在创建表单之前在运行时创建TDataModule

Access DataModule's event from another Form (delphi design-time)