Programování v JavaFX: kontrola formátu editačních polí

26. 11. 2015
Doba čtení: 8 minut

Sdílet

Minulý díl byl věnován mazání záznamů pomocí připravené PG funkce. Také jsme se začali věnovat aktualizaci a změnám v tabulkových záznamech postupnou tvorbou pomocných funkcí a procedur. Zahájili jsme prvním krokem kontrolu záznamů před uložením. Dnes si ukážeme další možnosti v této oblasti.

V minulém dílu jsme vyřešili problematiku prázdných editačních polí a na začátek dnešního se budeme věnovat nastavení délky zadávaných textových údajů. V naší zkušební tabulce se tento požadavek týká pouze jednoho jediného pole – retezec (editační pole u_Text). Pole je z definice tabulky nastaveno na maximální délku 32 znaků. My si zde ale ukážeme trochu obecnější řešení. K němu si připravíme novou funkci, která bude mít podobný formát jako ty minulé:

private boolean validLEN(final TextField field, final Integer len){                                     //1
        if(field.getText().length()>len) {                                                   //2
            dialogMessage("Pole " + field.getId() + " je delší než maximum " + len.toString() + " znaků!", "Kontrola editačních polí", 'E'); //3
            field.setText(field.getText().substring(0,len));                                            //4
            setFocus(field);
            return true; }
        else  return false; }

Přes určitou podobnost bude vhodné alespoň část funkce komentovat:

  1. řádek – funkce je opět logická, parametrem je editační pole a také číslená hodnota maximální délky zadávaného textu
  2. řádek – testuje se, jestli je zadaná délka větší než požadovaná maximální
  3. řádek – pokud je text delší, objeví se chybové hlášení
  4. řádek – zadaný text se zprava ořízne na maximální délku. Dál už jsou známé příkazy pro umístění kurzoru a nastavení návratových hodnot funkce

Bylo by samozřejmě také možné použít stejný trik jako ve funkci pro zjištění přítomnosti obsahu editačního pole a přidat widget Label. Kód není třeba uvádět, protože by se také jenom přidal nový parametr do volání funkce a změnil název pole v příkazu pro zobrazení dialogového okna. Pro vyzkoušení funkčnosti nové kontrolní funkce je nutné přidat další řádek do procedury saveUpdate:

else if (validLEN(u_Text, 32)) return;

Formát je opět velmi podobný a parametry jsou také jasné – příslušné editační pole a maximální počet znaků, který smí obsahovat. Pro zkoušku si přeneseme do editačních polí řádek č. 7 a pokusíme se o kontrolu zadání. Do editačního pole u_Text vložíme všechny znaky anglické abecedy a 10 číselných znaků, celkem 36 znaků. Před uložením musíme ještě nastavit nějakou hodnotu do pole Male des., abychom zabránili hlášení o prázdném poli. Příklad zadání je vidět na prvním obrázku v galerii. Pokud klikneme na příslušné tlačítko (Uložit změny), objeví se hlášení, které nám ukazuje druhý obrázek galerie. Po jeho odsouhlasení se objeví stav, který ukazuje třetí obrázek v galerii – zadaný text byl oříznutý o 4 znaky a je na něm „zaparkovaný“ kurzor.

Další součástí kontroly zadávaných údajů by měla být kontrola formátu jednotlivých typů dat. V našem případě si ukážeme kontrolu celých a desetinných čísel a datumů. Začneme tou nejjednodušší variantou, kterou je celé číslo. K jeho kontrole a zobrazení výsledků použijeme dvě funkce. První provede kontrolu, jestli se jedná o správně zadané celé číslo:

private boolean isInteger(final TextField input) {
        try { Integer.parseInt(input.getText());
            return true; }
        catch (NumberFormatException e) {
            return false; } }

Zde se velmi jednoduše využívá možností a vlastností číselného typu Integer, resp. jeho převod z textového zadání. Podle výsledků se přiřazuje logická návratová hodnota funkce. Druhá funkce zobrazuje výsledek kontroly a nějak na něj reaguje:

private boolean validINT(final TextField field){
        if (!isInteger(field)) {
            dialogMessage("Pole " + field.getId() + " neobsahuje celé číslo!", "Kontrola editačních polí", 'E');
            field.setText("");
            setFocus(field);
            return true; }
        else {
            return false; } }

