我正在研究需要监控多种形式的事情。从表单外部,并且不在表单中放置任何代码,我需要以某种方式从这些表单中捕获事件,最有可能以Windows消息的形式。但是你如何捕获与它相关的类外的Windows消息?
我的项目有一个对象,它包装了它正在监视的每个表单,我假设这个处理将进入这个对象。基本上,当我创建一个我想要监视的表单时,我创建了一个相应的对象,该对象又被添加到所有已创建表单的列表中。最重要的是,当该表单关闭时,我必须知道所以我可以从列表中删除此表单的包装器对象。
这些事件包括:
我不想要的东西:
OnClose
,因为它们将用于其他目的我想要的是什么:
使用相同信息但不同方法重写的问题
答案 0 :(得分: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;
答案 1 :(得分:7)
以下是David提供的解决方案的更完整示例:
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;
答案 2 :(得分:1)
比尝试在表单之外工作更好的解决方案是使每个表单都从实现该功能的公共基本表单下降。表单事件处理程序正是添加此代码的正确位置,但您将以祖先形式编写它们。任何后代表单仍然可以使用表单事件,只要它们始终在事件处理程序中的某处继承,祖先代码仍将执行。
答案 3 :(得分:0)
使用Windows消息确实可以达到fine granularity
(是的,这是您的部分要求!)但在某些仅依赖VCL Event Framework
的用户情况下,可以建议类似的解决方案:< / p>
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.
答案 4 :(得分:0)
另一个选项是创建TApplicationEvents并为OnMessage事件分配处理程序。一旦它被触发,使用FindControl函数和Msg.hWnd来检查它是否是tform类型并在没有hookin的情况下做你想做的事