2011-05-28 54 views
0

我需要處理WM_SETFOCUS或WM_KILLFOCUS在Delphi應用程序,我寫了這樣一個消息處理程序:處理WM_SETFOCUS或WM_KILLFOCUS德爾福

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

,但它不工作&別,叔火消息處理程序時WM_SetFocus到達後,我寫了一個應用程序消息處理程序,但對它沒有工作!

我覺得這個消息直接發送來控制,這是真的嗎?

任何人都可以幫助我做到這一點?

+0

你爲什麼寫了一個消息處理程序?它是TWinControl的下降嗎? – 2011-05-28 06:01:24

+0

等一下!再次,您希望哪些窗口收到這些通知? – 2011-05-28 06:46:49

+2

該控件的'OnEnter' /'OnExit'將不起作用? – 2011-05-28 08:27:22

回答

2

此答案假設您希望消息被窗體上的控件接收。

這些消息是非排隊的,並直接發送到控件。這就解釋了爲什麼你的兩次嘗試接收它們失敗了。

接收它們的唯一方法是通過控件的窗口過程。您有以下選項。

  1. 控制子類並處理消息。這可能是最容易完成的和插入類。
  2. 使用控件的WindowProc屬性替換窗口過程而不派生新類。

您可能會發現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. 
+0

但是他控制了控件的「子類」(可能是任何類型的控件):他爲該類添加了自己的消息處理程序。每個TObject後代自動調用消息處理程序,但是從TControl開始,消息只有在WndProc允許它們通過時纔會到達處理程序。所以如果他的處理程序從不開火,我想他或者別的WndProc會阻止這個信息。這就是爲什麼我認爲「控制」是MainForm的原因。 – NGLN 2011-05-28 07:15:41

+1

@NGLN我敢打賭,OP的問題中的消息處理程序與窗體而不是控件相關聯。 – 2011-05-28 07:16:47

+0

我的觀點正確:他在他的表格上嘗試這一點。我甚至認爲這是設計。 – NGLN 2011-05-28 07:24:21

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

+0

更正:如果消息未排隊(即,使用SendMessage發送),則直接向控件發送消息。如果郵件是排隊郵件(即使用PostMessage發佈),則通過郵件隊列發送郵件(對Application.OnMessage可見)。 – 2011-05-28 06:27:50

+0

更正2:非窗口控件不會收到輸入焦點,因此甚至從未與這些消息關聯 – 2011-05-28 06:39:50

+0

@David - 1)「消息直接發送到控件...」 - 我假設您正在討論TWinControls。 2)「非窗口控件沒有獲得輸入焦點」:我一般說話,但是我遵循你的優越知識,在非窗口控件的情況下,焦點消息是不相關的(這非常合理)。我收集OP顯然是在談論一個窗口控件,因爲問題是關於WM_SETFOCUS,WM_KILLFOCUS和setFocus,但也許這不是他們的代碼執行的地方。 – Vector 2011-05-28 07:17:36

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; 
+0

你應該真的把全局變量移動到類 – 2011-05-28 07:20:42

+0

任何特定的原因? – opc0de 2011-05-28 07:21:53

+1

這是行不通的,因爲您正在設置窗體的窗口過程而不是感興趣的控件。這是複製OP已經嘗試過的一種混亂方式。這與重寫TForm1.WndProc並無不同。 – 2011-05-28 07:24:54