7. diel - Jednoduchá kalkulačka v Qt a C ++ - Dokončenie
V minulej lekcii, Jednoduchá kalkulačka v Qt a C ++ - Model , sme si pripravili modelovú vrstvu pre našej formulárové aplikáciu v C ++ a frameworku Qt. Dnes formulár a modelovú vrstvu pospojíme a kalkulačku tak dokončíme, čím získame svoju prvú naozajstnú formulárové C ++ aplikáciu!
Kalkulacka.h
Ako vždy začneme od hlavičkového súboru. Nutné je pridať tu hlavičku
súboru model.h
a jednu členskú premennú - odkaz na náš
model:
... #include "model.h ... private: Model *model;
Sloty
Tiež budeme prijímať mnoho signálov zvonku a niečo ich musí zachytávať. Potrebujeme teda nejaké sloty:
... public slots: void numberTooBig(); void setPlus(); void setMinus(); void setTimes(); void setDivide(); void setHex(); void setDec(); void setOct(); void setBin(); void getFalseOp(int operand); void getZeroDivide(); void calculate(); ...
Pridali sme nasledujúce sloty:
numberTooBig()
- Pri výsledku, ktorý sa nezmestí na display,QLCDNumber
pošle signálvoid numberTooBig()
, ktorý je samozrejme dobré spracovať.setPlus()
, ... - Ako reakcia na kliknutie tlačidla výberu operácie použijeme slotyvoid setPlus()
...setHex()
, ... - Keď sa prepne číselná sústava, slotyvoid setHex()
a ďalšie podobné sa postarajú o príslušnú akciu.getFalseOp()
- Model nám môže poslať signál o chybe vstupe a my si ho spracujeme.getZeroDivide()
- Možno po kalkulačke bude niekto chcieť, aby niečo vydelila nulou. Túto situáciu si vezme na starosť tento slot.calculate()
- A konečne klikneme na tlačidlo "spočítaj". To bude mať za úlohu slotvoid calculate()
.
Kalkulacka.cpp
V hlavičke máme všetko definované a môžeme prejsť k implementácii.
QMessageBox
Občas potrebujeme informovať užívateľa o nejakých udalostiach. QMessageBox
je
na to ako stvorený. Vložíme si jeho hlavičku do súboru:
...
#include <QMessageBox>
...
Ako message box ovládať si ukážeme za okamih.
Konštruktor
Teraz sa pozrieme na konštruktor a pridáme do neho niekoľko riadkov:
... display->setDigitCount(32); display->setMaximumHeight(50); model = new Model(this); ...
Nášmu displeji hovoríme koľko číslic bude vedieť zobraziť. Myslím,
že 32
je dosť aj pre binárne čísla.
setDigitCount(n)
nám hovorí, koľko číslic display bude vedieť
zobraziť. Povolený rozsah je od žiadnej číslica až do 99 čísel na
displeji.
- Keďže sa mi zdá display nejako moc vysoký a čísla moc veľká, tak mu
upravíme výšku na
50
px. - Nutne potrebujeme objekt nášho modelu, aby sme s ním mohli komunikovať. Teda si ho hneď vytvoríme. Nezabudneme ho v destruktor tiež zmazať, ten nasleduje nižšie.
// Destruktor Kalkulacka::~Kalkulacka() { // Zde zničit vše, co jsme stvořili if (model != nullptr) { delete model; } if (btnEqual != nullptr) { delete btnEqual; } if (operationButtons != nullptr) { delete operationButtons; } if (btnPlus != nullptr) { delete btnPlus; } if (btnMinus != nullptr) { delete btnMinus; } if (btnTimes != nullptr) { delete btnTimes; } if (btnDivide != nullptr) { delete btnDivide; } if (leftOperand != nullptr) { delete leftOperand; } if (rightOperand != nullptr) { delete rightOperand; } if (numeralButtons != nullptr) { delete numeralButtons; } if (btnHex != nullptr) { delete btnHex; } if (btnDec != nullptr) { delete btnDec; } if (btnBin != nullptr) { delete btnBin; } if (btnOct != nullptr) { delete btnOct; } if (mainLayout != nullptr) { delete mainLayout; } }
Rada k novšiemu prostredie QtCreator: Miesto NULL
používajte nullptr
, čo je skutočný ukazovateľ na "nulu" a nie
len makro "nuly". Norma C ++ 11 nechce číslo, ale naozaj skutočný
ukazovateľ. V ďalšom kóde sa tejto normy budeme držať. Síce funkčne je
to zhodné, ale modernizácie ide vpred a môže sa stať, že prekladača budú
podporovať iba túto normu.
Prepojenie tlačidiel ku slotům
V konstruktoru budeme ďalej pripájať tlačidla ku slotům. Najprv zmeny
číselných sústav. Každé tlačidlo pošle signál clicked()
a
my k nemu pripravíme patričný slot. Ten napojíme na metódu, ktorú neskôr
vytvoríme. Ovšem prepojiť sloty s metódami môžeme hneď, aj keď zatiaľ
neexistujú:
... connect(btnBin, SIGNAL(clicked()), this, SLOT(setBin())); connect(btnOct, SIGNAL(clicked()), this, SLOT(setOct())); connect(btnDec, SIGNAL(clicked()), this, SLOT(setDec())); connect(btnHex, SIGNAL(clicked()), this, SLOT(setHex())); ...
Nasledujú tlačidlá jednotlivých operácií:
... connect(btnPlus, SIGNAL(clicked()), this, SLOT(setPlus())); connect(btnMinus, SIGNAL(clicked()), this, SLOT(setMinus())); connect(btnTimes, SIGNAL(clicked()), this, SLOT(setTimes())); connect(btnDivide, SIGNAL(clicked()), this, SLOT(setDivide())); ...
A zostáva nám posledné tlačidlo pre výpočet:
...
connect(btnEqual, SIGNAL(clicked()), this, SLOT(calculate()));
...
Overflow displeja
Komponent QLCDNumber
pri pretečeniu povolenej dĺžky čísla
posiela signál overflow()
. Síce nie je nutné na neho reagovať,
ale užívateľ by sa mohol čudovať, že má zobrazenú nulu. Preto si
myslím, že je vhodné ho na to upozorniť. Teda tento signál si prepojíme so
slotom, ktorý na túto skutočnosť bude reagovať:
...
connect(display, SIGNAL(overflow()), this, SLOT(numberTooBig()));
...
Ďalšie chybové stavy
Nesmieme zabúdať, že používateľ je schopný do vstupu zadať všetko možné a väčšinou to nie je správne. Je potrebné ho na to upozorniť nejakú prívetivú správou.
Signály z modelu si teda prepojíme s chybovými sloty. Všimnite si, že
operandFalse(int)
je len s typom argumentu. Jeho názov tu
neuvádzame:
... connect(model, SIGNAL(operandFalse(int)), this, SLOT(getFalseOp(int))); connect(model, SIGNAL(zeroDivide()), this, SLOT(getZeroDivide())); ...
Implementácia metód slotov
Tým máme konštruktor hotový. Nastal čas sloty implementovať.
Početné operácie
Začneme výpočtovými operáciami:
void Kalkulacka::setPlus() { model->setOperator(Model::OP_PLUS); } void Kalkulacka::setMinus() { model->setOperator(Model::OP_MINUS); } void Kalkulacka::setTimes() { model->setOperator(Model::OP_TIMES); } void Kalkulacka::setDivide() { model->setOperator(Model::OP_DIVIDE); }
Jednoducho len povieme modelu, akú operáciu chceme vykonávať. Použijeme k komu "jeho" koeficientu a členské funkcie. Myslím, že nič zložitého.
Prepínanie číselných sústav
Prepínanie sústav o nejakom základe je tiež jednoduché. Iba využijeme
skutočnosti, že slot je štandardné funkcie, ktorú možno zavolať, keď je
potreba. Komponent QLCDNumber
obsahuje sloty pre prepínanie
sústav: setHexMode()
atď. Alebo
setMode(QLCDNumber::Mode)
, kde Mode
môže byť
HEX
, DEC
, OCT
, BIN
. V našom
prípade je príkaz teda napr. display->setHexMode()
.
Samozrejme je treba o týchto zmenách informovať aj model a to
spôsobom: model->setNumBasis(Model::SYS_HEX);
.
Dodajme teda metódy aj pre tieto signály:
void Kalkulacka::setHex() { display->setHexMode(); model->setNumBasis(Model::SYS_HEX); } void Kalkulacka::setDec() { display->setDecMode(); model->setNumBasis(Model::SYS_DEC); } void Kalkulacka::setOct() { display->setOctMode(); model->setNumBasis(Model::SYS_OCT); } void Kalkulacka::setBin() { display->setBinMode(); model->setNumBasis(Model::SYS_BIN); }
Chybové hlášky
Poďme informovať užívateľa, že niečo spáchal inak, než je potrebné. A alebo, že sa stalo niečo podivného.
Veľké číslo
Začneme tým moc veľkým číslom:
void Kalkulacka::numberTooBig() { QMessageBox message(QMessageBox::Information, tr("Příliš dlouhé číslo"), tr("Buhužel číslo se nevejde na display")); message.exec(); }
Vidíme, že message box zobrazíme metódou exec()
. Oveľa
zaujímavejšie sú ale parametre pri jeho vytvorení:
- Prvým je ikona.
QMessageBox
disponuje nasledujúcimi už prednastavenými ikonami:NoIcon
- bez ikonyQuestion
-Information
-Warning
-Critical
-
NoIcon
- bez ikonyQuestion
-
Information
-
Warning
-
Critical
-
- Ďalším parametrom je titulok. Ten tu máme opäť pripravený pre
prípadné preklady aplikácie do iných jazykov pomocou funkcie
tr()
. - Posledným parametrom je tu text správy.
Možností je ešte viac, ale o tom si budeme hovoriť až sa dostaneme k dialógom v niektorej z ďalších lekcií.
Chybný vstup
Reakcia na chybný vstup bude opäť vo forme správy. Tu sa len musíme
rozhodnúť, ktorý to že operand bol zle
if (operand == Model::OP_LEFT)
... Pokiaľ bude chyba v oboch, model
pošle signály dva (postupne) a teda sa zobrazí aj dve správy:
void Kalkulacka::getFalseOp(int operand) { if (operand == Model::OP_LEFT) { QMessageBox msg(QMessageBox::Critical, tr("Číslo na levé straně"), tr("Někdě se stala chyba. Špatný formát čísla nebo nebylo zadáno vůbec")); msg.exec(); } else { QMessageBox msg(QMessageBox::Critical, tr("Číslo na pravé straně"), tr("Někde se stala chyba. Špatný formát čísla nebo nebylo zadáno vůbec")); msg.exec(); } }
Delenie nulou
Delenie nulou je oznámené tiež dialógom:
void Kalkulacka::getZeroDivide() { QMessageBox msg(QMessageBox::Critical, tr("Dělení nulou"), tr("Lituji, ale tato operace nemá definovaný výsledek!!!")); msg.exec(); }
Výpočet
Ostáva nám už len samotný výpočet, teda reakcia na vypočítávací tlačidlo:
void Kalkulacka::calculate() { model->setLeft(leftOperand->text()); model->setRight(rightOperand->text()); int result = model->calculate(); display->display(result); }
Najprv nastavíme ľavý a pravý operand. QLineEdit
disponuje funkciou text()
, ktorá vracia obsah editačného poľa
ako QString
.
Tento text odovzdáme modelu ako
model->setLeft(leftOperand->text())
. Model následne
požiadame o výsledok pomocou int result = model->calculate()
.
Komponent QLCDNumber
má metódu display(int)
, ktorá
výsledné číslo zobrazí.
Záverom
Naši kalkulačku máme hotovú a jej kompletné zdrojové kódy si môžete stiahnuť nižšie. Na záver ale ešte niekoľko poznámok:
- Čísla zadávajte v tvare zvolenej sústavy: Hex =
0x1af4
... alebo1af4
Oct =
017
..02
...Bin =
100011100
, bohužiaľ tvar0b010101
nie je akceptovaný - Hex =
0x1af4
... alebo1af4
- Oct =
017
..02
... - Bin =
100011100
, bohužiaľ tvar0b010101
nie je akceptovaný
Nabudúce, v lekcii QString - Dokončenie a súhrn základných reťazcových kolekcií , sa pozrieme na ďalšie zvláštnosti triedy
QString
. A keď zostane miesto, tak i na nejaké kolekcie ako je
QVector
, QList
a tak podobne, pretože sa nám
vzápätí budú tieto informácie hodiť.
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é 96x (13.13 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C++