Как проверить, указывают ли два события на одну и ту же процедуру в Delphi? - PullRequest
14 голосов
/ 01 августа 2011

Допустим, у меня есть событие Button1.OnClick, связанное с процедурой Button1Click.У меня также есть Button2.OnClick, связанный с какой-то другой процедурой.Как проверить, что оба события связаны с разными или одинаковыми процедурами во время выполнения?

Я пытался проверить:

  • Button1.OnClick = Button2.OnClick, но это дало мнеошибка (недостаточно фактических параметров)
  • @ (Button1.OnClick) = @ (Button2.OnClick), ошибка снова (недостаточно фактических параметров)

Как проверить этоправильно?

Ответы [ 3 ]

29 голосов
/ 01 августа 2011

Ссылка на метод может быть разбита на две части: указатель на объект и указатель на сам метод. В единице System определен удобный тип записи, называемый TMethod, который позволяет нам делать это в разбивке.

С этим знанием мы можем написать что-то вроде этого:

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

Надеюсь, это поможет. :)

Редактировать : просто изложить в лучшем формате проблему, которую я пытаюсь решить здесь (как указано в комментариях).

Если у вас есть две формы, обе из одного и того же базового класса:

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

и вы назначаете один и тот же метод из этих форм двум кнопкам:

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

И сравните два свойства OnClick, вы обнаружите, что Code то же самое, но Data отличается. Это потому, что это один и тот же метод, но в двух разных экземплярах класса ...

Теперь, если у вас есть два метода для одного и того же объекта:

Form1 := TMyForm.Create(nil);

Button1.OnClick := Form1.ButtonClick1;
Button2.OnClick := Form1.ButtonClick2;

Тогда их Data будут такими же, но их Code будут другими.

18 голосов
/ 01 августа 2011

Я делаю это с помощью этой функции:

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;

Это работает, но если кто-то знает менее хакерский способ сделать это, то я хотел бы услышать об этом!

2 голосов
/ 15 июня 2013

Я знаю, что это старый вопрос ... но вот мои 2цента ...

Этот ответ аналогичен ответу Ната, но не ограничивает нас только TNotifyEvents ... и отвечает на вопрос Дэвида о том, как сделать это, не будучи хакером ...

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

Я использую это так

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;

Также быстрая и грязная демонстрация

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...