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

mac*_*mac 17 delphi events

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

Cos*_*und 50

这是一个简短但完整的控制台应用程序,它展示了如何在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.
Run Code Online (Sandbox Code Playgroud)

  • @mac不,我不能.这*是一个完整的例子,在表格上做同样的事情不需要*任何特别的*; 表单就像任何其他类一样.执行基于表单的示例需要至少3个文件(dpr,dfm + pas),并且不添加*任何*new.我仍然怀疑这不是你所需要的,但由于你不想回答"为什么"的问题,我不能做得更好. (27认同)

War*_* P 19

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

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

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

  TMyForm = class(TForm)
            ....
Run Code Online (Sandbox Code Playgroud)

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

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

TMyForm = class(TForm)
 private
   FMyEvent : TMyEvent;
  ...
Run Code Online (Sandbox Code Playgroud)

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

  // this goes inside the class definition just before the final closing end 
 property MyEvent:TMyEvent read FMyEvent write FMyEvent
Run Code Online (Sandbox Code Playgroud)

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

// 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;
Run Code Online (Sandbox Code Playgroud)

  • 我不知道你的意思.如果您仍然不清楚,最好是问一个不同的问题. (2认同)

Too*_*the 14

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

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

type
  TMyProcEvent = procedure(const AIdent: string; const AValue: Integer) of object;
  TMyFuncEvent = function(const ANumber: Integer): Integer of object;
Run Code Online (Sandbox Code Playgroud)

在类中,您可以添加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;
Run Code Online (Sandbox Code Playgroud)

  • @mac,如果代码不适合您的复制粘贴,请自行复制粘贴.如果您不了解一些代码,请要求澄清.简单地要求更多复制粘贴友好代码让你看起来像一个懒惰[你有危险代码](http://meta.serverfault.com/questions/1039/what-is-do-you-haz-teh-codez )类型. (13认同)
  • 谢谢 !经过大量的搜索,这是迄今为止我发现的最好的解释。希望我能赞成你十次! (2认同)