Semplice Calcolatrice con le Qt

Qt logo

Del framework Qt per la creazione di interfacce grafiche abbiamo già parlato nel precedente articolo introduttivo. Presa familiarità con l'IDE QtCreator e assodato di conoscere discretamente il c++, adesso è venuto il momento di realizzare un piccolo programma per provare queste librerie.
Ho deciso di realizzare una piccola calcolatrice, in grado di svolgere le quattro operazioni aritmetiche di base. In questo articolo, spiego i passi principali della sua creazione, incentrandomi soprattuto sulla fase di creazione della veste grafica e sul meccanismo di comunicazione tra oggetti Signals and Slots. Vorrei inoltre evitare di tediarvi spiegando riga per riga tutti i dettagli implementativi, sia perchè non sarebbe sufficiente un solo articolo sia perchè lo scopo è illustrare i meccanismi principali di questo framework. Comunque in fondo all'articolo trovate lo zip del progetto, che potete liberamente modificare ed estendere, aggiungendo nuove funzionalità. Qui sotto avete un assaggio della semplice veste grafica della calcolatrice
 

 

Per prima cosa, occorre scegliere il tipo di progetto da realizzare. Per la calcolatrice, ho scelto di creare una semplice QDialog senza barra di menu.
Dal menu File, selezionate la voce New File or Project... e seguite la procedura di creazione di una QDialog. La procedura viene spiegata nel mio precedente articolo per una QMainWindow.
Nella scheda d'installazione Class Information scrivete il nome della classe, ad esempio Calcolatrice e nella casella etichettata Base Class selezionate la voce QDialog. Lasciate tutti gli altri campi come sono e, una volta terminata la procedura, il vostro progetto sarà strutturato nel seguente modo:
 

Il file Calcolatrice.pro è il file che utilizza QMake per generare il Makefile, con cui poi si esegue il build del progetto. Oltre alla cartella degli headers e dei codici sorgente, in basso notiamo il Qt Designer UI file calcolatrice.ui, il codice xml che rappresenta l'interfaccia grafica con il widget principale, i suoi figli, layouts e tutte le sue connessioni principali. I Qt Designer UI files vengono poi convertiti in codice c++ staticamente in fase di compilazione con tools integrati come qmake e uic o dinamicamente in fase di esecuzione tramite la classe QUiLoader. Noi utilizziamo la seconda procedura.

 
 

INTERFACCIA GRAFICA

 
Per costruire l'interfaccia grafica clicchiamo due volte sul file calcolatrice.ui per aprire la scheda Design. Iniziamo creando i 10 testi numerici e il punto per i numeri in formato decimale, trascinando il tasto Push Button, che si trova nel menu di sinistra dei widgets e layouts, sulla finestra della nostra interfaccia. Ridimensioniamo con il mouse i tasti e non preoccupiamoci della loro posizione.
Otterremo una situazione del genere:

Adesso creiamo un grid Layout per sistemare automaticamente tutti i tasti. Sebbene ogni widgets erediti dalla classe QWidget il metodo setGeometry() che permette di modificare staticamente la sua posizione e dimensione, si preferisce quasi sempre organizzarli in maniera più flessibile in layouts.
Selezionamo tutti i nostri bottoni, clicchiamo con il tasto destro del mouse e selezioniamo la voce Lay Out > Lay Out in a Grid.
Risistemando un pò con il mouse, il risultato dovrebbe essere questo:
.
Adesso applichiamo la stessa procedura per i tasti delle operazioni aritmetiche e i tasti CE e C. Nel mio progetto ho applicato un VerticalLayout per i primi e un HorizontalLayout per i secondi.
And Last but not Least la casella di testo per scrivere gli operandi e i risultati delle operazioni. Scorrete nella scheda Input Widgets del menu dei widgets e layouts e trascinate il tasto Line Edit nel punto della finestra in cui volete posizionarla.
Una volta inseriti tutti i widgets, provvedete a denominarli in maniera ordinata e dovreste ottenere come risultato finale la seguente interfaccia:

Interfaccia finale con struttura dei widgets nella colonna di destra

 
 

SIGNALS AND SLOTS

 
Terminata l'interfaccia grafica, dobbiamo occuparci di far comunicare tra loro i widgets. Ad esempio cliccando sul tasto 1 vogliamo comunicare all'oggetto QlineEdit di scrivere sulla casella di testo la cifra 1.
Il meccanismo offerto da Qt è quello dei Signals and Slots.
I Signals sono messaggi emessi da un oggetto quando cambia il suo stato interno, ad esempio il segnale clicked() viene lanciato da un button quando questo viene cliccato dall'utente. Ogni oggetto istanza di QObject o di una classe derivata ha dei signals predefiniti, ma è sempre possibile definire una sottoclasse di un widget ed aggiungerne di nuovi.
Gli Slots invece sono funzioni membro chie possono essere chiamate o in risposta a un segnale o normalmente come una qualsiasi funzione c++.
Un segnale di un oggetto può essere connesso agli slots di uno o più oggetti, premesso che le lista dei parametri del segnale e dello slot siano compatibili. Per Qt, lo slot deve avere un numero di parametri pari almeno a quello del segnale.
La connessione viene effettuata tramite il metodo connect di QObject

