【问题标题】:Delphi event handling, how to create own eventDelphi事件处理,如何创建自己的事件
【发布时间】:2011-04-26 06:06:31
【问题描述】:

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

【问题讨论】:

  • 请解释您实际尝试做的事情,提供足够的信息以便我们建议替代路线;因为我怀疑你提出的实际问题的答案对你没有帮助。
  • <joke>要使用事件获得完整的程序,请执行以下操作:文件 -> 新建 -> VCL 表单应用程序。你有它,它是一个完整的工作示例,说明如何使用事件,具有完整的源代码。</joke>。但正如我在之前的评论中提到的,我怀疑这就是你真正需要的。一般来说,很难从成熟的程序中学习。
  • 谢谢,我实际上想要一个小程序,在德尔福中精心创建事件。如何在 delphi 中创建自己的事件。
  • 你重复了这个问题,没有说你想要做什么。有可能的替代实现,使用匿名方法或传递接口,事件不是唯一的方法,无论您实际尝试做什么。我提供了一个简短但完整的使用事件的工作程序,希望对您有所帮助。
  • 你要求一个完整的演示,Cosmin 给你一个,然后你说,但是我如何将它添加到我的程序中。如果我可以用某种“烦人的用户”标记来标记这个问题,我会很想在这里这样做。 Mac,你需要学会提出直接、准确的问题,然后当你得到你想要的东西时,不要说相反的话。

标签: delphi events


【解决方案1】:

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

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.

【讨论】:

  • 非常感谢,很好的例子,你是否也提供了一个基于表单的例子,因为它是基于控制台的。我需要在表单上创建自己的事件并输出一些东西。谢谢你的好例子。
  • @mac 不,我不能。这一个完整的例子,在表单上做同样的事情不需要任何特殊的;表单只是一个类,就像任何其他类一样。执行基于表单的示例需要至少 3 个文件(dpr、dfm + pas)并且不会添加 anything 新文件。我仍然怀疑这不是您所需要的,但是由于您不想回答“做什么”的问题,所以我不能做得更好。
【解决方案2】:

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

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

 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;

【讨论】:

  • 谢谢沃伦;我将尝试用delphi做一些事情,实际上问题是,程序流程,要么我需要在一个单元中定义和调用事件,要么需要另一个单元来定义事件和分配属性,然后调用这个事件按钮单击事件。比如进度条和百分比计数器。
  • 我不明白你的意思。如果您仍然不清楚,最好提出不同的问题。
【解决方案3】:

当其他事情发生时(例如 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;

【讨论】:

  • 谢谢亲爱的,非常有帮助。但仍然不是复制粘贴然后只是更改属性可以达到不同的结果。
  • @mac,如果您的代码对复制粘贴不友好,请自己使其复制粘贴友好。如果您对代码有一点不理解,请要求澄清。简单地要求更易于复制粘贴的代码会让你看起来像一个懒惰的Do you haz teh codez 类型。
  • 谢谢!经过大量的谷歌搜索,这是迄今为止我找到的最好的解释。希望我能给你十次投票!
【解决方案4】:

在将“事件”放入 DLL 的上下文中,我使用接口逐步描述了一个概念...也许这会以不同的方式提供帮助:Using event listeners in a non-gui environment (DLL) (Delphi)

【讨论】:

  • 这将是一个很好的评论。
猜你喜欢
  • 1970-01-01
  • 2013-12-24
  • 1970-01-01
  • 2012-05-07
  • 2010-10-12
  • 1970-01-01
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多