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

cedebl8k  于 2023-08-04  发布在  其他
关注(0)|答案(4)|浏览(141)

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

eiee3dmh

eiee3dmh1#

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

program Project23;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  // Declare an event type. It looks a lot like a normal method declaration except
  // it is 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, plus a pointer to the
                                              // object instance it is intended 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,
                                         // we 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.

字符串

bkhjykvo

bkhjykvo2#

完整的项目答案是好的。但这是一个替代答案,展示了如何做你想做的,以一种你已经拥有的形式。
进入表单,进入接口部分,在类型区域,在表单的类定义之外,添加一个类型:

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;

dwbf0jvd

dwbf0jvd3#

您可以使用事件处理程序在发生其他事件时做出React(例如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;

r1zhe5dt

r1zhe5dt4#

在将“事件”放入DLL的上下文中,我描述了一个使用接口的概念,一步一步…也许这会以另一种方式有所帮助:在非GUI环境中使用事件侦听器(DLL)( Delphi )

相关问题