Hlavní navigace

Programování v JavaFX: mazání záznamů pomocí PG funkce, aktualizace záznamů

19. 11. 2015
Doba čtení: 9 minut

Sdílet

Minulý díl byl zaměřen na mazání tabulkových záznamů pomocí klasických SQL příkazů. Také jsme si připravili výkonnou funkci, která zajistí mazání záznamů pomocí deklarované PG funkce. V dnešním dílu si ukážeme mazání záznamů pomocí této funkce. Také se začneme věnovat aktualizaci a změnám v tabulkových záznamech.

Výkonnou funkci pro mazání dat pomocí dříve vytvořené PG funkce jsme si připravili již v minulém díleů. Dnes na to tedy můžeme navázat a připravit si jednoduchou „volací“ proceduru, která jednoduše a přímo smaže první dostupný záznam v naší zkušební tabulce:

private void onDelete() {
    deleteRec("udaje", "id", 4);            //1
    showFmt();                  //2
    tabPane.getSelectionModel().select(0); }    //3

Kód je sice jednoduchý a asi i očekávaný, přesto jednoduché vysvětlení nezaškodí:

  1. řádek – volá se PG procedura, kde jsou postupně zadané skutečné parametry: název tabulky, název sloupce, kde se hledá hodnota a konkrétní hodnota v záznamu, který se má smazat
  2. řádek – nové volání procedury pro zobrazení aktualizovaných dat
  3. řádek – přechod na první záložku TabPane

Na prvním obrázku první galerie pak vidíme, že záznam s pořadovým číslem 4 opravdu z tabulky zmizel. Podobně jako v minulé dílu si také vytvoříme možnost výběru příslušného záznamu v zobrazené tabulce pomocí myši. Mohli bychom to udělat sice přímo v proceduře volání, ale uděláme si to trochu obecněji (dále pak uvidíme, proč je to tak výhodnější) v několika krocích. Do procedury samexam4.java si přidáme deklaraci celočíselné proměnné:

Integer pid = null;

Tato proměnná by nám měla sloužit pro uchování hodnoty v příslušném sloupci zobrazené tabulky. Pro její uložení přidáme další řádek do výkonné procedury (tableClick), která nám reaguje na dvojklik myší na vybraném řádku tabulky. Také můžeme zjednodušit další řádek, který tuto hodnotu přenáší do příslušného editačního pole. Celý začátek procedury bude tedy vypadat následovně:

pid = Integer.valueOf(String.valueOf(table1.getSelectionModel().getSelectedItems().get(0).get(0)));
u_ID.setText(pid.toString());

První řádek se příliš neliší od toho původního. Změna vychází pouze z toho, že proměnná je celočíselného typu, a proto musíme zajistit převod původně textové hodnoty. A ve druhém řádku již nepotřebujeme volat hodnoty z tabulky a stačí nám pouze jednoduchý převod celočíselné hodnoty zpět na textovou. Poslední změnu pak uděláme ve volací proceduře velmi jednoduše:

deleteRec("udaje", "id", pid);

Druhý obrázek v první galerii nám ukazuje, že změna procedury pro myší dvojklik funguje i v novém formátu (je vybrán opět první řádek tabulky s pořadovým číslem 5). Třetí obrázek první galerie pak ukazuje, že vybraný řádek poslušně vymizel z přehledu. Poslední změna už bude jenom v aktuální proceduře a bude spočívat v přidání dialogu pro volbu uživatele, jestli mazat či nikoliv. Zde uvedeme pouze první řádek s voláním dialogu, kde je drobná změna v souvislosti s využitím nově deklarované proměnné:

Integer quest = questMessage("Je vybrána položka ID =" +pid.toString()+" , opravdu chcete vybranou položku smazat?", "Mazání záznamu");

Čtvrtý obrázek v první galerii zobrazuje příslušný dialog a dokazuje, že je i takto funkční. Na pátém obrázku první galerie je potom patrné, že opět došlo ke smazání vybraného záznamu (pořadové číslo 6). Tímto obrázkem bychom mohli kapitolu o mazání záznamů z tabulky ukončit a přesunout se do kapitoly další – aktualizace a úpravy záznamů. Abychom mohli tuto problematiku řešit, musíme si připravit několik pomocných kroků:

  1. změna zobrazení editačních polí
  2. změna zobrazení ovládacích tlačítek
  3. aktivace změn v záznamu
  4. příprava pro zrušení změn
  5. kontrola obsahu editačních polí

Zobrazení editačních polí

