Lekce 2 - Aplikace Kalkulačka v PyQt
V minulé lekci, Seznámení s PyQt, Instalace a první okenní aplikace v Python, jsme si udělali úvod do tvorby formulářových aplikací v Pythonu a naprogramovali okenní aplikaci Hello world.
Zdravím vás u další lekce PyQt. V dnešním tutoriálu si, jak bylo slibováno, vytvoříme aplikaci Kalkulačka, která bude provádět následující matematické operace:
- součet
- rozdíl
- součin
- podíl
Potřebné widgety
Pro lepší orientaci se můžete podívat na již hotový formulář:

Aplikace bude obsahovat následující widgety:
QWidget
- FormulářQLabel
- Popisek, zde použit na výpis výsledkuQPushButton
- Tlačítko pro provedení výpočtu- 2x
QLineEdit
- Jednořádkové textové pole k zadání čísla QComboBox
- Rozbalovací nabídka s početními operacemi- Layouty - Abychom mohli widgety na formulář rozumně poskládat
Vytvoření projektu
Vytvořte nový projekt, já ten svůj uložím opět jako
main.py
. Nejprve si opět naimportujeme QWidgets
z
PyQt5
a sys
. Dnes si naimportujeme také
QtGui
, protože dále změníme font našeho QLabelu
s
výsledkem.
from PyQt5 import QtWidgets, QtGui import sys
Ačkoli jsme minule pracovali čistě procedurálně, bez objektů, jak jen
jednoduše to šlo, je určitě lepší třídy pro své aplikace používat.
Okno aplikace proto tentokrát vytvoříme jako třídu, dědící z
QtWidgets.QMainWindow
. Ukažme si její kód, který si záhy
popíšeme:
class Window(QtWidgets.QMainWindow): def __init__(self, **kwargs): super(Window, self).__init__(**kwargs) self.setWindowTitle("Kalkulačka v PyQt5") self.init_gui() self.show() def init_gui(self): formular = QtWidgets.QWidget()
V konstruktoru si necháme předat případné argumenty z příkazové
řádky a nastavíme titulek okna. Další inicializaci okna přenecháme
metodě init_gui()
. Nakonec formulář zobrazíme. V metodě
init_gui()
vytvoříme formulář jako minule a uložíme si jej do
proměnné formular
.
Layout
Celému formuláři nastavíme layout na QVBoxLayout
,
V
v názvu označuje vertikální. Widgety na formuláři se budou
tedy skládat pod sebe, na rozdíl od minulé lekce, kde jsme
použili QHBoxLayout
, kde H
označovalo
horizontální. Následně přidáme do tohoto svislého layoutu ještě 2
vodorovné layouty. Ty budou tedy pod sebou a widgety v nich vložené se budou
skládat vedle sebe.
Kód metody init_gui()
se rozroste do následující podoby:
def init_gui(self):
formular = QtWidgets.QWidget()
formularLayout = QtWidgets.QVBoxLayout()
formular.setLayout(formularLayout)
boxLayout1 = QtWidgets.QHBoxLayout()
boxLayout2 = QtWidgets.QHBoxLayout()
formularLayout.addStretch()
formularLayout.addLayout(boxLayout1)
formularLayout.addLayout(boxLayout2)
formularLayout.addStretch()
Pokud jste se v layoutech ztratili, připravil jsem pro vás ilustraci:

formularLayout
řadící widgety pod sebe je zvýrazněný
červeně a layouty boxLayout1
a boxLayout2
v něm
vložené, vkládající widgety vedle sebe, jsou vyznačené zeleně.
Pomocí addStretch()
přidáme volné místo, které výsledek
vycentruje svisle. Na obrázku výše je toto volné místo zvýrazněné
modře.
Widgety
Máme hotové základní rozvržení naší aplikace, která je díky použití layoutů responzivní. To znamená, že když roztáhnete její okno, layouty se rovnoměrně roztáhnou s ním a widgety v nich se nové velikosti rovněž přizpůsobí. Nyní provedeme vložení dalších widgetů do layoutů:
def init_gui(self): formular = QtWidgets.QWidget() formularLayout = QtWidgets.QVBoxLayout() formular.setLayout(formularLayout) boxLayout1 = QtWidgets.QHBoxLayout() boxLayout2 = QtWidgets.QHBoxLayout() formularLayout.addStretch() formularLayout.addLayout(boxLayout1) formularLayout.addLayout(boxLayout2) formularLayout.addStretch() self.vysledekLabel = QtWidgets.QLabel("0", self) self.vysledekLabel.setFont(QtGui.QFont("Arial", 12, QtGui.QFont.Black)) self.cislo1Edit = QtWidgets.QLineEdit(self) self.cislo2Edit = QtWidgets.QLineEdit(self) self.vypoctiButton = QtWidgets.QPushButton("Výpočet", self) self.operatorComboBox = QtWidgets.QComboBox(self) self.operatorComboBox.addItem("+") self.operatorComboBox.addItem("-") self.operatorComboBox.addItem("/") self.operatorComboBox.addItem("*") boxLayout1.addWidget(self.cislo1Edit) boxLayout1.addWidget(self.operatorComboBox) boxLayout1.addWidget(self.cislo2Edit) boxLayout1.addWidget(self.vysledekLabel) boxLayout2.addWidget(self.vypoctiButton) self.setCentralWidget(formular)
Vytváříme widgety, jejichž seznam jsme si uvedli v úvodu lekce. Do
boxLayout1
vložíme textová políčka cislo1Edit
a
cislo2Edit
, také operatorComboBox
s výběrem operace
a vysledekLabel
. Všimněte si přidávání položek do
operatorComboBox
. Druhý řádek, boxLayout2
, obsahuje
jen vypoctiButton
.
Widgety jsme pojmenovali tak, aby končily názvem PyQt widgetu.
To je dobrá praktika, je tak jasné co je ve které proměnné uložené. Kdyby
se vysledekLabel
jmenoval jen vysledek
, mohl by jiný
programátor předpokládat, že se jedná jen o číslo a ne formulářový
prvek.
Možná vás zaujalo, že některé widgety jsme uložili jen jako lokální
proměnné a některé jsme uložili jako atributy třídy pomocí klíčového
slova self
. Je to proto, abychom s nimi mohli v aplikaci ještě
dále pracovat.
Poslední metoda setCentralWidget()
nastavuje náš formulář
jako hlavní okno a tím se zobrazí po spuštění aplikace.
Na úplný konec souboru dodáme několik řádků s tvorbou a spuštění aplikace:
aplikace = QtWidgets.QApplication(sys.argv) okno = Window() sys.exit(aplikace.exec_())
Projekt si můžete nyní zkusit spustit, náš formulář vypadá takto:

Zkuste si jej zmenšit a zvětšit, ať vidíte, že je opravdu responzivní.
Události
Nyní je třeba nastavit tlačítku vypoctiButton
funkci, která
se zavolá při události kliknutí na toto tlačítko. Těmto funkcím se v
programování často říká callback. Danou funkci si zatím
jen připravíme a na konci metody init_gui()
ji navážeme na
tlačítko.
def init_gui(self): # Předešlý kód metody init_gui() ... # ... self.vypoctiButton.clicked.connect(self.vypocti) def vypocti(self): pass # Zbytek souboru # ...
Přidáme logiku naší metody vypocti()
:
def vypocti(self): vysledek = ""; chyba = "" try: # do proměnných načteme hodnoty z ovládacích prvků cislo1 = float(self.cislo1Edit.text()) cislo2 = float(self.cislo2Edit.text()) operator = self.operatorComboBox.currentText() if (operator == "+"): vysledek = cislo1 + cislo2 elif (operator == "-"): vysledek = cislo1 - cislo2 elif (operator == "*"): vysledek = cislo1 * cislo2 elif (operator == "/"): if (cislo2 == 0): chyba = "Chyba dělení 0" else: vysledek = cislo1 / cislo2 else: chyba = "Chybná operace" except: # spustí se, pokud selže parsování na float() chyba = "Nebylo zadáno číslo!" if (chyba): self.vysledekLabel.setText(chyba) # zobrazení chyby else: self.vysledekLabel.setText(str(round(vysledek, 3))) # zobrazení výsledku zaokrouhleného na 3 desetinná místa
Nejprve si vytvoříme pomocné proměnné pro hodnoty, které načítáme z
ovládacích prvků. To abychom dále neopisovali dlouhé názvy a volání
dalších metod. Z QLineEdit
získáme text pomocí metody
text()
. Vybranou položku QComboBox
získáme metodou
currentText()
. Téměř celý kód je v bloku try
,
protože funkce float()
, převádějící text z textových polí
na číslo, může způsobit chybu. V takovém případě program přejde ihned
do bloku except
, chybu vypíše a výpočet se vůbec neprovede. Na
samotném výpočtu není nic moc zajímavého, za zmínku stojí asi jen
ošetření proti dělení nulou.
Máme hotovo Můžete si
vyzkoušet, že kalkulačka opravdu počítá a hlásí případné chyby.

V příští lekci, GridLayout v PyQt - Formulář s využitím tabulky, využijeme QGridLayout
pro
jednoduchou tvorbu přehledných formulářů.
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 797x (3.66 kB)
Aplikace je včetně zdrojových kódů v jazyce Python