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

时间:2011-04-26 06:06:31

标签: delphi events

我是delphi开发的新手。我必须创建一个事件并将一些属性作为参数传递。有人可以分享一些演示程序,演示如何从头开始。我几乎每个网站都搜索过,他们都给了一段代码,但我需要的是一个简单易懂的完整程序。

4 个答案:

答案 0 :(得分:49)

这是一个简短但完整的控制台应用程序,它展示了如何在Delphi中创建自己的事件。包括从类型声明到调用事件的所有内容。阅读代码中的注释,了解正在发生的事情。

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.

答案 1 :(得分:18)

完整的项目答案很好。但这是一个替代答案,展示了如何以你已有的形式做你想做的事。

进入表单,然后转到表单类定义之外的类型区域中的界面部分,并添加一个类型:

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

  TMyForm = class(TForm)
            ....

事件中的第一项是发送它的对象,但使用基类TObject而不是表单的实际类类型是传统的,但不是必需的。 上面的其他参数根本不需要,但是向您展示如何声明自己的附加数据。如果你不需要它们,那么只需使用Sender:TObject。 在这种情况下,您根本不必定义TMyEvent,只需使用TNotifyEvent类型。

现在声明一个在您的表单中使用该类型的字段:

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

现在声明一个访问该字段的属性,在表单的属性部分中:

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

现在转到你希望该事件发生的地方'开火'(如果已设置则调用)并写下:

// 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;

答案 2 :(得分:14)

使用事件处理程序在发生其他事情时做出反应(例如AfterCreation和关闭之前)。

要为自己的类使用事件,您需要定义事件类型。更改所需参数的类型和数量。

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

在课程中,您可以添加DoEvent(为正确的事件重命名)。所以你可以在内部调用DoEvent。 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;

答案 3 :(得分:0)

在放置"事件"的背景​​下进入一个DLL我用一步一步的接口描述了一个概念......也许这有助于以不同的方式:Using event listeners in a non-gui environment (DLL) (Delphi)