Lekce 4 - Upomínač narozenin v PyQt - Návrh formulářů
V předešlém cvičení, Řešené úlohy k 1.-3. lekci PyQt, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
V dnešním Python tutoriálu začneme v PyQt pracovat na aplikaci k upomínání narozenin přátel. Aplikace bude vypadat následovně:

Struktura aplikace
Vytvořte si nový projekt, já soubor opět pojmenuji main.py.
Jako vždy začneme formuláři. Tentokrát již budeme mít v aplikaci dva,
PrehledForm s přehledem osob a jejich narozenin a
OsobaForm k přidávání nových osob. Co se týká vytvoření
samotné aplikace, přejdeme ještě dále a i tu dnes vytvoříme přes třídu
App. Všechny tyto třídy si připravíme a do třídy
App přidáme metodu build(), která nám naši
aplikaci spustí. Třída App bude udržovat instance našich
dalších tříd, nyní formulářů.
from PyQt5 import QtWidgets, QtGui, QtCore import sys class OsobaForm(QtWidgets.QWidget): def __init__(self, **kwargs): super(OsobaForm, self).__init__(**kwargs) pass def setup(self): pass class PrehledForm(QtWidgets.QMainWindow): def __init__(self, **kwargs): super(PrehledForm, self).__init__(**kwargs) pass def setup(self): self.osoba_form = root.osoba_form class App(QtWidgets.QApplication): def __init__(self): super(App, self).__init__(sys.argv) def build(self): self.prehled_form = PrehledForm() self.osoba_form = OsobaForm() self.prehled_form.setup() self.osoba_form.setup() sys.exit(self.exec_()) root = App() root.build()
Oba formuláře jsou opět vytvořené jako třídy dědící z
QtWidgets.QWidget. Kromě konstruktoru (metody
__init__()) v nich máme i metodu setup(), kterou
spustíme až po vytvoření všech formulářů. Tímto způsobem k sobě budou
moci formuláře vzájemně přistupovat. Všimněte si, že v metodě
build() třídy App() vytvoříme oba formuláře a
až poté oběma zavoláme metodu setup(). Formulář
PrehledForm si v ní uloží instanci OsobaForm,
kterou si z aplikace vytáhne pomocí klíčového slova root.
Formulář s přehledem bude takto moci formulář pro osobu otevírat při
kliknutí na tlačítko "Přidat".
Kostru formulářů a aplikace máme vytvořenou, i když aplikace zatím po spuštění nic neudělá.
Návrh formulářů
Přesuňme se ke vkládání jednotlivých widgetů do formulářů.
Přehledový formulář
Přehledový formulář je základní okno aplikace s přehledem osob a jejich narozenin. Budeme potřebovat následující ovládací prvky:
- 8x
QLabel- Popisky - 2x
QPushButton- Tlačítko na přidání a odebrání osoby - 1x
QListWidget- Seznam osob - 1x
QCalendarWidget- Kalendář
Layout
Jako první musíme samozřejmě vytvořit systém layoutů, aby se widgety
ve formuláři správně poskládaly. Jelikož veškeré GUI zde píšeme jako
kód a nepoužíváme žádný GUI designer, budeme postupovat jednoduše shora
dolů a zleva doprava. Celému formuláři nastavíme QVBoxLayout,
čímž se v něm další layouty budou řadit pod sebe. V tomto formuláři
budeme box layouty využívat často.
Informační boxy