Zatím jsme měli tuto funkci nastavenou tak, že pole ID je trvale nastaveno pouze pro čtení a ostatní editační pole jsou uživatelsky přístupná. To ale v rámci třeba mazání záznamů nemá velký smysl, takže to celé trochu upravíme. Výsledek bude takový, že při dvojkliku na záznam v tabulce se všechna editační pole nastaví jenom pro čtení. Pouze v případě snahy o aktualizaci záznamu se vybraná pole (v našem konkrétním případě všechny kromě ID) nastaví i pro zápis nových hodnot. Abychom mohli funkci využít obecně, vytvoříme si dvě nové procedury. První z nich nastaví všechna editační pole pouze pro čtení:

private void tf_RO() {
        u_Cele.setEditable(false);
        u_Desetinne.setEditable(false);
        u_Maledes.setEditable(false);
        u_Text.setEditable(false);
        u_Datum.setEditable(false); }

Žádný velký komentář zde není třeba. Pro všechny deklarované proměnné (editační pole) se nastaví možnost editace na negativní hodnotu = pole nelze editovat. Velmi jednoduše vytvoříme i obrácenou proceduru, kde se všechna editační pole nastaví jako uživatelsky přístupná:

private void tf_RW() {
        u_Cele.setEditable(true);
        u_Desetinne.setEditable(true);
        u_Maledes.setEditable(true);
        u_Text.setEditable(true);
        u_Datum.setEditable(true); }

Aby bylo nastavení polí funkční, musíme do procedury tableClick přidat řádek volání nové procedury:

tf_RO();

To by prozatím stačilo a přejdeme k dalšímu kroku.

Ovládací tlačítka

Prozatím máme k dispozici tři tlačítka pro mazání záznamu, uložení a zrušení změn. Zde provedeme dvě jednoduché změny. Pomocí JFXSB přidáme ještě další tlačítko a proceduru pro jeho stisknutí. Obě změny přeneseme do JFX procedury. Tlačítka nastavíme tak, aby při dvojkliku na řádek tabulky byla aktivní pouze dvě – mazání záznamu a nově vytvořené tlačítko pro aktivaci úprav záznamu. Další dvě budou zatím neaktivní. Do procedury tableClick přidáme několik řádků:

d_Button.setDisable(false);
a_Button.setDisable(false);
u_Button.setDisable(true);
e_Button.setDisable(true);

Na šestém obrázku v první galerii pak vidíme vzhled okna po změně zobrazení editačních polí před změnou nastavení tlačítek. Sedmý obrázek první galerie pak ukazuje ten samý formulář po obou uvedených změnách. Máme tedy připravené tlačítko pro aktivaci změny v záznamu a bylo by vhodné mu přiřadit také nějakou činnost.

Aktivace změn

Z předchozích příprav je zřejmé, že budeme volit jeden z možných způsobů změn v tabulkových záznamech. Je samozřejmě možné tyto změny provádět i přímo v tabulce. Obě varianty mohou mít a také mají svoje výhody i nevýhody. My si zde uvedeme pouze tuto jednu. Postup tedy bude takový, že při stisku tlačítka Změnit záznam se příslušná editační pole nastaví jako uživatelsky přístupná a do prvního v pořadí se přesune kurzor. Pro zlepšení přehledu si k tomuto účelu vytvoříme novou proceduru:

private void rec_Update() {
        tf_RW();
        u_Button.setDisable(false);
        e_Button.setDisable(false);
        u_Cele.requestFocus();
    }

Volání této procedury přidáme do příslušné události tlačítka a můžeme zkusit funkčnost. Výsledek je zřejmý z předposledního obrázku v první galerie. Ještě by bylo vhodné se vrátit k poslednímu řádku nové procedury, kde se nastavuje kurzor na vybrané editační pole. Byl proto použit velmi jednoduchý příkaz, který ale nemusí být za všech okolností plně funkční. Proto zde uvedeme bez komentáře další možnost, která nastavení kurzoru (fokusu) do editačního pole řeší obecně a spolehlivě:

public void setFocus(final TextField tf) {
    Platform.runLater(new Runnable() {
        @Override public void run() {
            tf.requestFocus();
            }
            });
            }

Příprava rušení změn

Ve formuláři máme také tlačítko, které by mělo vrátit všechny případné změny do původního stavu. Bylo by samozřejmě možné to řešit opětovným dotazem do tabulky a zobrazením příslušných hodnot nebo návratem k zobrazení tabulky a dvojklikem na příslušný záznam. My ale využijeme toho, že máme hodnoty již k dispozici a uložíme si je do pomocné proměnné. V proceduře tedy deklarujeme novou proměnnou (pole řetězců):

private ArrayList data = new ArrayList();

Do procedury s aktivací změn pak přidáme několik dalších řádků:

data.clear();
data.add(u_Cele.getText());
data.add(u_Desetinne.getText());
data.add(u_Maledes.getText());
data.add(u_Text.getText());
data.add(u_Datum.getText());

