TProc to TNotifyEvent

前端 未结 2 1417
小鲜肉
小鲜肉 2020-12-30 03:01

Further to this post whose accepted answer remains very cryptic:

@Button1.OnClick := pPointer(Cardinal(pPointer( procedure (sender: tObject) begin ((sender a         


        
相关标签:
2条回答
  • 2020-12-30 03:17

    For reference this what I am getting at, I studied Barry Kelly's blog post referenced in the prior SO post mentioned above and came up with this 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;
    

    Still cryptic but encapsuled, so easing the task of the coder compared to the initial method.

    I tried to tidy MethRefToMethPtr and MakeNotify and put it all in one method.

    Notice that there was (a slight) change in the method's signature, the argument aProc became const.

    0 讨论(0)
  • 2020-12-30 03:31

    This will do the job readily enough:

    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;
    

    The Owner parameter in AnonProc2NotifyEvent is so that the lifetime of the wrapper object can be managed. Without something like that you would leak instances of TNotifyEventWrapper.

    Pass as Owner, the component to which you are connecting the event. For example:

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

    So, when the button is destroyed, the TNotifyEventWrapper will also be destroyed. The wrapper object must live at least as long as the object to whose events it is associated. And so the choice of Button1 as the owner is the natural and obvious one.

    0 讨论(0)
提交回复
热议问题