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
QLabel
y 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.
QHBoxLayout
QHBoxLayout
QListWidget
QVBoxLayout
QHBoxLayout
QLabel
QLabel
QHBoxLayout
QLabel
QLabel
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 174x (6.11 kB)
Aplikace je včetně zdrojových kódů v jazyce Python