我需要编写一个组件,该组件将在其他组件中注册,并检测其中一个注册组件是否获得焦点。
例如,对于组件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
。第二种方法:
注册控件时,将其替换为
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;
听起来如何?