Vianoce v ITnetwork sú tu! Dobí si teraz kredity a získaj až 80 % extra kreditov na e-learningové kurzy ZADARMO. Zisti viac.
Hľadáme nové posily do ITnetwork tímu. Pozri sa na voľné pozície a pridaj sa k najagilnejšej firme na trhu - Viac informácií.

5. diel - Uloženie objektov do CSV v Pythone časť 2

V minulej lekcii, Uloženie objektov do CSV v Pythone , sme načali databázu užívateľov pomocou CSV súborov.

Dnes do súboru CSV uložíme a aplikáciu dokončíme.

Načítanie užívateľov z CSV súboru

Uloženie nám funguje, zostáva vedieť dáta opätovne načítať. Načítame všetky riadky zo súboru a každý riadok rozdelíme metódou split() a následne do zoznamu pridáme objekt s príslušnými hodnotami. Pred načítaním si zoznam vyprázdnime, aby v ňom neboli aj používatelia načítaní niekedy skôr (keby sa aplikácia niekedy rozširovala).

def nacti(self):
    self.uzivatele = []
    with open(self.soubor, "r", encoding="utf-8") as f:
        for s in f.readlines():
            jmeno, vek, registrovan = s.strip().split(";")
            registrovan = datetime.datetime.strptime(registrovan, "%d.%m.%Y")
            self.pridejUzivatele(jmeno, vek, registrovan)

Trieda Databaze je teda kompletná. Teraz sa zameriame na formulárovú časť.

Prezentačná vrstva aplikácie

Ako prvé si pripravíme nové formulárové prvky. Aplikácia je napísaná v tkinter, ktorý je už súčasť Pythona. Na vytvorenie formulára som použil pygubu-designer, ktorý nainštalujete pomocou pip install pygubu a spustíte príkazom pygubu-designer. V pygubu-designeri si naklikáme formulár, ktorý potom prepojíme s funkciami. Formulár je uložený ako XML v .ui súbore.

Návrh Python formulára v pygubu-designer - Práca so súbormi v Pythone - Práca so súbormi v Pythone

Funkciu, ktorá sa zavolá po kliknutí na tlačidlo, v pygube-designeri nastavíme po vybraní tlačidla v záložke General -> Specific -> command.

Command v pygube dizajnéra pre Python - Práca so súbormi v Pythone - Práca so súbormi v Pythone

Funkciu, ktorá sa zavolá po vybraní položky z ListBoxu, v pygube-designeri po vybraní ListBoxu nastavíme v záložke Bindings.

Bindings v pygube dizajnéra pre Python - Práca so súbormi v Pythone - Práca so súbormi v Pythone

Pridáme tlačidlo "Načítať", ďalej ListBox listUzivatelu. Ďalej Entry na meno nového užívateľa, Entry na jeho vek a Entry na dátum registrácie. K ovládacím prvkom pridáme nejaké labely. Tieto prvky môžeme zoskupiť do Frame. V ďalšom Frame budú 3 labely na detail užívateľa, tie pomenujeme jmenoLabel, vekLabel a registrovanLabel. Ďalšie 3 labely pridáme ako ich popis. Nakoniec pridáme tlačidlo "Pridať" na pridanie užívateľa. Pokiaľ to bolo veľmi rýchle, tu je obrázok výsledného formulára:

Formulár programu pre prácu s CSV súbormi v Pythonu - Práca so súbormi v Pythone - Práca so súbormi v Pythone

V reáli by bolo pridanie užívateľov pravdepodobne prítomné v samostatnom formulári, ktorý by sa zobrazoval ako dialóg, ale nám to bude v tutoriáli stačiť takto.

Najskôr si musíme upraviť triedu Aplikace, aby sme využili náš naklikaný formulár (zdrojové kódy a gui.iu sú prípadne na stiahnutie na konci článku, keby vám čokoľvek nešlo). Formulár získame načítaním súboru, potom nastavíme rodičov hlavnému framu a nakoniec napojíme obslužné funkcie. To všetko za nás v pozadí prevedie pygubu a my sa tak o nič nestaráme. Trieda Aplikace teraz vyzerá takto:

class Aplikace():

    def __init__(self, master):
        self.master = master
        self.db = Databaze("uzivatele.csv")
        self.builder = pygubu.Builder()
        self.builder.add_from_file("gui.ui")
        self.builder.get_object("Frame_1", self.master)
        self.builder.connect_callbacks(self)

A inicializujeme ju takto:

root = tkinter.Tk()
aplikace = Aplikace(root)
root.mainloop()

Z obsluhy tlačidla "Uložiť" odstránime vytvorenie testovacích užívateľov. Samotné uloženie teraz vložíme do tryexcept bloku. Vieme totiž, že finally (teda with blok v našej databáze) výnimky nepohlcuje, čo tiež chceme a budeme na ne reagovať vo formulárovej časti, kam reakcia logicky patrí. Upozornenie na chybu, teda komunikácia s užívateľom, priamo v triede Databaze by bolo zle. Po zachytení výnimky zobrazíme MessageBox s chybou. Obslužná metóda tlačidla bude teda vyzerať takto:

def tlacitkoNacistClicked(self):
    try:
        self.db.uloz()
    except:
        messagebox.showerror("Chyba", "Databázi se nepodařilo uložit, zkontrolujte přístupová práva k souboru.")

