Остановить распространение событий в Delphi 7

Я застрял на проблеме в Delphi 7 О распространении событий (из-за моего невежества).

меня просят динамически присоединить OnMouseUp обработчик событий на некоторых элементах управления в форме (и я в порядке с этой вещью), но если OnMouseUp присутствует OnClick событие на этом элементе управления не должно обрабатываться.

фон

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

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

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

необходимость

Я не прошу подтверждения или вопроса о (возможном отсутствии) благости дизайна обо всем этом (кстати, после многих размышлений и рассуждений это, казалось, путь, по которому мы можем идти с меньшей болью); моя проблема разве что для такого дизайна я должен был бы позволить динамически подключаться OnMouseUp обработчики событий останавливают распространение событий до существующего OnClick события на этих элементах управления.

возможно ли это с Delphi 7?

2 ответов


обратите внимание, что следующее явно не отвечает на вопрос здесь. Это скорее предложение по перепроектированию концепции (перенаправление событий OnClick вместо добавления дополнительного OnMouseUp). Речь идет о том, как перенаправить обработчик событий OnClick (если он назначен некоторым) всех компонентов (при необходимости может быть отфильтрован) на другой (общий) обработчик событий OnClick. Он также включает в себя метод восстановления их в исходное состояние.

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

код состоит из следующий:

  • OnSpecialClick - это обработчик событий, к которому будут привязаны все события OnClick при вызове процедуры ReplaceOnClickEvents, обратите внимание, что он должен быть опубликован, чтобы быть видимым для RTTI !!!

  • Button1Click - представляет здесь старый обработчик событий, который должен быть заменен, он привязан к Button1.Событие onclick на дизайн времени

  • ReplaceOnClickEvents - метод, который перебирает все компоненты на форме и проверяет
    если текущий итерационный имеет назначенный обработчик событий OnClick; если это так, он сохраняет его в резервную коллекцию и заменяет этот обработчик событий OnSpecialClick

  • RestoreOnClickEvents - метод, который восстанавливает исходные обработчики событий OnClick; это выполняет итерацию по коллекции резервных копий и назначает методы событий ее сохраненным экземплярам компонентов

  • CheckBox1Click - этот флажок click event предназначен для переключения между общим и специальным режимом (CheckBox1 checked state означает специальный режим), только это событие OnClick не заменяется вызовом ReplaceOnClickEvents (потому что вы не сможете восстановить режим обратно в нормально)

и вот это:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, TypInfo, StdCtrls, Contnrs;

type
  TEventBackup = class
    Component: TComponent;
    OnClickMethod: TMethod;
  end;

type
  TForm1 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;
    procedure Button1Click(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
  private
    procedure ReplaceOnClickEvents;
    procedure RestoreOnClickEvents;
  published
    procedure OnSpecialClick(Sender: TObject);
  end;

var
  Form1: TForm1;
  EventBackupList: TObjectList;

implementation

{$R *.dfm}

procedure TForm1.OnSpecialClick(Sender: TObject);
begin
  ShowMessage('Hi, I''m an OnSpecialClick event message!');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage('Hi, I''m just that boring original OnClick event message!');
end;

procedure TForm1.ReplaceOnClickEvents;
var
  I: Integer;
  Component: TComponent;
  EventMethod: TMethod;
  EventBackup: TEventBackup;
begin
  for I := 0 to ComponentCount - 1 do
  begin
    Component := Components[I];
    if Component = CheckBox1 then
      Continue;

    if IsPublishedProp(Component, 'OnClick') then
    begin
      EventMethod := GetMethodProp(Component, 'OnClick');
      if Assigned(EventMethod.Code) and Assigned(EventMethod.Data) then
      begin
        EventBackup := TEventBackup.Create;
        EventBackup.Component := Component;
        EventBackup.OnClickMethod := EventMethod;
        EventBackupList.Add(EventBackup);
        EventMethod.Code := MethodAddress('OnSpecialClick');
        EventMethod.Data := Pointer(Self);
        SetMethodProp(Component, 'OnClick', EventMethod);
      end;
    end;
  end;
end;

procedure TForm1.RestoreOnClickEvents;
var
  I: Integer;
  EventBackup: TEventBackup;
begin
  for I := 0 to EventBackupList.Count - 1 do
  begin
    EventBackup := TEventBackup(EventBackupList[I]);
    SetMethodProp(EventBackup.Component, 'OnClick', EventBackup.OnClickMethod);
  end;
  EventBackupList.Clear;
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if CheckBox1.Checked then
    ReplaceOnClickEvents
  else
    RestoreOnClickEvents;
end;

initialization
  EventBackupList := TObjectList.Create;
  EventBackupList.OwnsObjects := True;

finalization
  EventBackupList.Free;

end.

как сказали и Тлама, и Тондрей, есть несколько способов выполнить то, что вы пытаетесь:

  1. сделать if Assigned(Control.OnMouseUp) then Exit; на OnClick обработчик события

  2. "отменить назначение"OnClick событие при назначении OnMouseUp (и наоборот)

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