IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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ál void numberTooBig(), ktorý je samozrejme dobré spracovať.
  • setPlus(), ... - Ako reakcia na kliknutie tlačidla výberu operácie použijeme sloty void setPlus()...
  • setHex(), ... - Keď sa prepne číselná sústava, sloty void 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 slot void 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 ikony

    Question -ikona otázky - Qt - Okenné / formulárové aplikácie v C ++

    Information -ikona informácie - Qt - Okenné / formulárové aplikácie v C ++

    Warning -ikona varovania - Qt - Okenné / formulárové aplikácie v C ++

    Critical -Ikona kritickej situácie - Qt - Okenné / formulárové aplikácie v C ++

  • NoIcon - bez ikony
  • Question -ikona otázky - Qt - Okenné / formulárové aplikácie v C ++
  • Information -ikona informácie - Qt - Okenné / formulárové aplikácie v C ++
  • Warning -ikona varovania - Qt - Okenné / formulárové aplikácie v C ++
  • Critical -Ikona kritickej situácie - Qt - Okenné / formulárové aplikácie v C ++
  • Ď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... alebo 1af4

    Oct = 017.. 02...

    Bin = 100011100, bohužiaľ tvar 0b010101 nie je akceptovaný

  • Hex = 0x1af4... alebo 1af4
  • Oct = 017.. 02...
  • Bin = 100011100, bohužiaľ tvar 0b010101 nie je akceptovaný
Okenné kalkulačka v C ++ a Qt - Qt - Okenné / formulárové aplikácie v C ++

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é 92x (13.13 kB)
Aplikácia je vrátane zdrojových kódov v jazyku C++

 

Predchádzajúci článok
Jednoduchá kalkulačka v Qt a C ++ - Model
Všetky články v sekcii
Qt - Okenné / formulárové aplikácie v C ++
Preskočiť článok
(neodporúčame)
QString - Dokončenie a súhrn základných reťazcových kolekcií
Článok pre vás napísal Virlupus
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje webovým aplikacím, skladově-účetnímu softwaru, 3D grafice, lexiální analýze a parserování. Studuje fyziku na MFF UK. Učil IT na střední škole.
Aktivity