web-dev-qa-db-fra.com

Gestion des événements Delphi, comment créer son propre événement

Je suis nouveau dans le développement de Delphes. Je dois créer un événement et transmettre certaines propriétés en tant que paramètres. Quelqu'un pourrait-il partager un programme de démonstration qui montre comment procéder à partir de zéro? J'ai cherché sur presque tous les sites, ils ont tous fourni un code, mais ce dont j'ai besoin, c'est d'un programme complet, simple et compréhensible. 

16
mac

Voici une application console courte mais complète qui explique comment créer votre propre événement dans Delphi. Inclut tout, de la déclaration de type à l'appel de l'événement. Lisez les commentaires dans le code pour comprendre ce qui se passe.

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.
48
Cosmin Prund

La réponse complète du projet est bonne. Mais c’est une autre réponse qui montre comment faire ce que vous voulez, sous une forme que vous avez déjà.

Accédez à votre formulaire et accédez à la section Interface, dans la zone des types, en dehors de la définition de classe de votre formulaire, puis ajoutez un type:

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

  TMyForm = class(TForm)
            ....

Il est classique, mais pas obligatoire, que le premier élément de votre événement soit l'objet qui l'envoie, mais d'utiliser la classe de base TObject au lieu du type de classe réel de votre formulaire.
Les autres paramètres ci-dessus ne sont pas du tout nécessaires, mais vous montrent comment vous déclareriez vos propres données supplémentaires. si vous n'en avez pas besoin, utilisez simplement Sender: TObject . Dans ce cas, vous n'avez pas du tout besoin de définir TMyEvent, utilisez simplement le type TNotifyEvent.

Maintenant, déclarez un champ qui utilise ce type, dans votre formulaire:

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

Maintenant, déclarez une propriété qui accède à ce champ, dans la section des propriétés de votre formulaire:

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

Maintenant, allez à l'endroit où vous voulez que cet événement "se déclenche" (soit appelé s'il est défini) et écrivez ceci:

// 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;
18
Warren P

Vous utilisez un gestionnaire d'événements pour réagir lorsque quelque chose d'autre se produit (par exemple, AfterCreation et avant la fermeture).

Afin d'utiliser des événements pour votre propre classe, vous devez définir le type d'événement. Changez le type et le nombre de paramètres nécessaires.

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

Dans la classe, vous pouvez ajouter un DoEvent (renommer l'événement approprié). SO vous pouvez appeler DoEvent en interne. DoEvent gère la possibilité qu’un événement ne soit pas affecté. 

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;
14
Toon Krijthe

dans le contexte du placement "d'événements" dans une DLL, j'ai décrit étape par étape un concept utilisant des interfaces ... cela aide peut-être différemment: Utilisation d'écouteurs d'événement dans un environnement non graphique (Delphi)

0
monnoo