我需要编写一个组件,它将在其他组件中注册,并检测其中一个注册组件是否获得焦点.
例如,对于我的组件TFocusObserver,我正在注册三个对象.
FocusObserver.Register(MyMemo); FocusObserver.Register(MyButton); FocusObserver.Register(MyEdit);
现在,如果其中一个组件获得焦点,那么FocusObserver会启动一些通知事件.
我正在寻找如何检测焦点变化,并发现TScreen.OnActiveControlChange正是我需要的.所以我的组件可以连接到这个事件.问题是可能存在多个TFocusObserver,或者以后的somoene可能希望使用OnActiveControlChange.
这是我将从多播事件中受益的时间 – 它将立即解决我的问题.
我在想如何解决这个问题,目前我有两个想法:
>以某种方式扩展TScreen,这样它将为我提供一个更多的活动.
>引入一个中间对象,它将连接到OnActiveControlChange并为其他对象公开一个多播事件.
在简要介绍一下这些来源后,我不清楚如何通过使用第一个想法解决它,第二个想法的缺点是有人可以简单地为OnActiveControlChange指定另一个方法,并且所有内容都会崩溃.
会对一些建议表示感谢.
解决方法
如果你的focusObserver类可以是TWinControl的后代,那么你可以这样做:
TFocusObserver = class( TWinControl ) procedure CMFocusChanged(var Message: TCMFocusChanged); message CM_FOCUSCHANGED; end;
和
procedure TFocusObserver.CMFocusChanged(var Message: TCMFocusChanged); var LControl: TWinControl; begin LControl := TWinControl(Message.Sender); if LControl <> nil then begin form1.Caption := lControl.Name; end; end;
这里的主要想法是观看CM_FOCUSCHANGED.
第二种方法:
注册Control时,将其替换为WindowProc.这是一个小代码片段:
TRegisteredComp = class private fControl: TControl; fowndproc: TWndMethod; procedure HookWndProc(var Message: TMessage); public constructor Create( c: TControl ); destructor Destroy; override; end; TFocusObserver = class private l: TList; public constructor Create; destructor Destroy; override; procedure reg( c: TControl ); end;
并在实施中:
constructor TFocusObserver.Create; begin l := TList.Create; end; destructor TFocusObserver.Destroy; var i: integer; begin for i := 0 to l.Count - 1 do TRegisteredComp(l[i]).Free; l.Free; inherited; end; procedure TFocusObserver.reg( c: TControl ); var rc: TRegisteredComp; begin rc := TRegisteredComp.Create( c ); l.Add( rc ); end; constructor TRegisteredComp.Create(c: TControl); begin fControl := c; fowndproc := c.WindowProc; c.WindowProc := HookWndProc; end; destructor TRegisteredComp.Destroy; begin fControl.WindowProc := fowndproc; inherited; end; procedure TRegisteredComp.HookWndProc(var Message: TMessage); begin if ( Message.Msg = CM_FOCUSCHANGED ) and ( TControl(Message.LParam) = fControl ) then form1.ListBox1.Items.Add( 'focused: ' + fControl.Name ); fowndproc( Message ); end;
而不仅仅是注册你想要观看的控件,例如:
procedure TForm1.FormCreate(Sender: TObject); var i: Integer; begin fo := TFocusObserver.Create; for i := 0 to ControlCount - 1 do fo.reg( Controls[i] ); end;
听起来怎么样?