Obě funkce mají v parametru příslušné editační pole. Pokud se zjistí, že zadaný text neodpovídá formátu celého čísla, tak se zobrazí chybové hlášení, následně se původně zadaný text vymaže a na příslušné editační pole se nastaví kurzor. Samozřejmě se nastaví i příslušné logické návratové hodnoty. Aby bylo možné novou funkci vyzkoušet, musíme opět doplnit příslušnou kontrolní proceduru save_Update o další řádek:

else if (validINT(u_Cele)) return;

Pak už můžeme vyzkoušet funkčnost kontroly tím, že zadáme do editačního pole dva typy „celých čísel“ – čistý text a desetinné číslo. Konkrétně nám to ukazují čtvrtý a pátý obrázek v galerii. Šestý obrázek galerie pak ukazuje chybové hlášení, které se nám při předchozích pokusech objeví. Na sedmém obrázku v galerii je pak vidět prázdné editační pole s kurzorem. Tím můžeme kontrolu celých čísel ukončit a přejít na čísla desetinná. Zde si ukážeme trochu složitější případ, kdy se bude kontrolovat nejen správný formát zadaného čísla, ale také to, aby zadávané číslo nebylo záporné. Kontrola se bude opět skládat ze dvou funkcí, kdy první je velmi podobná té předchozí:

private boolean isDouble(final TextField input) {
        try { Double.parseDouble(input.getText());
            return true; }
        catch (NumberFormatException e) {
            return false; } }

Kód nemá smysl komentovat, protože se od toho minulého liší pouze v použité funkci pro kontrolu zadaného textu. Druhá funkce už ale bude o něco složitější než ta minulá:

private boolean validDBL(final TextField field){
        field.setText(field.getText().replaceFirst(",","."));                               //1
        if (!isDouble(field)) {                                             //2
            dialogMessage("Pole " + field.getId() + " neobsahuje desetinné číslo!", "Kontrola editačních polí", 'E'); //3
            setFocus(field);
            return true;
        } else {
            Double prevod = Double.valueOf(field.getText());                                //4
            if(prevod<0.0) {                                             //5
                dialogMessage("Pole " + field.getId() + " obsahuje záporné číslo!", "Kontrola editačních polí", 'E');    //6
                setFocus(field);
                return true;
            } else {
                Double zustatek = Math.round(prevod * 100) / 100.0;                         //7
                field.setText(zustatek.toString());                                 //8
                return false; } } }

Zde se už stručný komentář vyplatí:

  1. řádek – pokud se v textu najde znak desetinné čárky, nahradí se desetinnou tečkou. Uživatel tedy může používat obě znaménka bez omezení
  2. řádek – pokud není zadané číslo ve správném formátu
  3. řádek – zobrazí se chybové hlášení
  4. řádek – pokud je číslo ve správném formátu, převede se na desetinné
  5. řádek – pokud je číslo menší než 0
  6. řádek – zobrazí se chybové hlášení
  7. řádek – pokud je číslo větší než 0, zaokrouhlí se na dvě desetinná místa
  8. řádek – zaokrouhlené číslo se uloží do příslušného editačního pole

Bylo by samozřejmě možné použít jiné testy a nastavení, ale pro naše ukázkové účely je tento příklad určitě dostatečný. Do procedury save_Update musíme tentokrát přidat dva řádky:

else if (validDBL(u_Desetinne)) return;
else if (validDBL(u_Maledes)) return;

Následně je pak možné vyzkoušet jestli a jak kontrola funguje. Je to velmi obdobné jako u celých čísel, a tak nemá valný smysl zde uvádět příklady a obrázky. Místo toho se raději pustíme do poslední kontroly formátu a to při zadávání data v posledním editačním poli (u_Datum). Daná problematika by se určitě dala řešit pomocí nástrojů samotného frameworku JavaFX. My si ale ukážeme trochu jinou variantu, kde použijeme externí knihovnu. Více o ní se dozvědět a stáhnout si potřebné soubory je možné zde: Joda-Time. Stažení potřebného souboru (joda-time-2.9-dist.tar.gz) je pak možné zde: Joda-Time Github. Stažený archiv si rozbalíme a do adresáře libs přidáme pouze jedinou knihovnu – joda-time-2.9.jar. Bližší podrobnosti si zájemci mohou najít a prostudovat na uvedeném odkazu, takže my se pustíme hned do zkoušky. K tomu účelu si vytvoříme novou jednoduchou proceduru a zkušebně ji navážeme na tlačítko Zrušit změny.