Obdobne upravíme metódu tlačidla "Načítať", iba po načítaní databázy vložíme objekty do ListBox. Ten predtým vyprázdnime, aby nám tam nezostávali používatelia z predošlého načítania. V reáli by sa načítanie vykonalo asi automaticky po spustení aplikácie a uložení po ukončení, pre názornosť si to však ponecháme na tlačidlách. Metóda tlačidla "Načítať" teda vyzerá takto:

def tlacitkoNacistClicked(self):
    try:
        self.db.nacti()
    except:
        messagebox.showerror("Chyba", "Databázi se nepodařilo načíst, soubor zřejmě neexisituje.")
        return
    listbox = self.builder.get_object("listUzivatelu")
    listbox.delete(0,tkinter.END)
    for u in self.db.VratVsechny():
        listbox.insert(tkinter.END, u.jmeno)

Teraz spracujeme kliknutie na položku v listUzivatelu, ktoré vykoná zobrazenie detailu vybraného užívateľa do pripravených labelov:

def ziskejUzivatele(self, evt):
    listbox = self.builder.get_object("listUzivatelu")
    i = listbox.curselection()[0] + 1 if len(listbox.curselection()) > 0 else None
    if len(self.db.uzivatele) == 0 or i == None:
        return
    jmeno_label = self.builder.get_object("jmenoLabel")
    vek_label = self.builder.get_object("vekLabel")
    registovan_label = self.builder.get_object("registrovanLabel")
    u = self.db.uzivatele[i-1]
    jmeno_label["text"] = u.jmeno
    vek_label["text"] = u.vek
    registovan_label["text"] = u.registrovan.strftime("%d.%m.%Y")

Kód sme opodmienkovali pre prípad, že by nebol žiadny užívateľ vybraný (list by bol prázdny). Môžete si vyskúšať, že všetko funguje.

Posledné tlačidlo bez metódy je "Pridať" nového užívateľa. Vytvoríme si obslužnú metódu. Vloženie bude veľmi jednoduché, prvok však musíme pridať ako do databázy, tak do listUzivatelu:

def tlacitkoPridatClicked(self):
    jmeno = self.builder.get_object("jmenoEntry").get()
    vek = self.builder.get_object("vekEntry").get()
    registrovan = self.builder.get_object("registrovanEntry").get()
    if jmeno == "" or vek == "" or registrovan == "":
        return
    registrovan = datetime.datetime.strptime(registrovan, "%d.%m.%Y")
    self.db.pridejUzivatele(jmeno, vek, registrovan)
    listbox = self.builder.get_object("listUzivatelu")
    listbox.delete(0,tkinter.END)
    for u in self.db.vratVsechny():
        listbox.insert(tkinter.END, u.jmeno)

Skúsime pridať nového používateľa:

Pridanie nového užívateľa v CSV databáze v Pythonu - Práca so súbormi v Pythone - Práca so súbormi v Pythone

Podobne by sme si mohli napísať aj mazanie používateľov, ale to už nechám na vás. Zostáva nám ešte ošetriť cestu k súboru, aby viedla do zložky AppData, nie do zložky s programom. To vieme z tutoriálu Úvod do práce so súbormi v Pythone. Získanie cesty vykonáme v konštruktore triedy Aplikace:

def __init__(self, master):
    self.master = master
    try:
        cesta = os.path.join(os.getenv("APPDATA"), "DatabazeUzivatelu")
        if not os.path.exists(cesta):
            os.mkdir(cesta)
    except:
        messagebox.showerror("Chyba", "Nepodařilo se vytvořit složku " + cesta + ", zkontrolujte prosím svá oprávnění.")
    self.db = Databaze(os.path.join(cesta, "uzivatele.csv"))
    self.builder = pygubu.Builder()
    self.builder.add_from_file("gui.ui")
    self.builder.get_object("Frame_1", self.master)
    self.builder.connect_callbacks(self)

A je to:)

Naša aplikácia je takmer hotová, ešte sa zamyslíme nad tým, čo sa stane, keď niekto do mena vloží bodkočiarku. Aplikácia sa rozbije. Preto budeme v metóde uloz() bodkočiarky z mena odstraňovať. Keby sme robili aplikáciu, kde by sme ich potrebovali (čo sa nestáva príliš často), môžeme vybrať iný zástupný znak. Ak by sme chceli byť dokonalí, vložíme takú hodnotu so bodkočiarkou do úvodzoviek. Potom však už nejde o jednoduché CSV a metóda split() nám prestane stačiť. Ďalej by sa to samozrejme dalo riešiť iným formátom. My si teda bodkočiarky iba odstráňme, presnejšie ich nahradíme medzerami zmenou jediného riadku v metóde uloz():

hodnoty = [u.jmeno.replace(";", " "), str(u.vek), u.registrovan.strftime("%d.%m.%Y")]

A sme hotoví. Pokiaľ vám niečo nešlo úplne hladko, hotový projekt máte ako vždy v prílohe aj so zdrojovým kódom.

V nasledujúcom cvičení, Riešené úlohy k 1.-5. lekciu práce so súbormi v Pythone, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 290x (3.12 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python

 

Predchádzajúci článok
Uloženie objektov do CSV v Pythone
Všetky články v sekcii
Práca so súbormi v Pythone
Preskočiť článok
(neodporúčame)
Riešené úlohy k 1.-5. lekciu práce so súbormi v Pythone
Článok pre vás napísal MQ .
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Používám hlavně Python a zajímám se o Deep Learning a vše kolem.
Aktivity