开发者

Handle WM_SetFocus or WM_KillFocus on Delphi

I need to handle WM_SetFocus or WM_KillFocus on delphi application , i wrote a message handler like this :

Procedure Focus(var Msg: TWMSetFocus); message WM_SetFocus;

but it doesn't work & don,t fire the message handler when WM_SetFocus arrived , after that i wrote a Application Message Handler but against it doesn,t wo开发者_StackOverflow社区rk !

I think this messages send to control directly , is it true ?

Any one can help me to do this ?


This answer assumes you want the messages to be received by controls on a form.

These messages are non-queued and are sent directly to the control. That explains why your two attempts to receive them have failed.

The only way to receive them is through the window procedure of the control. You have the following options.

  1. Subclass the control and handle the message. This is perhaps most easily done with and interposer class.
  2. Use the WindowProc property of the control to replace the window procedure without deriving a new class.

You might find that TForm.SetFocusedControl could help. It is called in response to a control receiving WM_SetFocus messages, as well as being called in some other situations (see the VCL code for details).

Option 1: Interposer

unit uWindowProc;

interface

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

type
  TEdit = class(StdCtrls.TEdit)
  protected
    procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
  end;

  TMyForm = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
  end;

var
  MyForm: TMyForm;

implementation

{$R *.dfm}

{ TEdit }

procedure TEdit.WMSetFocus(var Message: TWMSetFocus);
begin
  inherited;
  Beep;
end;

end.

Option 2: WindowProc

unit uWindowProc;

interface

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

type
  TMyForm = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    procedure FormCreate(Sender: TObject);
  private
    FOriginalWindowProc: TWndMethod;
    procedure NewWindowProc(var Message: TMessage);
  end;

var
  MyForm: TMyForm;

implementation

{$R *.dfm}

procedure TMyForm.FormCreate(Sender: TObject);
begin
  FOriginalWindowProc := Edit1.WindowProc;
  Edit1.WindowProc := NewWindowProc;
end;

procedure TMyForm.NewWindowProc(var Message: TMessage);
begin
  if Message.Msg=WM_SETFOCUS then
    Beep;
  FOriginalWindowProc(Message);
end;

end.


@Mojtaba - whether or not a message is sent directly to the control depends on what type of control it is.

As Andrei K suggested, a message is sent directly only to controls descended from TWinControl - there are other controls that are descended from TControl but they are not TWinControls. For example, TLabel is not descended from TWinControl, but TPanel is.

For a control that's not a TWinControl, the message is sent to the Delphi application's default message handler (generally the application's 'main form' message handler) which handles the message internally, depending on the message content.

See:

TWinControl: http://docwiki.embarcadero.com/VCL/en/Controls.TWinControl

TLabel: http://docwiki.embarcadero.com/VCL/en/StdCtrls.TLabel

TPanel: http://docwiki.embarcadero.com/VCL/XE/en/ExtCtrls.TPanel


Or you can use this wich works on freepascal too

var
  Form1: TForm1;
  OldProc : Pointer;
  counter : Integer = 0;
implementation

{$R *.dfm}

function WndProc1(hw:HWND;Msg:Cardinal;wparam:WPARAM;lparam:LPARAM):LResult;stdcall;
begin
  if Msg = WM_SETFOCUS then
  begin
    Inc(counter);
    Form1.Caption:=IntToStr(counter);
  end;
  Result := CallWindowProc(oldProc,hw,Msg,wparam,lparam);
end;

procedure TForm1.FormShow(Sender: TObject);
var
newproc:Pointer;
begin
  DWORD(OldProc) := GetWindowLong(Edit1.Handle,GWL_WNDPROC);
  newproc := @WndProc1;
  SetWindowLong(Edit1.Handle,GWL_WNDPROC,Integer(newproc));
end;
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