在Delphi上处理WM_SetFocus或WM_KillFocus

时间:2011-05-28 04:14:23

标签: delphi

我需要在delphi应用程序上处理WM_SetFocus或WM_KillFocus,我写了一个这样的消息处理程序:

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

但它不起作用&不要在WM_SetFocus到达时触发消息处理程序,之后我写了一个应用程序消息处理程序,但反对它不起作用!

我认为此消息直接发送给控件,是真的吗?

任何人都可以帮我这么做吗?

3 个答案:

答案 0 :(得分:3)

此答案假设您希望表单上的控件接收消息。

这些消息未排队,直接发送给控件。这就解释了为什么你的两次尝试都失败了。

接收它们的唯一方法是通过控件的窗口过程。您有以下选择。

  1. 对控件进行子类化并处理消息。这可能是使用和插入者类最容易完成的。
  2. 使用控件的WindowProc属性替换窗口过程而不派生新类。
  3. 您可能会发现TForm.SetFocusedControl可以提供帮助。它被调用以响应接收WM_SetFocus消息的控件,以及在其他一些情况下被调用(有关详细信息,请参阅VCL代码)。

    选项1:插入器

    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.
    

    选项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.
    

答案 1 :(得分:0)

@Mojtaba - 是否将消息直接发送到控件取决于它是什么类型的控件。

正如Andrei K建议的那样,消息只会直接发送给来自TWinControl的控件 - 还有其他控件来自TControl,但它们不是TWinControls。例如,TL​​abel不是TWinControl的后代,而是TPanel。

对于不是TWinControl的控件,消息将发送到Delphi应用程序的默认消息处理程序(通常是应用程序的“主窗体”消息处理程序),该处理程序在内部处理消息,具体取决于消息内容。

请参阅:

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

答案 2 :(得分:0)

或者你可以使用这个也适用于freepascal

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;