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.
- Subclass the control and handle the message. This is perhaps most easily done with and interposer class.
- 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;
精彩评论