Lekce 5 - Jednoduchá kalkulačka v Qt a C++ - Layout
V minulé lekci, Řetězce v Qt - QString a QChar, jsme něco pověděli o řetězcích v Qt a v C++.
Dnes začneme tvořit již nějakou zajímavější aplikaci, velmi jednoduchou kalkulačku. Bude mít dvě vstupní pole a čtyři základní operace: násobení, dělení, sčítání a odečítání.
Dnes nám bude stačit obyčejné okno bez toolbarů, menu, stavového
řádku a takových podobných vymožeností
Qt je založeno na architektuře MVC, tedy
přesněji řečeno na architektuře Model - View, protože
pohled zastupuje i funkci controlleru - zpracování
požadavků. Pokud jste se s touto architekturou ještě nesetkali,
důležité je, že oddělujeme kód logiky aplikace (v našem případě nyní
třída s výpočty pro kalkulačku) od prezentace, což je v našem případě
kód definující a obsluhující formulář. Nikdy tedy nebudeme
provádět nic složitého přímo v souboru s formulářem, ale pouze zde
provoláme metody nějaké další třídy, ve které bude další kód
umístěný.
Návrh aplikace
Celý návrh můžeme udělat několika způsoby:
- Od modelu - tedy prvně navrhnout, co bude základ logiky, a to potom zobrazit ve formuláři.
- Od view - pohledu: tedy prozkoumat, co budeme zobrazovat, a pak si k tomu udělat logickou část.
- Od každého něco - postupně něco zobrazit. Pak udělat kus logiky, zas to zobrazit, nebo i opačně.
Zde jsem zvolil druhou variantu. Vytvoříme si nejprve kompletní okno a jeho rozvržení, čímž se rozhodneme, co kde má být zobrazeno. Teprve potom, v příští lekci, si vytvoříme třídu, která nám potřebná data poskytne, když o ně požádáme.
Návod k použití aplikace
Kalkulačka bude fungovat takto:
- Zadáme celé číslo do jednoho pak do druhého vstupního pole
- Zvolíme operaci mezi čísly
- Zvolíme číselnou soustavu k zobrazení
- Stiskneme tlačítko pro výsledek. Ten se ukáže, pokud nenastala chyba.
Při chybě zadání, nebo jiné chybě, se zobrazí krátký dialog pomocí
QMessageBox.
Založení projektu
Projekt tentokrát založíme jen na QWidget, který můžeme
použít i jako základ aplikace. Dřívější lekce měly za úkol ukázat
základ komplexní aplikace a z čeho se skládá celé okno, proto jsme v nich
použili QMainWindow. V kalkulačce ovšem nebudeme potřebovat
menu, toolbar a jiné věci. Právě proto raději použijeme
QWidget, který bude fungovat jako plnohodnotné okno i s ikonou,
titulkem, frontou událostí a vším potřebným.
Nový projekt již založit umíme. Jen v jedné chvíli to chce maličkou
změnu. Předně si pojmenujeme třídu okna Kalkulacka, hlavně
žádná diakritická znaménka, a QMainWindow změníme na
QWidget:

Též jsem si pro vás připravil ikonu okna:
Tu již také umíme nastavit. Přidáme nový soubor Qt - Resource. Klidně si ikonu můžete stáhnout a použít. Nebo si udělat svoji či najít jinou vhodnou. Jinak je postup vlastně stejný jako v dřívějších lekcích.
Návrh uživatelského rozhraní
Jsem ze staré školy a rád používám papír a tužku. Prostě když chci udělat nějakou grafiku v programu, tak si ji nakreslím na papír a potom se rozhodnu jaká technika na to bude nejlepší. Ani zde to nebude jinak:

Když jsem se dlouho díval na obrázek výše, došlo mi, že tabulka
(mřížka) je zcela ideální pro rozvržení všech prvků. Použijeme tedy QGridLayout. Je
to velmi flexibilní rozvržení. Každý prvek má svou vlastní "buňku",
ovšem může jich mít i několik - jak v řádku tak i v sloupci. Též lze
nastavit i různé mezery mezi buňkami. Výsledný formulář pro kalkulačku
bude potom vypadat následovně:

Nemohl jsem odolat a proto výsledek budeme zobrazovat jako na opravdovém
segmentovém displeji kalkulačky. Je pravda, že ovládací prvek QLCDNumber umí
zobrazit jen celá čísla, zato v několika soustavách - šestnáctková,
decimální, osmičková a binární. Toho přeci musíme také využít, proto
přidáme i čtyři přepínače - QRadioButton,
které umožní změnit zobrazení pro danou číselnou soustavu.
Abychom nemuseli řešit, jaké číslo nebo text uživatel zadal, použijeme
pro každý operand (číslo) zvláštní vstup. Ten bude bohužel pouze
textový QLineEdit, ze
kterého získáme řetězec QString, tedy i tak si budeme muset
zajistit, aby uživatel opravdu vložil celé číslo a ne cosi podivného.
Dlouho jsem rozmýšlel, zda pro volbu operace použít tlačítka, seznam
nebo rozbalovací seznam - ComboBox... Výhra padla opět na
RadioButton, uživatelsky je to pro tento účel přívětivé. Jenže
zde budeme mít dvě sady přepínačů a Qt vše, co se definuje v
jednom kontextu, bere, že to k sobě patří. Tedy tyto dvě skupiny musíme od
sebe oddělit. K tomu doslova vybízí třída QButtonGroup.
Pro zobrazení výsledku výpočtu bude potom nejlepší obyčejné tlačítko.
kalkulacka.h
Nejprve si modifikujeme hlavičkový soubor kalkulačky, kde doplníme
potřebné ukazatele. Jinak si myslím, že v tomto souboru není extra co
vysvětlovat. O všech použitých třídách si ještě podrobněji povíme u
souboru kalkulacka.cpp. Obsah kalkulacka.h je
následující:
#ifndef KALKULACKA_H #define KALKULACKA_H #include <QWidget> #include <QGridLayout> #include <QLCDNumber> #include <QRadioButton> #include <QButtonGroup> #include <QLineEdit> #include <QPushButton> class Kalkulacka : public QWidget { Q_OBJECT public: Kalkulacka(QWidget *parent = 0); ~Kalkulacka(); QGridLayout *mainLayout; QLCDNumber *display; QRadioButton *btnDec; QRadioButton *btnHex; QRadioButton *btnOct; QRadioButton *btnBin; QButtonGroup *numeralButtons; QLineEdit *leftOperand; QLineEdit *rightOperand; QRadioButton *btnPlus; QRadioButton *btnMinus; QRadioButton *btnTimes; QRadioButton *btnDivide; QButtonGroup *operationButtons; QPushButton *btnEqual; }; #endif // KALKULACKA_H
kalkulacka.cpp
Rovnou přejdeme i do souboru s implementací a vložíme do něj následující kód, který si záhy vysvětlíme:
#include "kalkulacka.h" #include <QIcon> Kalkulacka::Kalkulacka(QWidget *parent) : QWidget(parent) { mainLayout = new QGridLayout(); display = new QLCDNumber(); mainLayout->addWidget(display, 1, 1, 1, 4); btnHex = new QRadioButton("HEX", this); btnDec = new QRadioButton("DEC", this); btnOct = new QRadioButton("OCT", this); btnBin = new QRadioButton("BIN", this); numeralButtons = new QButtonGroup(); mainLayout->addWidget(btnDec, 2, 1); mainLayout->addWidget(btnHex, 2, 2); mainLayout->addWidget(btnBin, 2, 3); mainLayout->addWidget(btnOct, 2, 4); numeralButtons->addButton(btnHex); numeralButtons->addButton(btnDec); numeralButtons->addButton(btnOct); numeralButtons->addButton(btnBin); leftOperand = new QLineEdit(); rightOperand = new QLineEdit(); mainLayout->addWidget(leftOperand, 3, 1, 1, 2); mainLayout->addWidget(rightOperand, 3, 3, 1, 2); btnPlus = new QRadioButton("+", this); btnMinus = new QRadioButton("-", this); btnTimes = new QRadioButton("*", this); btnDivide = new QRadioButton("/", this); operationButtons = new QButtonGroup(); operationButtons->addButton((btnPlus)); operationButtons->addButton((btnMinus)); operationButtons->addButton((btnTimes)); operationButtons->addButton((btnDivide)); mainLayout->addWidget(btnPlus, 4, 1); mainLayout->addWidget(btnMinus, 4, 2); mainLayout->addWidget(btnTimes, 4, 3); mainLayout->addWidget(btnDivide, 4, 4); btnEqual = new QPushButton(tr("Spočítej")); mainLayout->addWidget(btnEqual, 5, 1, 1, 4); setLayout(mainLayout); btnDec->setChecked(true); btnPlus->setChecked(true); } Kalkulacka::~Kalkulacka() { if (btnEqual != NULL) { delete btnEqual; } if (operationButtons != NULL) { delete operationButtons; } if (btnPlus != NULL) { delete btnPlus; } if (btnMinus != NULL) { delete btnMinus; } if (btnTimes != NULL) { delete btnTimes; } if (btnDivide != NULL) { delete btnDivide; } if (leftOperand != NULL) { delete leftOperand; } if (rightOperand != NULL) { delete rightOperand; } if (numeralButtons != NULL) { delete numeralButtons; } if (btnHex != NULL) { delete btnHex; } if (btnDec != NULL) { delete btnDec; } if (btnBin != NULL) { delete btnBin; } if (btnOct != NULL) { delete btnOct; } if (mainLayout != NULL) { delete mainLayout; } setWindowIcon(QIcon(":/img/mainIcon")); resize(640, 480); }
Na úplném začátku jsme vytvořili objekt tabulkového layoutu a
následně objekt LCD a umístili jej do layoutu pomocí
mainLayout->addWidget(display, 1, 1, 1, 4);. Zde stojí za
všimnutí parametry, který mi jsou:
- ukazatel na widget
- řádek v tabulce - počítáno od
1don - sloupek v tabulce - opět od
1don - počet sloučených řádků, přes které má ovládací prvek přesahovat
(pro hodnotu
1se nic nestane) - počet sloučených sloupců, zde tedy prvek zabere
4sloupce
Poté vyrobíme první skupinu přepínačů pro přechody z jedné
číselné soustavy do druhé a umístíme ji do layoutu pomocí
mainLayout->addWidget(btnDec, 2, 1);... Tak přidáme i skupiny
tlačítek: operationButtons->addButton((btnPlus));... Zde si
lze všimnout, že dva parametry jsme vynechali, protože nejsou potřebné a Qt
nám to umožňuje. Jednoduše jen volíme řádek a sloupec.
Pro jistotu znovu pro zapamatování:
QGridLayout si své pozice čísluje od jedničky,
nikoli od nuly jako pole v C.
leftOperand = new QLineEdit(); a
rightOperand = new QLineEdit(); jsou dvě důležitá editační
políčka k vložení dvou vstupních čísel. Samozřejmě je hned umístíme
do "tabulky" rozložení prvků jako
mainLayout->addWidget(leftOperand, 3, 1, 1, 2);. Každé z nich
bude zabírat polovinu řádku, tedy 2 sloupce.
Následují "přepínače" pro početní operace. Zde asi není také není moc co vysvětlovat, protože je to stejný postup, který byl použit u *přepínačů" číselných soustav.
Celý layout nakonec vložíme do widgetu pomocí
setLayout(mainLayout); a pro jistotu, aby bylo jasné, že
počítáme v dekadické soustavě a základní operace je sčítání,
nastavíme dané přepínače jako aktivní/zapnuté:
btnDec->setChecked(true); a
btnPlus->setChecked(true);
A zcela na konec si nastavíme ikonu a velikost okna:
setWindowIcon(QIcon(":/img/mainIcon")); resize(640, 480);
Jako poslední máme tlačítko pro výpočet. Takové již jsme dělali skoro na počátku kurzu. Ovšem zde je drobná změna, která asi bude později dost důležitá a myslím, že se z ní stane i dost dobrý zvyk.
Mezinárodní rozhraní
btnEqual = new QPushButton(tr("Spočítej"));
Na kódu výše je samozřejmě zajímavé použití funkce
tr(QString). Ta se dá vyložit jako: přelož řetězec. Tedy
pokud všechny řetězce budeme uzavírat do této funkce, máme aplikaci
připravenou k případným vícejazyčným mutacím. Během kurzu si tyto
možnosti ještě představíme.
Závěr
Tím máme hotové rozvržení aplikace. Klidně si ji přeložte a spusťte.
Sice nic zatím nedělá, ale vypadá hezky 
Příště, v lekci Jednoduchá kalkulačka v Qt a C++ - Model, si vytvoříme jednoduchý model. Sice je kalkulačka jednoduchá, ale pracujeme v MVC (MV) frameworku, tak by bylo dobré dodržet tuto architekturu. Opravdu se bude hodit později, když si osvojíme dobré návyky co nejdříve. Příště také ošetříme uživatelské vstupy a zprovozníme přepínače.
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 85x (12.46 kB)
Aplikace je včetně zdrojových kódů v jazyce C++
