Как я могу поймать определенные события формы извне формы? - PullRequest
7 голосов
/ 05 января 2012

Я работаю над чем-то, что потребует мониторинга многих форм.Из-за пределов формы и без помещения какого-либо кода в форму мне нужно каким-то образом захватывать события из этих форм, скорее всего, в форме сообщений Windows.Но как бы вы перехватывали сообщения Windows вне класса, с которым он связан?

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

Эти события включают в себя:

  • Свернуть
  • Развернуть
  • Восстановить
  • Закрыть
  • Фокусировать / выводить

Чего я НЕ хочу:

  • Любой код внутри любых форм или блоков форм для этой обработки
  • Наследование форм из любой настраиваемой базовой формы
  • Использование событий формы, таких как OnClose, поскольку они будут использоваться для других целей

Чего я хочу:

  • Обработка сообщений Windows для этих событий
  • Любые советы о том, как получать сообщения Windows извне класса
  • Какие сообщения Windows мне нужно прослушивать

Вопрос переписан с той же информацией, но с другим подходом

Ответы [ 5 ]

9 голосов
/ 05 января 2012

Вам необходимо прослушивать определенные сообщения Windows, доставляемые в форму. Самый простой способ сделать это - назначить свойство WindowProc формы. Не забудьте сохранить прежнее значение WindowProc и вызвать его из вашей замены.

В вашем объекте-оболочке объявите поле, подобное этому:

FOriginalWindowProc: TWndMethod;

Затем в конструкторе обёртки сделайте это:

FOriginalWindowProc := Form.WindowProc;
Form.WindowProc := NewWindowProc;

Наконец, выполните процедуру замены окна:

procedure TFormWrapper.NewWindowProc(var Message: TMessage);
begin
  //test for and respond to the messages of interest
  FOriginalWindowProc(Message);
end;
7 голосов
/ 06 января 2012

Вот более полный пример решения, предоставленного Дэвидом:

private
  { Private declarations }
  SaveProc : TWndMethod;
  procedure CommonWindowProc(var Message: TMessage);

...

procedure TForm1.Button1Click(Sender: TObject);
var
  f : tForm2;
begin
  f := tForm2.Create(nil);
  SaveProc := f.WindowProc;
  f.WindowProc := CommonWindowProc;
  f.Show;
end;

procedure TForm1.CommonWindowProc(var Message: TMessage);
begin
  case Message.Msg of
    WM_SIZE : Memo1.Lines.Add('Resizing');
    WM_CLOSE : Memo1.Lines.Add('Closing');
    CM_MOUSEENTER : Memo1.Lines.Add('Mouse enter form');
    CM_MOUSELEAVE : Memo1.Lines.Add('Mouse leaving form');
    // all other messages will be available as needed
  end;
  SaveProc(Message); // Call the original handler for the other form
end;
1 голос
/ 05 января 2012

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

0 голосов
/ 07 января 2012

Другой вариант - создать TApplicationEvents и назначить обработчик для события OnMessage. Один раз, если он сработал, используйте функцию FindControl и Msg.hWnd, чтобы проверить, является ли он типом tform, и делайте то, что вы когда-либо хотите, без подключения

0 голосов
/ 06 января 2012

Использование сообщений Windows действительно может достичь fine granularity (да, это часть ваших требований!), Но в некоторых случаях, когда достаточно полагаться только на VCL Event Framework, можно предложить аналогичное решение:

unit Host;

interface

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

type
  THostForm = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    FFormResize: TNotifyEvent;
    FFormActivate: TNotifyEvent;
    FFormDeactivate: TNotifyEvent;
    FFormDestroy: TNotifyEvent;

    procedure _FormResize(Sender: TObject);
    procedure _FormActivate(Sender: TObject);
    procedure _FormDeactivate(Sender: TObject);

    procedure InternalEventHandlerInit(const AForm:TForm);
  public
    procedure Log(const Msg:string);
    procedure Logln(const Msg:string);
  end;

var
  HostForm: THostForm;

implementation

{$R *.dfm}

procedure THostForm.Button1Click(Sender: TObject);
var
  frm: TForm;
begin
  frm := TForm.Create(nil);
  frm.Name := 'EmbeddedForm';
  frm.Caption := 'Embedded Form';
  //
  InternalEventHandlerInit(frm);
  //
  Logln('<'+frm.Caption+'> created.');
  //
  frm.Show;
end;


procedure THostForm.InternalEventHandlerInit(const AForm: TForm);
begin
  FFormResize := AForm.OnResize;
  AForm.OnResize := _FormResize;
  //
  FFormActivate :=  AForm.OnActivate;
  AForm.OnActivate := _FormActivate;
  //
  FFormDeactivate :=  AForm.OnDeactivate;
  AForm.OnDeactivate := _FormDeactivate;
end;

procedure THostForm.Log(const Msg: string);
begin
  Memo1.Lines.Add(Msg);
end;

procedure THostForm.Logln(const Msg: string);
begin
  Memo1.Lines.Add(Msg);
  Memo1.Lines.Add('');
end;

procedure THostForm._FormActivate(Sender: TObject);
begin
  Log('Before OnActivate <'+(Sender as TCustomForm).Caption+'>');
  //
  if Assigned(FFormActivate) then
    FFormActivate(Sender) // <<<
  else
    Log('No OnActivate Event Handler attached in <'+(Sender as TCustomForm).Caption+'>');
  //
  Logln('After OnActivate <'+(Sender as TCustomForm).Caption+'>');
end;

procedure THostForm._FormDeactivate(Sender: TObject);
begin
  Log('Before OnDeactivate <'+(Sender as TCustomForm).Caption+'>');
  //
  if Assigned(FFormDeactivate) then
    FFormDeactivate(Sender)
  else
    Log('No OnDeActivate Event Handler attached in <'+(Sender as TCustomForm).Caption+'>');
  //
  Logln('After OnDeactivate <'+(Sender as TCustomForm).Caption+'>');
end;

procedure THostForm._FormResize(Sender: TObject);
begin
  Log('Before OnResize <'+(Sender as TCustomForm).Caption+'>');
  //
  if Assigned(FFormResize) then
    FFormResize(Sender)
  else
    Log('No OnResize Event Handler attached in <'+(Sender as TCustomForm).Caption+'>');
  //
  Logln('After OnResize <'+(Sender as TCustomForm).Caption+'>');
end;

end.
...