Lekce 6 - Upomínač narozenin v PyQt - Logická vrstva
V minulé lekci, Upomínač narozenin v PyQt - Dokončení návrhu formulářů, jsme navrhli kompletně formuláře pro naši PyQt aplikaci pro upomínání narozenin osob.
V dnešním Python tutoriálu se budeme zabývat návrhem logické vrstvy, tedy tříd, které obsahují logiku aplikace.
Osoba
V naší aplikaci budou zcela jistě figurovat osoby, vytvořme jim tedy
novou třídu. Další třídy budeme nyní přidávat nad třídu
App
.
Vlastnosti
Osoba bude mít 2 vlastnosti: jméno a narozeniny. Tyto vlastnosti nastavíme pomocí konstruktoru.
class Osoba(): def __init__(self, jmeno, narozeniny): self.jmeno = jmeno self.narozeniny = narozeniny
Metody
Kromě konstruktoru bude třída disponovat metodami
spocti_vek()
a zbyva_dni()
.
spocti_vek()
Metoda vypočítá a vrátí aktuální věk osoby v celých letech, výpočet věku tedy provedeme následujícím způsobem:
- Získáme si aktuální datum (bez času) pomocí
datetime.datetime.now().date()
. Právě zavolánídate()
vrátí pouze datum z aktuálního data a času. - Věk spočítáme jako rozdíl roků v aktuálním datu a datu narozenin. Asi je vám jasné, že tento věk není přesný. Pokud jsme se narodili 1.2.1990 a je 1.1.2020, není nám 30 let, ale jen 29. Z toho důvodu provedeme korekci.
- V případě, že je aktuální datum menší (dříve) než datum narození po přidání námi vypočítaných let, nastal výše uvedený případ a my věk o rok snížíme.
- Hotový věk vrátíme.
Kód metody bude následující:
def spocti_vek(self): dnes = datetime.datetime.now() vek = dnes.year - self.narozeniny.year if dnes < self.narozeniny.replace(year=self.narozeniny.year + vek): vek -= 1 return vek
zbyva_dni()
Metoda nám vrátí kolik dní zbývá do narozenin osoby. To zjistíme následujícím způsobem:
- Získáme si aktuální datum (opět bez času).
- Získáme datum dalších narozenin přičtením věku + 1 k datu narození.
- Data odečteme a celkový rozdíl ve dnech vrátíme.
def zbyva_dni(self): dnes = datetime.datetime.now() dalsi_narozeniny = self.narozeniny + relativedelta(years = self.spocti_vek() + 1) rozdil = dalsi_narozeniny - dnes return rozdil.days
Přičtení roků provedeme přes funkci relativedelta()
. Tu si
naimportujte pomocí řádku:
from dateutil.relativedelta import relativedelta
Řáde umístíme mezi importy na začátek souboru.
__str__()
Jelikož budeme osoby vypisovat, vytvoříme metodu __str__()
tak, aby vracela jméno osoby:
def __str__(self): return self.jmeno
Správce osob
Další logickou komponentou aplikace bude správce osob. Třída se bude starat o osoby, bude je umět přidávat, odebírat a jejich seznam ukládat do souboru a opětovně načíst. Konečně bude umět mezi osobami vyhledat tu, která má nejbližší narozeniny.
Všimněte si, jak je i za úlohu spravování osob zodpovědná oddělená třída a tyto metody nemícháme s metodami GUI. V kalkulačce jsme tuto návrhovou praktiku zanedbali, protože to byla naše první aplikace a byla také velmi jednoduchá. Odteď budeme ovšem do GUI psát vždy jen obsluhu uživatelského rozhraní a jakoukoli logiku vždy oddělíme do samostatných tříd.
Vlastnosti a atributy
Jedinou vlastností třídy je seznam osob. Seznam osob bude pouze obyčejný list/pole, do kterého budeme osoby přidávat.
Třída zatím vypadá takto:
class SpravceOsob():
osoby = []
Metody
Kromě přidávání a odebírání bude třída umět i nalézt osobu s nejbližšími narozeninami. Ukládání a načítání osob do/ze souboru necháme na později.
pridej()
Metoda přidá novou osobu do pole/listu. Jelikož osobu přidáváme formulářem, hodí se nám, aby metoda brala v parametrech vlastnosti osoby a na jejich základě vytvořila novou instanci. Z data narození uložíme pouze část s datem, tedy bez času.
Zde zadané datum ošetřovat nemusíme, jelikož uživatel nemá možnost zadat datum v budoucnosti díky vygenerovaným hodnotám.
def pridej(self, jmeno, datum_narozeni):
osoba = Osoba(jmeno, datum_narozeni)
self.osoby.append(osoba)
odeber()
Metoda odebere osobu z pole/listu. Protože vždy budeme chtít odebírat již hotovou osobu, bere metoda v parametru právě tu.
def odeber(self, osoba):
self.osoby.remove(osoba)
najdi_nejblizsi()
Metoda najde a vrátí osobu, která má nejbližší narozeniny. K vyhledání osoby v listu použijeme funkci `sorted(), která vrátí osoby uspořádané podle klíče. V našem případě klíčem bude kolik dní zbývá do jejich narozenin.
def najdi_nejblizsi(self): if len(self.osoby) > 0: serazene = sorted(self.osoby, key = lambda item: item.zbyva_dni()) return serazene[0] return None
V další lekci, Upomínač narozenin v PyQt - Dokončení aplikace, dokončíme aplikaci Upomínač narozenin.