bool QObject::connect(senderQObjectPtr,
             SIGNAL(signalName(argumentList)),
             receiverQObjectPointer,
             SLOT(slotName(argumentList))
             optionalConnectionType);

senderQObjectPtr è l'oggetto che invia il segnale,
SIGNAL(signalName(argumentList)) è il segnale
receiverQObjectPointer è l'oggetto che riceve il segnale
SLOT(slotName(argumentList)) è lo slot chiamato in risposta al segnale
optionalConnectionType è un parametro opzionale che noi non utilizziamo. Vedete le api per una spiegazione più dettagliata

Andiamo ad analizzare una connessione signal-connect per il tasto "=" della calcolatrice, che trovate nel file calcolatrice.cpp del progetto.

        connect(ui->pushButton_eq, SIGNAL(clicked()), calcManager, SLOT(calc()));

In questo caso l'oggetto pushButton_eq (il pulsante "=") emette il segnale click(), che è ricevuto dallo slot calc() dell'oggeto calcManager (istanza della classe CalcManager da me aggiunta per gestire le operazioni di calcolo). Nel file calcManager.cpp, lo slot calc() è definito come segue:

void CalcManager::calc(){

        _operand=ui->lineEdit->text().toDouble();
        doOperation();
        QString res=QString::number(_result,'f');
        res.remove( QRegExp("0+$") );
        res.remove( QRegExp("\.$") );
        ui->lineEdit->setText(res);
        _operand=ui->lineEdit->text().toDouble();
        _operation=Nothing;
        _eraseOperand=true;
}

Tralasciando i dettagli, possiamo vedere che in calc() viene effettuata l'operazione (doOperation()) e viene stampato a video nella casella di testo lineEdit il risultato res.

Infine vediamo un uso più avanzato del meccanismo signals and slots: la classe QSignalMapper . Questa classe viene utilizzata per le frequenti situazioni in cui più segnali sono connessi allo stesso slot e lo slot ha bisogno di gestire ogni segnale differentemente. QSignalMapper è impiegata soprattuto nei casi in cui si vuole connettere un set di segnali con un solo slot che ha più parametri dei segnali ricevuti. Ad esempio, nel caso della calcolatrice, per connettere i segnali click() del tastierino numerico con un solo slot buttonClicked(QString), non potremmo impiegare il normale meccanismo signal-slot a causa dell'incompatibilità dei parametri.
Il seguente frammento di codice riporta l'implementazione di questo meccanismo per i pulsanti del tastierino numerico. In seguito spieghiamo le funzioni utilizzate.


        QSignalMapper *signalMapper = new QSignalMapper(this);

        signalMapper->setMapping(ui->pushButton_0, QString::number(0));
        signalMapper->setMapping(ui->pushButton_1, QString::number(1));
        signalMapper->setMapping(ui->pushButton_2, QString::number(2));
        signalMapper->setMapping(ui->pushButton_3, QString::number(3));
        signalMapper->setMapping(ui->pushButton_4, QString::number(4));
        signalMapper->setMapping(ui->pushButton_5, QString::number(5));
        signalMapper->setMapping(ui->pushButton_6, QString::number(6));
        signalMapper->setMapping(ui->pushButton_7, QString::number(7));
        signalMapper->setMapping(ui->pushButton_8, QString::number(8));
        signalMapper->setMapping(ui->pushButton_9, QString::number(9));
        signalMapper->setMapping(ui->pushButton_point, QString("."));

        connect(ui->pushButton_0, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_1, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_2, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_3, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_4, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_5, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_6, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_7, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_8, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_9, SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(ui->pushButton_point, SIGNAL(clicked()), signalMapper, SLOT(map()));

        connect(signalMapper, SIGNAL(mapped(QString)), calcManager, SLOT(buttonClicked(QString)));

Dopo aver creato l'oggetto signalMapper istanza della classe QSignalMapper, associamo tramite la funzione setMapping() una stringa diversa per ogni pulsante (a pushButton_1 la stringa "1", a pushButton_2 la stringa "2" e così via fino a pushButton_point a cui associamo la stringa "."). Poi con la funzione connect, connettiamo il segnale click() dei tasti con lo slot map() di QSignalMapper.
Lo slot map() emetterà poi il segnale mapped(QString) con la stringa precedentemente associata all'oggetto che ha generato il segnale originario.
Infine l'ultimo connect associa il segnale mapped(QString) allo slot buttonClicked(QString) dell'oggetto calcManager.

Quanto è stato spiegato finora non copre ovviamente tutta la realizzazione del progetto, ma ha come scopo quello di chiarire i meccanismi e i concetti principali del framework Qt.
Qui trovate lo zip della Calcolatrice.
Siete ovviamente liberi di modificare il codice e se volete chiedermi qualcosa non esitate a farlo postando un commento.

Fonti:

Semplice Calcolatrice con le Qt ultima modifica: 2012-11-02T03:02:34+01:00 da marcopaci


Advertisment ad adsense adlogger