Delphi: Как назначить динамически обработчик событий без перезаписывания существующего обработчика событий?

Мне нужно прокрутить компоненты и назначить обработчик событий (например, динамически назначать событие OnClick для всех TButton для

ShowMessage('You clicked on ' + (Sender as TButton).Name);

Проблема в том, что в некоторых случаях я уже назначил событие TButton OnClick.

Есть ли способ решить проблему?

Предположим, что у меня есть Button1, для которого обработчик событий harcoded onclick:

ShowMessage('This is Button1');

После моего "разбора" мне бы хотелось, чтобы полный обработчик событий для Button1 стал:

ShowMessage('This is Button1'); // design time event handler code
ShowMessage('You clicked on ' + (Sender as TButton).Name); // runtime added

Примечание. Я ищу решение, которое позволяет мне использовать TButton, поскольку он не наследуется от него.

Ответ 1

вы можете искать назначение OnClick перед его перезаписью, сохраняйте это и используйте его в своем новом обработчике - в основном, цепочку событий.

Что-то вроде этого:

  var original : TNotifyEvent;

  original := Component.OnClick;
  Component.OnClick := NewMethod;

а затем в вашем NewMethod:

  if assigned(original) then original(Sender);

вы, вероятно, не захотите использовать одну исходную переменную, но вместо этого удерживайте коллекцию, содержащую ключ для компонента.

Ответ 2

Если вы пишете обработчики замены самостоятельно, вы можете сделать следующее:

  • Перед назначением нового обработчика храните ссылку на объект и ссылку на исходный обработчик в списке или другой структуре.

  • В вашем обработчике замены включен код для проверки списка, чтобы увидеть, имеет ли текущий объект запись. Если это так, вызовите хранимый метод, прежде чем выполнять свою собственную работу.

Это довольно легкий (список, в котором каждая запись представляет собой два указателя). С небольшой дополнительной работой (для поддержки заказа) вы могли бы, вероятно, даже подключить более одного замененного обработчика.

Ответ 3

Вы не можете сделать это напрямую, поскольку Delphi не поддерживает прикованные события (я принимаю VCL Delphi).

Итак, все, что вы хотите сделать, связанное с непосредственным назначением события OnClick, не будет работать. Что вы можете сделать, так это создать компонент перехватчика, то есть что-то с этой сигнатурой:

type
   TButton = class(stdctrls.TButton)

Вам придется переопределить свойство OnClick, чтобы событие записи хранило обработчик события во внутренний список, доступный классу.

property OnClick: TNotifyEvent read GetOnClick write SetOnClick;

то в обработчике SetOnClick вы сможете просто сохранить обработчик событий во внутреннем списке.

Теперь вам придется переопределить процедуру Click, чтобы она вызывала каждый делегат (каждый обработчик событий) по очереди.

procedure Click; override;

И это будет сделано.

Обратите внимание, что в конце концов вы будете подклассифицировать класс TButton, даже если вы используете одно и то же имя... В любом случае, лучшее решение, о котором я могу думать. Приятная вещь в том, что вы все еще можете использовать назначения, не зная о связанных событиях, вы можете просто:

MyButton.OnClick := MyHandler

и он будет автоматически привязан к остальным обработчикам событий.