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

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

フォームの外部で作業するよりも優れた解決策は、すべてのフォームを、機能を実装する共通のベースフォームから派生させることです。フォームイベントハンドラーは、このコードを追加するのに最適な場所ですが、すべてを祖先フォームで記述します。子孫フォームは引き続きフォームイベントを使用でき、イベントハンドラーのどこかで継承されたものを常に呼び出す限り、祖先コードは引き続き実行されます。

于 2012-01-05T14:17:29.687 に答える
1

もう1つのオプションは、TApplicationEventsを作成し、OnMessageイベントにハンドラーを割り当てることです。起動したら、FindControl関数とMsg.hWndを使用して、それがtformタイプであるかどうかを確認し、フックインなしで好きなことを実行します

于 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 に答える