připraveno pro cvičení 11. října

Kontrola údajů v editačním poli

Kontrola správnosti údajů zadávaných uživatelem programu do formuláře je jednou ze základních, rutinních činností, které jsou součástí obsluhy téměř každého formuláře. Provádí se minimálně na čtyřech úrovních:

U databázových aplikací se často pracuje ještě s kontrolou při zápisu do databáze, a to jak na úrovni aplikace, tak i na úrovni databáze. Připomínám, že v řadě případů se snažíme volit takové ovládací prvky, které z principu neumožňují chybné zadání - volby, přepínače, výběr z připraveného menu apod.

Podíváme se zde na některé problémy kontroly zadávaných údajů, především ve vztahu k uživateli programu. Jako příklad použijeme ve všech případech kontrolu na zadání celého čísla.

Připravte si pro toto procvičení nový projekt - jako základ vezměte již dříve použité téměř prázdné hlavní okno, z něhož se zobrazuje druhé, modální okno. (Modálním oknům se často říká dialogová, i když to není zcela přesné.) Do tohoto dialogu umístěte čtyři (stejná) editační pole - objekty typu TEdit a dvě tlačítka pro ukončení dialogu OK a Cancel (typu TButton nebo jednodušeji TBitBtn z palety Additional).

K těmto editačním polím postupně přidávejte jako události následující kontroly na to, zda uživatel skutečně zapisuje do editačního pole číselnou hodnotu.

Filtrace kláves

Základní schema je následující a zapisujeme ho do obsluhy události OnKeyPress:

if not (Key in ['0'..'9',#8]) then begin
   Key:=#0;MessageBeep(0);
end;

Stisknutá klávesa je uložena v parametru Key; obsluha události může tuto hodnotu změnit. Nezapomeňte do seznamu kláves zahrnout minimálně Backspace, příp. znaménko, mezeru apod. Tuto kontrolu lze "obelstít" přenesením údajů přes schránku.

Průběžná kontrola

Průběžnou kontrolu hodnoty můžeme umístit do obsluhy události OnChange. Poměrně primitivní kontrola využívá standardní funkce Val:

{ Získej text z editačního pole }
Val(Edit2.Text, I, Code);
{ Chyba? }
if Code <> 0 then
   MessageDlg('Chyba na pozici: ' + IntToStr(Code), mtWarning, [mbOk], 0);

Obecně tento způsob kontroly není příliš vhodný. Kromě toho lze pole i formulář opustit i s nesprávně zadanou hodnotou.

Kontrola při opuštění pole

Umísťuje se do obsluhy události OnExit, jinak použijeme obdobné řešení jako v předcházejícím bodě.

{ Získej text z editačního pole }
Val(Edit3.Text, I, Code);
{ Chyba? }
if Code <> 0 then begin
   MessageDlg('Chybná hodnota v editačním poli', mtWarning, [mbOk], 0);
   Edit3.SetFocus;
end;

Tento způsob kontroly je třeba považovat za základní. Při nalezení chyby je žádoucí vrátit kurzor do chybně vyplněného pole - voláním metody SetFocus tohoto editačního pole. Je však třeba dát pozor na to, aby uživatel měl možnost zjistit alespoň nějakou "přijatelnou" hodnotu, jinak není možné tento formulář opustit.

Všechny kontroly

Vytvořte ještě čtvrté editační pole, kde použijete současně všechny výše zmíněné kontroly. Pokuste se to ale udělat tak, abyste nemuseli psát příliš mnoho dalšího programového kódu.

Návod: Jako obsluhu příslušných událostí použijte již existující obsluhy událostí - místo zápisu nové obsluhy vyberte v Inspektoru objektů již existující obsluhu z menu. Tyto existující obsluhy je třeba upravit tak, aby odkaz na konkrétní editační pole (tj. Edit1 apod.) byl nahrazen odkazem na "zasílatele" příslušné zprávy (např. o tom, že nastala změna v editačním poli), který je obsažen v parametru Sender většiny událostí. Používáme konstrukci (Sender as TEdit).Text, protože parametr Sender je typu TObject a většina použitých vlastností (např. Text) je definována až u konkrétního ovládacího prvku.

Kontrola při opuštění formuláře

Toto je druhá základní kontrola, při které lze zkontrolovat i logickou návaznost údajů zadávaných do jednotlivých editačních polí. Používá nám již známou událost OnCloseQuery.

if Save then
try
   a:=StrToInt(Edit1.Text)+StrToInt(Edit2.Text)+StrToInt(Edit3.Text)+StrToInt(Edit4.Text);
   if a<50 then begin
      ShowMessage('Součet zadaných hodnot musí být alespoň 50');
      CanClose:=false;
   end;
   except on EConvertError do begin
      CanClose:=false; ShowMessage('Něco je špatně');
      end;
   end;

Běžně chceme uživateli umožnit i opuštění formuláře bez uložení - když uživatel nemá data nebo si s formulářem neví rady. Zavedeme dvě tlačítka pro ukončení a rozlišíme je od sebe přiřazením hodnoty logické proměnné Save - tuto proměnnou definujeme většinou jako privátní položku příslušného okna. Přidejte ještě dotaz potvrzující opuštění formuláře bez uložení dat - využijte vlastnosti Modified editačního pole.

Poznámka: Standardní mechanismus pro rozlišení toho, kterým tlačítkem uživatel ukončil dialog, je přes vlastnost ModalResult prvku typu TButton - tato hodnota je vrácena jako výsledek funkce ShowModal, kterou zobrazujeme dialog. Tuto hodnotu se však dozvíme až po vyvolání funkce ShowModal a nemůžeme jí tedy přímo využít už při provádění události OnCloseQuery.

Kromě konstrukcí známých z dřívějška jsme na ukázku použili konstrukci try ... except on ... end, která využívá mechanismus tzv. výjimky, s nimiž se seznámíme příště. Mechanismus je zhruba takový, že při chybě v části try se předá řízení na část except on, kde je obsluha (předpokládaných) chyb. Zbývající část v příkazu try se již neprovádí.