TProc to TNotifyEvent

Plus de cela post dont la réponse acceptée reste très cryptique:

@Button1.OnClick := pPointer(Cardinal(pPointer( procedure (sender: tObject) begin ((sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!' end )^ ) + C)^;

je me demande si il est possible de concevoir un plus simple et simple et élégant qui ressemble à:

Button.OnClick :=
                    AnonProc2NotifyEvent (
                    procedure (Sender: TObject)
                    begin
                      ((Sender as TButton).Owner as TForm).Caption := 'Freedom to anonymous methods!'
                    end
                      );

afin d'atteindre le même but et où AnonProc2NotifyEvent est une méthode du propriétaire de bouton avec la signature suivante:

TOwnerOfButton = class(TForm)
  Button: TButton;
  ...
private
  ...
protected
  function AnonProc2NotifyEvent(aProc: TProc<TObject>): TNotifyEvent;
public
  ...
end;

est-ce réalisable et, dans l'affirmative, comment le mettre en œuvre ?

15
demandé sur Community 2012-07-15 15:44:59

2 réponses

Ce sera de faire le travail assez facilement:

type
  TNotifyEventWrapper = class(TComponent)
  private
    FProc: TProc<TObject>;
  public
    constructor Create(Owner: TComponent; Proc: TProc<TObject>);
  published
    procedure Event(Sender: TObject);
  end;

constructor TNotifyEventWrapper.Create(Owner: TComponent; Proc: TProc<TObject>);
begin
  inherited Create(Owner);
  FProc := Proc;
end;

procedure TNotifyEventWrapper.Event(Sender: TObject);
begin
  FProc(Sender);
end;

function AnonProc2NotifyEvent(Owner: TComponent; Proc: TProc<TObject>): TNotifyEvent;
begin
  Result := TNotifyEventWrapper.Create(Owner, Proc).Event;
end;

Owner paramètre AnonProc2NotifyEvent permet de gérer la durée de vie de l'objet wrapper. Sans quelque chose comme ça, vous divulgueriez des exemples de TNotifyEventWrapper.

Pass Owner, le composant auquel vous connectez l'événement. Par exemple:

Button1.OnClick := AnonProc2NotifyEvent(
  Button1,
  procedure(Sender: TObject)
  begin
    (Sender as TButton).Caption := 'Clicked';
  end
);

Donc, lorsque le bouton est détruit, le TNotifyEventWrapper seront également détruites. L'objet de wrapper doit vivre au moins aussi longtemps que l'objet de dont les événements sont associés. Et donc, le choix du Button1 comme le propriétaire est le naturel et évident.

24
répondu David Heffernan 2012-07-15 12:11:19

Pour faire référence à ce à quoi je veux en venir, j'ai étudié Barry Kellyblog post référencé dans le précédent so post mentionné ci-dessus et a trouvé cette solution:

function TMainForm.Proc2NotifyEvent(const aProc: TNotifyReference): TNotifyEvent;
type
  TVtable = array[0..3] of Pointer;
  PVtable = ^TVtable;
  PPVtable = ^PVtable;
begin
  TMethod(Result).Code := PPVtable((@aProc)^)^^[3];
  TMethod(Result).Data := Pointer((@aProc)^);
end;

Encore cryptique mais encapsuled, facilitant la tâche du codeur par rapport à la méthode initiale.

j'ai essayé de mettre de l'ordre MethRefToMethPtr et MakeNotify et mettez tout cela dans une méthode.

remarquez qu'il y avait (un léger) changement dans la signature de la méthode, l'argument aProc est devenu const.

5
répondu menjaraz 2017-05-23 12:34:11