První příkaz nuluje obsah proměnné a další do ní ukládají data z jednotlivých editačních polí.

Kontrola obsahu

Tuto oblast můžeme rozdělit na tři podskupiny:

  • kontrola přítomnosti obsahu
  • kontrola délky zadaného obsahu
  • kontrola formátu zadaného obsahu

Postupně se na všechny tyto tři podskupiny krátce podíváme. První je pro nás vlastně nutností, protože všechna pole v tabulce jsou vytvořena s nastavením NOT NULL. To znamená, že všechna editační pole musí mít nějaký obsah a nemohou zůstat prázdná. Řešení se zde nabízejí tři. Prvním z nich je jiná definice vytvoření tabulky, kde budou implicitně použity předdefinované hodnoty. Ta pro nás není moc zajímavá. Obdobně nezajímavá je i další možnost, kdy by se mohly nějaké defaultní hodnoty ukládat programově přímo do editačních polí nebo proměnných. My se zaměříme na poslední variantu, kdy se před uložením do tabulky budou postupně kontrolovat obsahy všech editačních polí. Pokud bude některé z nich prázdné, uživatel bude na tuto skutečnost upozorněn a uložení údajů neproběhne do té doby, než provede nápravu. Pro zajištění kontroly nějakého obsahu v editačním poli si vytvoříme novou funkci:

private boolean emptyTF(final TextField field) {                            //1
        if(field.getText().isEmpty()) {                                 //2
            dialogMessage("Pole " + field.getId() + " je prázdné!", "Kontrola editačních polí", 'E');  //3
            setFocus(field);                                        //4
            return true; }                                      //5
        else return false; }                                        //6

Aby byla funkce skutečně funkční, musíme do procedury přidat jednak výše uvedenou proceduru setFocus a z předchozích ukázkových příkladů zkopírovat proceduru dialogMessage. Pak už je možné novou funkci blíže okomentovat:

  1. řádek – funkce je jako celek logická a má jeden parametr – editační pole
  2. řádek – kontrola, jestli je editační pole prázdné. Pokud ano, spouští se další příkazy
  3. řádek – objeví se chybový dialog, který uživatele upozorní na to, že je editační pole prázdné
  4. řádek – na příslušné editační pole se umístí kurzor
  5. řádek – návratová hodnota funkce se nastaví na kladnou
  6. řádek – pokud editační pole něco obsahuje (není prázdné), návratová hodnota funkce se nastaví na negativní

Abychom mohli vše vyzkoušet, přidáme si další proceduru, která bude zajišťovat uložení změn do tabulky. V této fázi do ní vložíme pouze příkazy pro kontrolu obsahu editačních polí:

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 {

        }
    }

V proceduře se postupně kontrolují jednotlivá editační pole. Pokud je některé prázdné, procedura se ukončí. Kontrola probíhá tak dlouho, dokud ve všech editačních polích není nějaký obsah (zatím jenom „nějaký“, kontroluje se pouze jeho přítomnost!). Volání nové procedury přiřadíme k tlačítku Uložit změny a můžeme zkusit vymazat obsah pole Cele. Na posledním obrázku první galerii pak vidíme dialogové okno, které se nám při pokusu o uložení změn objeví. Při pokusech také zjistíme, že se kurzor přesunuje na příslušné místo. Z obrázku dialogového okna je zřejmé, že název editačního pole není úplně ideální. Je to proto, že jsme použili velmi jednoduchou funkci widgetu TextField:

field.getId()

Tato funkce zobrazuje název widgetu tak, jak byl zadán v JFXSB a přenesen do procedury. Bylo by asi vhodnější si názvy nějak „zlidštit“. To je možné např. tak, že se potřebné názvy editačních polí (widgety Label) přidají do FXML souboru a přenesou do příslušné procedury. Pak je možné použít trochu jinou verzi kontrolní funkce:

CS24 tip temata

private boolean emptyTF(final TextField field, final Label label) {
        if(field.getText().isEmpty()) {
            dialogMessage("Pole " + label.getText() + " je prázdné!", "Kontrola editačních polí", 'E');
            setFocus(field);
            return true; }
        else return false; }

Změny jsou pouze dvě: přidává se druhý parametr, který odkazuje na widget Label a do chybového dialogu se přenáší text, který je v názvu editačního pole (tedy příslušném widgetu Label). Tímto bychom dnešní díl mohli uzavřít a do přílohy přidat příslušnou proceduru: samexam4.java.

V dnešním dílu jsme si ukázali 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. V příštím dílu tuto kontrolu dokončíme dalšími kroky a ukážeme si uložení aktualizovaných záznamů do tabulky.