How to check if two events are pointing to the same procedure in Delphi?

后端 未结 3 1838
故里飘歌
故里飘歌 2020-12-01 16:27

Say I have a Button1.OnClick event linked to Button1Click procedure. I also have Button2.OnClick linked to some other procedure. How do I check that both events are linked t

相关标签:
3条回答
  • 2020-12-01 16:46

    I know this is an old question...but here's my 2cents...

    This is answer is similar to Nat's but doesn't limit us to only TNotifyEvents...and answers David's question of how to do this with out it being a hack...

    function CompareMethods(aMethod1, aMethod2: TMethod): boolean;
    begin
      Result := (aMethod1.Code = aMethod2.Code) and
                (aMethod1.Data = aMethod2.Data);
    end; 
    

    I use it like so

    procedure TDefaultLoop.RemoveObserver(aObserver: TObject; aEvent: TNotifyEvent);
    var
      a_Index: integer;
    begin
      for a_Index := 0 to FNotifyList.Count - 1 do
        if Assigned(FNotifyList[a_Index]) and
         (TNotify(FNotifyList[a_Index]).Observer = aObserver) and
          CompareMethods(TMethod(TNotify(FNotifyList[a_Index]).Event), TMethod(aEvent))     then
    begin
      FNotifyList.Delete(a_Index);
      FNotifyList[a_Index] := nil;
    end;
    

    Also a quick and dirty demonstration

    procedure TForm53.Button1Click(Sender: TObject);
    var
      a_Event1, a_Event2: TMethod;
    begin
      if Sender is TButton then
      begin
         a_Event1 := TMethod(Button1.OnClick);
         a_Event2 := TMethod(Button2.OnClick);
        if CompareMethods(TMethod(TButton(Sender).OnClick), a_Event1) then
           ShowMessage('Button1Click Same Method');
        if CompareMethods(TMethod(TButton(Sender).OnClick), a_Event2) then
           ShowMessage('Button2Click Same Method');
      end;
    end;
    
    
    procedure TForm53.Button2Click(Sender: TObject);
    var
      a_Event1, a_Event2: TMethod;
    begin
      if Sender is TButton then
      begin
         a_Event1 := TMethod(Button1.OnClick);
         a_Event2 := TMethod(Button2.OnClick);
        if CompareMethods(TMethod(TButton(Sender).OnClick), a_Event1) then
           ShowMessage('Button1Click Same Method');
        if CompareMethods(TMethod(TButton(Sender).OnClick), a_Event2) then
           ShowMessage('Button2Click Same Method');
      end;
    end;
    
    0 讨论(0)
  • 2020-12-01 16:59

    A method reference can be broken down in to two parts, the pointer to the object and the pointer to the method itself. There is a convenient record type defined in the System unit called TMethod that allows us to do that break down.

    With that knowledge, we can write something like this:

    function SameMethod(AMethod1, AMethod2: TNotifyEvent): boolean;
    begin
      result := (TMethod(AMethod1).Code = TMethod(AMethod2).Code) 
                and (TMethod(AMethod1).Data = TMethod(AMethod2).Data);   
    end;
    

    Hope this helps. :)

    Edit: Just to lay out in a better format the problem I am trying to solve here (as alluded to in the comments).

    If you have two forms, both instantiated from the same base class:

    Form1 := TMyForm.Create(nil);
    Form2 := TMyForm.Create(nil);
    

    and you assign the same method from those forms to the two buttons:

    Button1.OnClick := Form1.ButtonClick;
    Button2.OnClick := Form2.ButtonClick;
    

    And compare the two OnClick properties, you will find that the Code is the same, but the Data is different. That is because it's the same method, but on two different instantiations of the class...

    Now, if you had two methods on the same object:

    Form1 := TMyForm.Create(nil);
    
    Button1.OnClick := Form1.ButtonClick1;
    Button2.OnClick := Form1.ButtonClick2;
    

    Then their Data will be the same, but their Code will be different.

    0 讨论(0)
  • 2020-12-01 17:03

    I do it with this function:

    function MethodPointersEqual(const MethodPointer1, MethodPointer2): Boolean;
    var
      Method1: System.TMethod absolute MethodPointer1;
      Method2: System.TMethod absolute MethodPointer2;
    begin
      Result := (Method1.Code=Method2.Code) and (Method1.Data=Method2.Data)
    end;
    

    It works, but if someone knows a less hacky way to do it then I'd love to hear about it!

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