Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 143. - co bylo aktivní dřív?

Jan Šindelář 16.6.2004

Po hrátkách s grafikou tu máme tentokrát něco méně vizuálního. Ukážeme si, jak vyřešit jeden zdánlivě zapeklitý problém. Jak zjistit, který objekt formuláře byl aktivní před tím, než jsme aktivovali objekt jiný?

Představte si modelovou situaci. Na formuláři máme několik EditBoxů a tlačítko. Chceme, aby po stisku tlačítka došlo k nějaké akci v závislosti na tom, který EditBox byl předtím vybrán (který měl focus). Problém je v tom, že jakmile stiskneme tlačítko, v ten okamžik dostane focus právě toto tlačítko a my už pak nejsme běžným způsobem schopni zjistit, který objekt měl focus předtím.

Řešení je poměrně snadné. Vytvoříme si dvě proměnné wcActive a wcPrevious typu TWinControl. Jedna bude evidovat aktuální aktivní objekt, druhá zase ten předchozí. V okamžiku změny focusu se pak obsah těchto proměnných aktualizuje tím, že se hodnoty vymění, resp. obsah wcActive bude uložen do wcPrevious a do wcActive uložíme aktuální aktivní objekt.

Jak ale zjistíme, že ke změně focusu došlo? Využijeme událost OnActiveControlChange objektu TScreen. Tento objekt je vytvářen automaticky spolu s aplikací a událost je vyvolána právě při aktivního objektu. Na tuto událost "navěsíme" vlastní proceduru ActiveControlChanged, kde budeme provádět aktualizaci obsahu zmiňovaných proměnných.

Na formulář tedy umístíme dva EditBoxy, jedno tlačítko a ještě nějaký další objekt (v našem případě CheckBox). Zdrojový kód pak vypadá takto:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    CheckBox1: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    wcActive, wcPrevious : TWinControl;
  public
    { Public declarations }
    procedure ActiveControlChanged(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Screen.OnActiveControlChange := ActiveControlChanged;
end;

procedure TForm1.ActiveControlChanged(Sender: TObject) ;
begin
  wcPrevious := wcActive;
  wcActive := ActiveControl;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Screen.OnActiveControlChange := nil;
end;

procedure TForm1.Button1Click(Sender: TObject) ;
begin
  if TEdit(wcPrevious) = Edit1 then ShowMessage(`Edit1 mel focus`)
  else if TEdit(wcPrevious) = Edit2 then ShowMessage(`Edit2 mel focus`)
      else ShowMessage(`Focus mel jiny objekt`);
end;

end.

Po stisknutí tlačítka pak dojde k jednoduchému vyhodnocení podle obsahu proměnné wcPrevious. Soustředíme se zde pouze na objekty typu TEdit a podle jejich názvu pak zjistíme, kdo měl focus před právě aktivním objektem.