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

Tipy a triky v Delphi, díl 132. - automatické odklepnutí dialogů

Jan Šindelář - 31.3.2004

Jednoduchá dialogová okna typu Ano/Ne/Storno jsou obvyklým způsobem komunikace s uživatelem, pokud se program potřebuje rozhodnout či ujistit o další činnosti. Někdy ale nastává s těmito dialogy problém. Některé aplikace jako například antiviry, různé „kontroly“ disků a podobně jsou často spouštěny automaticky v zadaný čas v rámci údržby systému a je žádoucí, aby také automaticky svou činnost ukončily zcela bez zásahu uživatele. Problém může nastat právě v okamžiku, kdy program zobrazí modální dialogové okno, čekající na vstup uživatele, protože bez jeho reakce se dál nehne. Celý automatický proces je tak nabourán jenom tím, že je potřeba "odkliknout" jeden dialog.

Řeší se to tedy obvykle tak, že se dialog po nějakém časovém intervalu uzavře sám, přičemž je zvolena automaticky doporučená, tj. méně "nebezpečná" volba, kterou by si uživatel stejně na 90% rovněž vybral. Nemusí ani jít o nějaké nebezpečné funkce, většinou se jedná jen o dialog informační, který uživateli říká, že daný proces byl v pořádku dokončen a program se chystá končit. Samozřejmě by šlo podobnou věc řešit velmi snadno tím, že bychom podobný informační a rádoby zbytečný dialog prostě v aplikaci vynechali, ale jak by se nám líbilo, kdyby se po ukončení antivirového testu nic nezobrazilo? V takovém případě nemáme jistotu, jestli aplikace během své činnosti "nespadla" nebo normálně skončila. Proto je lepší použít časový dialog.

Cílem dnešního příkladu tedy bude po stisknutí tlačítka zobrazit standardní dialogové okno, které bude navíc obsahovat ukazatel průběhu. Po deseti sekundách, jejichž ubíhání bude indikováno právě zmiňovaným ukazatelem, dojde k automatickému uzavření dialogu.

Na prázdný formulář umístíme tlačítko a Timer, který se nám postará o čas. Vše ostatní už probíhá dynamicky za běhu programu, kdy vygenerujeme příslušný dialog a přidáme do něj ProgressBar. Poté nastavíme základní vlastnosti dialogu (titulek, text, časový interval) a dialog modálně zobrazíme, přičemž zároveň spustíme Timer. V jeho události pak hlídáme, jestli již nevypršel čas a pokud ano, vrátíme ModalResult zobrazeného dialogu jako Cancel. Všimněte si, že počet sekund není nastaven přímo jako hodnota Timeru (zde je nastavena jedna sekunda), ale využíváme k tomu hodnotu vlastnosti Tag našeho dialogu, kam na začátku vložíme hodnotu 10 a při každém kroku pak kontrolujeme pozici ProgressBaru s touto hodnotou. Maximální hodnota ProgressBaru se totiž převezme právě a hodnoty položky Tag našeho MessageDialogu.

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Timer1: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject) ;
var
  AMsgDialog: TForm;
  AProgressBar: TProgressBar;
  ATimer: TTimer;
begin
  AMsgDialog := CreateMessageDialog(`Ukoncit program?`, mtWarning, [mbYes, mbNo]);
  AProgressBar := TProgressBar.Create(AMsgDialog);
  ATimer := TTimer.Create(AMsgDialog);
  with AMsgDialog do
    try
      Tag := 10;
      Caption := `Automaticke ukonceni`;
      Height := 150;
      with AProgressBar do
        begin
          Name := `Progress`;
          Parent := AMsgDialog;
          Max := AMsgDialog.Tag;
          Step := 1;
          Top := 100;
          Left := 8;
          Width := AMsgDialog.ClientWidth - 16;
        end;
      with ATimer do
        begin
          Interval := 1000;
          OnTimer := Timer1Timer;
        end;
      case ShowModal of
        ID_YES: ShowMessage(`Bylo stisknuto "Ano"`);
        ID_NO: ShowMessage(`Bylo stisknuto "Ne"`);
        ID_CANCEL: ShowMessage(`Cas vyprsel!`);
      end;
    finally
      ATimer.OnTimer := nil;
      Free;
    end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  aPB : TProgressBar;
begin
  if NOT (Sender is TTimer) then Exit;
  if ((Sender as TTimer).Owner) is TForm then
    with ((Sender as TTimer).Owner) as TForm do
      begin
        aPB := TProgressBar(FindComponent(`Progress`)) ;
        if aPB.Position >= aPB.Max then ModalResult := mrCancel
                                  else aPB.StepIt;
      end;
end;
end.

Dialog si samozřejmě můžete upravit přesně podle vašich požadavků a kromě ProgressBaru můžete třeba přidat malé vylepšení a nechat zobrazovat i zbývající čas do automatického uzavření.