7

自分自身に他のコンポーネントを登録し、登録されたコンポーネントの 1 つがフォーカスを受け取るかどうかを検出するコンポーネントを作成する必要があります。

たとえば、私のコンポーネントでは、 TFocusObserver3 つのオブジェクトを登録しています。

FocusObserver.Register(MyMemo);
FocusObserver.Register(MyButton);
FocusObserver.Register(MyEdit);

そして、このコンポーネントの 1 つがフォーカスを受け取ると、FocusObserver何らかの通知イベントが発生します。

フォーカスの変化を検出する方法を探していましたが、それTScreen.OnActiveControlChangeがまさに必要なものであることがわかりました。したがって、私のコンポーネントはこのイベントに接続できます。問題は、複数のTFocusObserverが存在するか、後で他の人が使用したくなる可能性があることですOnActiveControlChange

これは、マルチキャスト イベントの恩恵を受ける時間です。問題はすぐに解決されます。

これを解決する方法を考えていましたが、現在2つのアイデアがあります。

  1. どういうわけか拡張してTScreen、もう1つのイベントを提供します。
  2. OnActiveControlChange他のオブジェクトに接続して 1 つのマルチキャスト イベントを公開する中間オブジェクトを導入します。

ソースを簡単に調べた後、最初のアイデアを使用してそれを解決する方法が明確にわかりません.2番目のアイデアには、誰かが別のメソッドを簡単に割り当てることができOnActiveControlChange、すべてがバラバラになるという欠点があります。

いくつかの提案に感謝します。

4

3 に答える 3

9

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です。

2 番目のアプローチ:

コントロールを登録するときは、それを置き換えます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;

どのように聞こえますか?

于 2012-06-25T13:14:46.193 に答える
0

You could remember the value of Screen.OnActiveControlChange just before your component replaces it.

FOnActiveControlChange := Screen.OnActiveControlChange;
Screen.OnActiveControlChange = MyOnActiveControlChange;

Then in xxx.MyOnActiveControlChange

begin
  // what you wanted to do here
  ...

  if Assigned( FOnActiveControlChange) then begin

    // Forward to previous subscriber.
    FOnActiveControlChange( Sender, ...);
end;

But this only works if you're in control of the application, if someone else uses your component and he/she has other components that also use OnActiveControlChange things might go wrong.

于 2012-06-25T12:03:51.437 に答える