private void isDate() {
        String input = "11.12.2013";                        //1
        LocalDate localDate = null;                     //2
        DateTimeFormatter formatter = DateTimeFormat.forPattern("d.M.yyyy");    //3
        localDate = formatter.parseLocalDate(input);                //4

        System.out.println(input);
        System.out.println(localDate); }

Procedura má několik příkazů včetně zápisu zadání a výsledku do konzole. Některé si podrobněji rozebereme:

  1. řádek – zde je zadání data v našem obvyklém formátu a pro první nástřel samozřejmě správné
  2. řádek – z knihovny Joda-Time deklarujeme příslušnou proměnnou
  3. řádek – z té samé knihovny deklarujeme další proměnnou, která očekává nějaký formát zadaného data
  4. řádek – pomocí deklarovaného formátu převedeme zadání na příslušné datum

Osmý obrázek galerie nám ukazuje, co se v konzole objeví. Pak postupně zkusíme změnit zadání čtyřmi způsoby a na obrázcích 9 – 12 v galerii je vidět, že se to chybami jenom hemží:

11.13.2013
11.xx.2013
31.11.2013
11/12/2013

Pro uživatele nejsou chybové hlášky zrovna moc záživné, takže se je pokusíme odstranit. Proto „obklíčíme“ výkonný příkaz známou smyčkou pro zachytávání výjimek. Jak je patrné z předchozích obrázků, mohou se zde vyskytnou dva různé typy výjimek, a proto musíme zachycení provést asi nějak takto:

try { localDate = formatter.parseLocalDate(input); }
        catch (IllegalFieldValueException e) {  }
        catch (IllegalArgumentException f) { }

Pokud si vyzkoušíme nějaké špatné zadání teď, dostaneme výsledek, který je vidět na obrázku č. 13 galerie. Z něj je patrné, že v případě nějakého problému je hodnota proměnné

localData = null

Poslední úpravu uděláme na základě této povědomosti a použijeme test obsahu proměnné pro výpis do konzole:

if (localDate != null) {
            System.out.println(input);
            System.out.println(localDate); }
        else System.out.println("Spatny format!");

Každý si může vyzkoušet, jak funguje tato poslední úprava. My se k nebudeme už vracet a naopak se pustíme do definitivního řešení kontroly zadání data ve správném formátu. Jako obvykle si k tomu vytvoříme dvě funkce. Ta první bude vycházet z předchozí:

private boolean isDatum(final TextField input) {
        LocalDate localDate = null;
        DateTimeFormatter formatter = DateTimeFormat.forPattern("d.M.yyyy");
        try { localDate = formatter.parseLocalDate(input.getText());
        return true; }
        catch (IllegalFieldValueException e) { return false; }
        catch (IllegalArgumentException f) { return false; } }

Odlišnost není příliš veliká, pouze jsme nastavili typ funkce a formální parametr, vynechali zobrazení do konzole a přidali návratové hodnoty. Výkonná funkce bude mít opět známý formát:

private boolean validDTM(final TextField field){
        if (!isDatum(field)) {
            dialogMessage("Pole " + field.getId() + " neobsahuje datum ve správném formátu!", "Kontrola editačních polí", 'E');
            field.setText("");
            setFocus(field);
            return true; }
        else {
            return false; } }

Při nesprávném zadání se objeví chybové hlášení, obsah pole se vymaže a nastaví se na něj kurzor. Do procedury save_Update můžeme přidat poslední kontrolní řádek:

ict ve školství 24

private void save_Update() {
        if (emptyTF(u_Cele)) return;
        else if (emptyTF(u_Desetinne)) return;
        else if (emptyTF(u_Maledes)) return;
        else if (emptyTF(u_Text)) return;
        else if (emptyTF(u_Datum)) return;
        else if (validLEN(u_Text, 32)) return;
        else if (validINT(u_Cele)) return;
        else if (validDBL(u_Desetinne)) return;
        else if (validDBL(u_Maledes)) return;
        else if (validDTM(u_Datum)) return;
        else {

        }
    }

a vše řádně vyzkoušet. Předposlední obrázek v galerii ukazuje jedno nesprávné zadání a poslední článek galerie pak příslušné chybové hlášení. Tím dnešní díl ukončíme a do přílohy dáme celou proceduru: samexam4.java.

V dnešním dílu jsme se věnovali kontrole obsahu editačních polí a ukázali si možnost kontroly délky textového řetězce a formátu celých a desetinných čísel a také datumů. V příštím dílu ukončíme kapitolu ukázkou uložení aktualizovaných dat a zrušení provedených změn v editačních polích.