Na část vyznačenou červeně na obrázku budeme potřebovat:
QHBoxLayout- umožní řádit labely vedle sebeQLabel- Popisek s textem "Dnes je"QLabel- Popisek s dnešním datem
QHBoxLayout- umožní řádit labely vedle sebeQLabel- Popisek s textem "Nejbližší narozeniny"QLabel- Popisek s nejbližšími narozeninami (zatím nebude použitý)
Nejprve si na začátek souboru přidejte:
import datetime
Tím jsme si naimportovali funkcionalitu pro práci s datem a časem a budeme
schopní do QLabelu zobrazit co je dnes za den. Ukažme si nyní
upravený kód třídy PrehledForm, který si následně podrobně
popíšeme.
class PrehledForm(QtWidgets.QMainWindow): def __init__(self, **kwargs): super(PrehledForm, self).__init__(**kwargs) # Titulek, ikonka a minimální šířka okna self.setWindowTitle("Výročí") self.setWindowIcon(QtGui.QIcon("icon.png")) self.setMinimumWidth(650) # Vytvoříme hlavní widget a nastavíme BoxLayout formular = QtWidgets.QWidget() layoutFormulare = QtWidgets.QVBoxLayout() formular.setLayout(layoutFormulare) self.setCentralWidget(formular) # Vytvoříme informační box s BoxLayoutem (Dnešní datum) self.dnesLayout = QtWidgets.QHBoxLayout() layoutFormulare.addLayout(self.dnesLayout) self.dnesLayout.addWidget(QtWidgets.QLabel("Dnes je:")) self.dnesLayout.addStretch() self.dnesLabel = QtWidgets.QLabel(self.get_current_date()) self.dnesLayout.addWidget(self.dnesLabel) # Vytvoříme informační box s BoxLayoutem (Nejbližší narozeniny) self.narozeninyLayout = QtWidgets.QHBoxLayout() layoutFormulare.addLayout(self.narozeninyLayout) self.narozeninyLayout.addWidget(QtWidgets.QLabel("Nejbližší narozeniny:")) self.narozeninyLayout.addStretch() self.nejblizsiLabel = QtWidgets.QLabel("") self.narozeninyLayout.addWidget(self.nejblizsiLabel) self.show() def get_current_date(self): return (str(datetime.datetime.now().day) + "." + str(datetime.datetime.now().month) + "." + str(datetime.datetime.now().year)) # Získá požadované instance def setup(self): self.osoba_form = root.osoba_form
První trojice řádků nastavuje titulek okna, jeho ikonku a minimální
šířku, aby se okno nedalo zmenšit tak, že by se do něj obsah nevešel.
Ikonku, která se vám líbí, si můžete najít na https://www.iconfinder.com/ nebo si
stáhnout ikony přiložené v dnešním archivu. Soubor poté stačí umístit
do složky se souborem main.py. Když ji nenastavíte nebo dokonce
i když ji nastavíte a nenahrajete, vadit to nebude.
Další řádky vytvářejí samotný formulář a nastavují mu
QVBoxLayout pro řazení widgetů (přesněji dalších layoutů)
pod sebe. Formulář se následně nastaví aplikaci jako výchozí.
První informační boxík s dnešním datem vytváříme tedy jako
QHBoxLayout. Na kódu je zajímavé asi jen to, že aby byly
QLabely naproti sobě, je mezi ně vloženo prázdné místo
pomocí addStretch().
Nakonec následuje vytvoření druhého boxíku s dnešními narozeninami, situace je zde úplně stejná jako v boxíku předchozím.
Metoda get_current_date() vrátí aktuální datum v českém
formátu (mm.dd.rrrr) a měla by být z kódu srozumitelná.
Pokud spustíte aplikaci, zobrazí se vám následující okénko:

ListWidget, kalendář a informace o osobě
Základní informace máme hotové a nyní vytvoříme layouty pro
QListWidget, kalendář a informace o aktuálně vybrané
osobě.

Vytvoříme QHBoxLayout, který bude obsahovat jednotlivé
BoxLayouty s widgety.
QHBoxLayoutQHBoxLayoutQListWidget
QVBoxLayoutQHBoxLayoutQLabelQLabel
QHBoxLayoutQLabelQLabel
QCalendarWidget
# Předchozí kód metody __init__() třídy PrehledForm # ... # Společný layout pro osobyListBox a narozenMonthCalendar self.prostredniLayout = QtWidgets.QHBoxLayout() layoutFormulare.addLayout(self.prostredniLayout) # Vytvoříme layout pro osobyListBox self.jmenaLayout = QtWidgets.QHBoxLayout() self.osobyListBox = QtWidgets.QListWidget() self.jmenaLayout.addWidget(self.osobyListBox) self.prostredniLayout.addLayout(self.jmenaLayout) # Vytvoříme layout pro narozenMonthCalendar self.kalendarLayout = QtWidgets.QVBoxLayout() self.narozenMonthCalendar = QtWidgets.QCalendarWidget(self) self.narozenMonthCalendar.setEnabled(False) # Vytvoříme layout pro informace o osobách self.osobaLayout = QtWidgets.QHBoxLayout() self.osobaLayout.addWidget(QtWidgets.QLabel("Narozen:")) self.osobaLayout.addStretch() self.narozeninyLabel = QtWidgets.QLabel("") self.osobaLayout.addWidget(self.narozeninyLabel) self.kalendarLayout.addLayout(self.osobaLayout) self.osobaLayout2 = QtWidgets.QHBoxLayout() self.osobaLayout2.addWidget(QtWidgets.QLabel("Věk:")) self.osobaLayout2.addStretch() self.vekLabel = QtWidgets.QLabel("") self.osobaLayout2.addWidget(self.vekLabel) self.kalendarLayout.addLayout(self.osobaLayout2) self.kalendarLayout.addWidget(self.narozenMonthCalendar) self.prostredniLayout.addLayout(self.kalendarLayout) self.show()
Naše počínání je velmi podobné jako u informačního boxíku. Pro celou
prostřední část jsme si vytvořili QHBoxLayout, aby se její
součásti mohly řadit vedle sebe. Přidání QListWidget je
triviální. Další widgety vpravo jsou komplikované jen kvůli layoutům. Je
zde třeba vložit další QVBoxLayout, který umožní zobrazit
dva layouty s labely a třetí s kalendářem pod sebou. U kalendáře je
zajímavé patrně jen to, že jsme mu nastavili setEnabled(False),
aby se na něm datum narození vybrané osoby zobrazovalo, ale nedalo se vybrat
jiné.
Náš formulář PrehledForm je skoro hotov, stačí jen přidat
tlačítka 

V další lekci, Upomínač narozenin v PyQt - Dokončení návrhu formulářů, rozpracujeme návrh prvního z formulářů aplikace v PyQt pro upomínání narozenin osob.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 179x (6.11 kB)
Aplikace je včetně zdrojových kódů v jazyce Python
