5. diel - Uloženie objektov do CSV v Pythone časť 2
V minulej lekcii, Uloženie objektov do CSV v Pythone , sme načal databázu užívateľov pomocou CSV súborov. Teraz aplikáciu dokončíme a doladíme.
Načítanie použí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
užívatelia načítanie 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árovom č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ť Pythone. 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-dizajnérov si naklikáte formulár,
ktorý potom prepojíme s funkciami. Formulár je uložený ako XML v
.ui
súbore.
Funkciu, ktorá sa zavolá po kliknutí na tlačidlo, v pygubu-dizajnérov nastavíme po vybraní tlačidla v záložke General -> Specific -> command.
Funkciu, ktorá sa zavolá po vybraní položky z listbox, v pygubu-dizajnérov po vybraní listbox nastavíme v záložke Bindings.
Pridáme tlačidlo "Načítať", ďalej ListBox
listUzivatelu
. Ďalej Entry
na meno nového
použí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 popisok. Nakoniec pridáme tlačidlo "Pridať" na pridanie
používateľa. Ak to bolo moc rýchle, tu je obrázok výsledného
formulára:
V reáli by bolo pridanie používateľov pravdepodobne prítomné v samostatnom formulári, ktorý by sa zobrazoval ako dialóg, ale nám to bude v tutoriálu 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
k stiahnutiu na konci článku, keby vám čokoľvek nešlo). Formulár získame
načítaním súboru, potom nastavíme rodičia 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
používateľov. Samotné uloženie teraz vložíme do try
-
except
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árové časti, kam reakcie 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
u. Ten predtým
vyprázdnime, aby nám tam nezostávali používatelia z predošlého
načítanie. V reáli by sa načítanie vykonalo asi automaticky po spustení
aplikácie a uloženie 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 kliknutí 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 opodmínkovali 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 použí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:
Podobne by sme si mohli napísať aj mazanie uží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 konstruktoru 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čiarka. Aplikácia sa rozbije. Preto
budeme v metóde uloz()
bodkočiarkami 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 sa bodkočiarkou do úvodzoviek. Potom sa 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čiarkami 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í. Ak 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 budúcej lekcii, Úvod do formátu XML v Pythone , sa pozrieme na formát XML.
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é 267x (3.12 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python