Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I catch certain events of a form from outside the form?

I'm working on something which will require monitoring of many forms. From outside the form, and without putting any code inside the form, I need to somehow capture events from these forms, most likely in the form of windows messages. But how would you capture windows messages from outside the class it's related to?

My project has an object which wraps each form it is monitoring, and I presume this handling will go in this object. Essentially, when I create a form I want to monitor, I create a corresponding object which in turn gets added to a list of all created forms. Most importantly, when that form is closed, I have to know so I can remove this form's wrapper object from the list.

These events include:

  • Minimize
  • Maximize
  • Restore
  • Close
  • Focus in/out

What I DON'T want:

  • Any code inside any forms or form units for this handling
  • Inheriting the forms from any custom base form
  • Using the form's events such as OnClose because they will be used for other purposes

What I DO want:

  • Handling of windows messages for these events
  • Any tips on how to get windows messages from outside the class
  • Which windows messages I need to listen for

Question re-written with same information but different approach

like image 228
Jerry Dodge Avatar asked Jan 05 '12 14:01

Jerry Dodge


Video Answer


2 Answers

You need to listen for particular windows messages being delivered to the form. The easiest way to do this is to assign the WindowProc property of the form. Remember to keep a hold of the previous value of WindowProc and call it from your replacement.

In your wrapper object declare a field like this:

FOriginalWindowProc: TWndMethod;

Then in the wrapper's constructor do this:

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

Finally, implement the replacement window procedure:

procedure TFormWrapper.NewWindowProc(var Message: TMessage);
begin
  //test for and respond to the messages of interest
  FOriginalWindowProc(Message);
end;
like image 132
David Heffernan Avatar answered Oct 01 '22 15:10

David Heffernan


Here's a more complete example of the solution that David Provided:

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;
like image 26
Mike W Avatar answered Oct 01 '22 13:10

Mike W