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
1
don
- sloupek v tabulce - opět od
1
don
- počet sloučených řádků, přes které má ovládací prvek přesahovat
(pro hodnotu
1
se nic nestane) - počet sloučených sloupců, zde tedy prvek zabere
4
sloupce
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 84x (12.46 kB)
Aplikace je včetně zdrojových kódů v jazyce C++