7

我正在做一些需要监控许多表格的事情。从表单外部,并且不将任何代码放入表单内,我需要以某种方式从这些表单中捕获事件,最有可能以 Windows 消息的形式。但是,您将如何从与其相关的类之外捕获 Windows 消息?

我的项目有一个对象,它包装了它正在监视的每个表单,我认为这个处理将进入这个对象。本质上,当我创建要监视的表单时,我会创建一个相应的对象,该对象又会添加到所有已创建表单的列表中。最重要的是,当该表单关闭时,我必须知道这样才能从列表中删除该表单的包装对象。

这些事件包括:

  • 最小化
  • 最大化
  • 恢复
  • 聚焦/聚焦

我不想要的:

  • 用于此处理的任何表单或表单单元内的任何代码
  • 从任何自定义基本表单继承表单
  • 使用表单的事件,例如OnClose因为它们将用于其他目的

我想要什么:

  • 处理这些事件的 Windows 消息
  • 关于如何从课堂外获取 Windows 消息的任何提示
  • 我需要收听哪些 Windows 消息

用相同的信息但不同的方法重写了问题

4

5 回答 5

9

您需要侦听传递到表单的特定 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;
于 2012-01-05T14:18:55.783 回答
7

这是大卫提供的解决方案的更完整示例:

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;
于 2012-01-06T00:58:41.807 回答
1

比尝试在表单之外工作更好的解决方案是使每个表单都从实现该功能的通用基本表单下降。表单事件处理程序正是添加此代码的正确位置,但您将其全部编写在祖先表单中。任何后代表单仍然可以使用表单事件,只要它们总是在事件处理程序中的某个地方调用继承,祖先代码仍然会执行。

于 2012-01-05T14:17:29.687 回答
1

另一种选择是创建 TApplicationEvents 并将处理程序分配给 OnMessage 事件。一旦它被触发,使用 FindControl 函数和 Msg.hWnd 来检查它是否是 tform 类型,并在没有 hookin 的情况下做任何你想做的事情

于 2012-01-07T19:55:46.263 回答
0

使用 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.
于 2012-01-06T12:10:17.247 回答