2. diel - Aplikácie Kalkulačka v PyQt
Zdravím vás u ďalšej lekcie PyQt. V lekcii minulej, Zoznámenie s PyQt, Inštalácia a prvé okenné aplikácie v Python , sme si urobili úvod do tvorby formulárových aplikácií v Pythone a naprogramovali okenné Hello world. V dnešnom tutoriále si, ako bolo sľubované, vytvoríme aplikáciu Kalkulačka, ktorá bude vykonávať nasledujúce matematické operácie:
- súčet
- rozdiel
- súčin
- podiel
Potrebné widgety
Pre lepšiu orientáciu sa môžete pozrieť na už hotový formulár:
Aplikácia bude obsahovať nasledujúce widgety:
QWidget
- FormulárQLabel
- Popisok, tu použitý na výpis výsledkuQPushButton
- Tlačidlo pre výpočet- 2x
QLineEdit
- Jednoriadkové textové pole na zadanie čísla QComboBox
- Rozbaľovacia ponuka s výpočtovými operáciami- Layouty - Aby sme mohli widgety na formulár rozumne poskladať
Vytvorenie projektu
Vytvorte nový projekt, ja ten svoj uložím opäť ako main.py
.
Najprv si opäť importujete QWidgets
z PyQt5
a
sys
. Dnes si importujete tiež QtGui
, pretože ďalej
zmeníme font nášho QLabelu
s výsledkom.
from PyQt5 import QtWidgets, QtGui import sys
Hoci sme minule pracovali čisto procedurálne, bez objektov, ako len
jednoducho to išlo, je určite lepšie triedy pre svoje aplikácie používať.
Okno aplikácie preto tentoraz vytvoríme ako triedu, dedičov z
QtWidgets.QMainWindow
. Ukážme si jej kód, ktorý si vzápätí
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 odovzdať prípadné argumenty z príkazového
riadku a nastavíme titulok okna. Ďalšie inicializácii okná prenecháme
metóde init_gui()
. Nakoniec formulár zobrazíme. V metóde
init_gui()
vytvoríme formulár ako minule a uložíme si ho do
premennej formular
.
Layout
Celému formulári nastavíme layout na QVBoxLayout
,
V
v názve označuje vertikálnej. Widgety na formulári sa budú
teda skladať pod seba, na rozdiel od minulej lekcie, kde sme
použili QHBoxLayout
, kde H
označovalo horizontálne.
Následne pridáme do tohto zvislého layoutu ešte 2 vodorovné layouty. Tie
budú teda pod sebou a widgety v nich vložené sa budú skladať vedľa
seba.
Kód metódy init_gui()
sa rozrastie do nasledujúcej
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()
Ak ste sa v Layout stratili, pripravil som pre vás ilustráciu:
formularLayout
radiacej widgety pod seba je zvýraznený
červeno a layouty boxLayout1
a boxLayout2
v ňom
vložené, vkladajúce widgety vedľa seba, sú vyznačené zelene.
Pomocou addStretch()
pridáme voľné miesto, ktoré výsledok
vycentruje zvisle. Na obrázku vyššie je toto voľné miesto zvýraznené
modro.
Widgety
Máme hotové základné rozvrhnutie našej aplikácie, ktorá je vďaka použitiu layoutov responzívne. To znamená, že keď roztiahnete jej okno, layouty sa rovnomerne roztiahnu s ním a widgety v nich sa novej veľkosti tiež prispôsobí. Teraz vykonáme vloženie ďalších widgetov do layoutov:
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árame widgety, ktorých zoznam sme si uviedli v úvode lekcie. Do
boxLayout1
vložíme textová políčka cislo1Edit
a
cislo2Edit
, tiež operatorComboBox
s výberom
operácie a vysledekLabel
. Všimnite si pridávanie položiek do
operatorComboBox
. Druhý riadok, boxLayout2
, obsahuje
len vypoctiButton
.
Widgety sme pomenovali tak, aby končili názvom PyQt widgetu.
To je dobrá praktika, je tak jasné čo je v ktorej premennej uložené. Keby
sa vysledekLabel
volal len vysledek
, mohol by iný
programátor predpokladať, že sa jedná len o číslo a nie formulárový
prvok.
Možno vás zaujalo, že niektoré widgety sme uložili len ako lokálne
premenné a niektoré sme uložili ako atribúty triedy pomocou kľúčového
slova self
. Je to preto, aby sme s nimi mohli v aplikácii ešte
ďalej pracovať.
Posledný metóda setCentralWidget()
nastavuje náš formulár
ako hlavné okno a tým sa zobrazí po spustení aplikácie.
Na úplný koniec súboru dodáme niekoľko riadkov s tvorbou a spustenie aplikácie:
aplikace = QtWidgets.QApplication(sys.argv) okno = Window() sys.exit(aplikace.exec_())
Projekt si môžete teraz skúsiť spustiť, náš formulár vyzerá takto:
Skúste si ho zmenšiť a zväčšiť, nech vidíte, že je naozaj responzívne.
Udalosti
Teraz je potrebné nastaviť tlačidlu vypoctiButton
funkciu,
ktorá sa zavolá pri udalosti kliknutí na toto tlačidlo. Týmto funkciám sa
v programovaní často hovorí callback. Danú funkciu si
zatiaľ len pripravíme a na konci metódy init_gui()
ju
nadviažeme na tlačidlo.
def init_gui(self): # Předešlý kód metody init_gui() ... # ... self.vypoctiButton.clicked.connect(self.vypocti) def vypocti(self): pass # Zbytek souboru # ...
Pridáme logiku našej metódy 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
Najprv si vytvoríme pomocné premenné pre hodnoty, ktoré načítame z
ovládacích prvkov. To aby sme ďalej neopisoval dlhé názvy a volanie
ďalších metód. Z QLineEdit
získame text pomocou metódy
text()
. Vybranú položku QComboBox
získame metódou
currentText()
. Takmer celý kód je v bloku try
,
pretože funkcia float()
, prevádzajúcej text z textových polí
na číslo, môže spôsobiť chybu. V takom prípade program prejde ihneď do
bloku except
, chybu vypíše a výpočet sa vôbec neuskutoční.
Na samotnom výpočte nie je nič moc zaujímavého, za zmienku stojí asi len
ošetrenie proti delenie nulou.
máme hotovo Môžete si vyskúšať, že kalkulačka naozaj počíta a hlási prípadné chyby.
V budúcej lekcii, GridLayout v PyQt - Formulár s využitím tabuľky , na nás čaká ďalší projekt, tentoraz oveľa väčšieho rozsahu. Nechajte sa prekvapiť
V budúcej lekcii, GridLayout v PyQt - Formulár s využitím tabuľky , využijeme QGridLayout
pre
jednoduchú tvorbu prehľadných formulárov.
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é 775x (3.66 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python