简体   繁体   English

Delphi事件处理,如何创建自己的事件

[英]Delphi event handling, how to create own event

I am new to delphi development. 我是delphi开发的新手。 I have to create an event and pass some properties as parameters. 我必须创建一个事件并将一些属性作为参数传递。 Could someone share some demo program that shows how to do this from scratch. 有人可以分享一些演示程序,演示如何从头开始。 I googled nearly every site, they all gave a piece of code, but what I need is a full fledged program that is simple and understandable. 我几乎每个网站都搜索过,他们都给了一段代码,但我需要的是一个简单易懂的完整程序。

Here's a short-but-complete console application that shows how to create your own event in Delphi. 这是一个简短但完整的控制台应用程序,它展示了如何在Delphi中创建自己的事件。 Includes everything from type declaration to calling the event. 包括从类型声明到调用事件的所有内容。 Read the comments in the code to understand what's going on. 阅读代码中的注释以了解正在发生的事情。

program Project23;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  // Declare an event type. It looks allot like a normal method declaration except
  // it suffixed by "of object". That "of object" tells Delphi the variable of this
  // type needs to be assigned a method of an object, not just any global function
  // with the correct signature.
  TMyEventTakingAStringParameter = procedure(const aStrParam:string) of object;

  // A class that uses the actual event
  TMyDummyLoggingClass = class
  public
    OnLogMsg: TMyEventTakingAStringParameter; // This will hold the "closure", a pointer to
                                              // the method function itself + a pointer to the
                                              // object instance it's supposed to work on.
    procedure LogMsg(const msg:string);
  end;

  // A class that provides the required string method to be used as a parameter
  TMyClassImplementingTheStringMethod = class
  public
    procedure WriteLine(const Something:string); // Intentionally using different names for
                                                 // method and params; Names don't matter, only the
                                                 // signature matters.
  end;

  procedure TMyDummyLoggingClass.LogMsg(const msg: string);
  begin
    if Assigned(OnLogMsg) then // tests if the event is assigned
      OnLogMsg(msg); // calls the event.
  end;

  procedure TMyClassImplementingTheStringMethod.WriteLine(const Something: string);
  begin
    // Simple implementation, writing the string to console
    Writeln(Something);
  end;

var Logging: TMyDummyLoggingClass; // This has the OnLogMsg variable
    LoggingProvider: TMyClassImplementingTheStringMethod; // This provides the method we'll assign to OnLogMsg

begin
  try
    Logging := TMyDummyLoggingClass.Create;
    try

      // This does nothing, because there's no OnLogMsg assigned.
      Logging.LogMsg('Test 1');

      LoggingProvider := TMyClassImplementingTheStringMethod.Create;
      try
        Logging.OnLogMsg := LoggingProvider.WriteLine; // Assign the event
        try

          // This will indirectly call LoggingProvider.WriteLine, because that's what's
          // assigned to Logging.OnLogMsg
          Logging.LogMsg('Test 2');

        finally Logging.OnLogMsg := nil; // Since the assigned event includes a pointer to both
                                         // the method itself and to the instance of LoggingProvider,
                                         // need to make sure the event doesn't out-live the LoggingProvider                                             
        end;
      finally LoggingProvider.Free;
      end;
    finally Logging.Free;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

The complete project answer is good. 完整的项目答案很好。 But this is an alternate answer showing how to do what you want, in a form you already have. 但这是一个替代答案,展示了如何以您已有的形式做您想做的事情。

Go into your form, and go to the interface section, in the types area, outside your form's class definition and add a type: 进入表单,然后转到表单类定义之外的类型区域中的接口部分,并添加一个类型:

 interface
 type
  TMyEvent = procedure(Sender:TObject;Param1,Param2,Param3:Integer) of object;

  TMyForm = class(TForm)
            ....

It is traditional, but not required, that the first item in your event be the object sending it, but to use base class TObject instead of your form's actual class type. 事件中的第一项是发送它的对象,但使用基类TObject而不是表单的实际类类型是传统的,但不是必需的。
The other parameters above are not required at all, but are showing you how you would declare your own additional data. 上面的其他参数根本不需要,但是向您展示如何声明自己的附加数据。 if you don't need them, then just use Sender:TObject. 如果你不需要它们,那么只需使用Sender:TObject。 And in that case, you don't have to define TMyEvent at all, just use the TNotifyEvent type. 在这种情况下,您根本不必定义TMyEvent,只需使用TNotifyEvent类型。

Now declare a field that uses that type, in your form: 现在在表单中声明一个使用该类型的字段:

TMyForm = class(TForm)
 private
   FMyEvent : TMyEvent;
  ...

Now declare a property that accesses that field, in your form's properties section: 现在声明一个访问该字段的属性,在表单的属性部分中:

  // this goes inside the class definition just before the final closing end 
 property MyEvent:TMyEvent read FMyEvent write FMyEvent

Now go to where you want that event to 'fire' (get called if it is set) and write this: 现在转到你希望该事件“激发”的地方(如果已设置则调用)并写下:

// this goes inside a procedure or function, where you need to "fire" the event.
procedure TMyForm.DoSomething;
begin
  ...
  if Assigned(FMyEvent) then FMyEvent(Self,Param1,Param2,Param3);
end;

You use an event handler to react when something else happens (for example AfterCreation and before closing). 您可以使用事件处理程序在发生其他事件时做出反应(例如AfterCreation和关闭之前)。

In order to use events for your own class, you need to define the event type. 要为自己的类使用事件,您需要定义事件类型。 Change the type and number of parameters needed. 更改所需参数的类型和数量。

type
  TMyProcEvent = procedure(const AIdent: string; const AValue: Integer) of object;
  TMyFuncEvent = function(const ANumber: Integer): Integer of object;

In the class, you can add a DoEvent (rename for the proper event). 在类中,您可以添加DoEvent(为正确的事件重命名)。 SO you can call the DoEvent internally. 所以你可以在内部调用DoEvent。 The DoEvent handles the possibility that an event is not assigned. DoEvent处理未分配事件的可能性。

type
  TMyClass = class
  private
    FMyProcEvent : TMyProcEvent;
    FMyFuncEvent : TMyFuncEvent;
  protected
    procedure DoMyProcEvent(const AIdent: string; const AValue: Integer);
    function DoMyFuncEvent(const ANumber: Integer): Integer;

  public
    property MyProcEvent: TMyProcEvent read FMyProcEvent write FMyProcEvent;
    property MyFuncEvent: TMyFuncEvent read FMyFuncEvent write FMyFuncEvent;
  end;

procedure TMyClass.DoMyProcEvent(const AIdent: string; const AValue: Integer);
begin
  if Assigned(FMyProcEvent) then
    FMyProcEvent(AIdent, AValue);
  // Possibly add more general or default code.
end;


function TMyClass.DoMyFuncEvent(const ANumber: Integer): Integer;
begin
  if Assigned(FMyFuncEvent) then
    Result := FMyFuncEvent(ANumber)
  else
    Result := cNotAssignedValue;
end;

在将“事件”放入DLL的上下文中,我使用接口逐步描述了一个概念......也许这有助于以不同的方式: 在非gui环境中使用事件监听器(DLL)(Delphi)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM