Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Creare un'applicazione con Qt Widgets

Il modulo Qt Widgets del framework Qt permette di realizzare applicazioni desktop con interfaccia grafica in linguaggio C++: ecco come.
Il modulo Qt Widgets del framework Qt permette di realizzare applicazioni desktop con interfaccia grafica in linguaggio C++: ecco come.
Link copiato negli appunti

Tra le svariate tipologie di progetto che Qt Creator include, vi è anche quella relativa alla definizione di progetti basati sul modulo Qt Widgets per la creazione di applicazioni desktop con interfaccia grafica.

Il wizard per la creazione di progetti è disponibile alla voce File -> New file or project dal menù principale di Qt Creator, ed è strutturato in diversi passaggi. Il primo di essi riguarda proprio la tipologia di progetto, che nel caso specifico è Qt Widgets Application, come mostrato nella figura seguente.

I passi successivi del wizard riguardano la selezione del nome del progetto e della sua cartella di destinazione, i kit da utilizzare per la compilazione ed il deployment dell'eseguibile, ed il sistema di versioning usato.

Al termine del wizard, il progetto verrà serializzato su disco e caricato automaticamente in Qt Creator in modalità di editing dei sorgenti. Se non abbiamo ancora verificato l'installazione dello SDK di Qt, è opportuno a questo punto avviare la compilazione e l'esecuzione del programma eseguibile per verificare che la configurazione sia corretta e tutte le dipendenze siano soddisfatte.

A questo scopo possiamo lanciare il comando di esecuzione cliccando su Build -> Run o usare la combinazione di tasti Ctrl + R e osservare i messaggi testuali emessi dal compilatore e dal linker nel pannello inferiore alla voce Compile output, che può essere portato in primo piano usando la combinazione Alt + 4.

Il pannello Issues (Alt + 1) mostra il suddetto output di compilazione in forma sinottica, evidenziando anche graficamente la differenza tra warning ed errori veri e propri.

Elementi di un progetto widget-based

La vista ad albero situata nel pannello sinistro di Qt Creator mostra i vari elementi del progetto correntemente aperto. Per un progetto widget-based appena creato, tra di essi troviamo i seguenti file:

  • il file di configurazione del progetto che generalmente è basato sulla sintassi di qmake ed ha estensione .pro;
  • un listato che include la funzione main(), cioè il punto di inizio per l'esecuzione del programma, generalmente denominato main.cpp;
  • un file header e di implementazione per la finestra principale dell'applicazione;
  • un file .ui per la definizione del layout grafico della finestra principale;

Come impostazione di default la finestra principale dell'applicazione è basata sulla classe QMainWindow. Quest'ultima è una derivata di QWidget che aggiunge alcuni elementi tipici di una finestra quali la barra dei menù e quella di stato, le barre degli strumenti, nonchè la possibilità di ospitare sotto-finestre dockabili.

La creazione della finestra principale è quindi il primo esempio di estensione per ereditarietà delle funzionalità offerte dal modulo widgets. Il nome suggerito per la classe derivata da QMainWindow è per default MainWindow, ma esso può essere modificato già in fase di creazione del progetto o successivamente mediante refactoring sia del codice sorgente che dei relativi file .ui.

L'entry point di un'applicazione widget-based

Il listato seguente è una versione leggermente modificata del listato generato automaticamente da Qt Creator che include la definizione della funzione main() per un'applicazione Qt widget-based.

In esso possiamo osservare i passaggi fondamentali su cui si basa il funzionamento dell'applicazione. Le prime istruzioni sono relative all'inizializzazione di un oggetto di tipo QApplication.

#include "mainwindow.h"
	#include <QApplication>
	#include <QStyleFactory>
	int main(int argc, char *argv[])
	{
		// parametrizzazione dell'applicazione con metodi statici
		QApplication::setStyle(QStyleFactory::create("Fusion"));
		// costruzione dell'oggetto applicazione, che gestisce anche
		// gli argomenti da riga di comando
		QApplication a(argc, argv);
		// inizializzazione della finestra principale
		MainWindow w;
		w.show();
		// punto di inizio dell'event loop del thread GUI (o thread principale)
		return a.exec();
	}

In Qt esiste una gerarachia di classi che modella il concetto di applicazione, declidandolo nelle sue varianti di applicazione senza GUI (QCoreApplication), applicazione con GUI (QGuiApplication) e applicazione con GUI basata su widgets (QApplication).

La classe QApplication estende per ereditarietà le funzionalità di QCoreApplication e QGuiApplication specializzandone il comportamento per il caso di applicazioni che fanno uso di widgets. Essa, pur non essendo propriamente un singleton, è concepita per essere tale, quindi come regola generale deve essere istanziata solo una volta nel contesto di un'applicazione widget-based.

L'istanza di QApplication sovrintende la corretta inizializzazione di tutte le impostazioni che riguardano il rendering delle widgets e la gestione degli argomenti passati da riga di comando. Pertanto, deve essere inizializzata prima di istanziare la finestra principale dell'applicazione o ogni altra widget.

La configurazione dei parametri dell'istanza avviene tramite l'uso di API statiche della classe, invocate prima della costruzione dell'oggetto stesso. In questo caso, ad esempio, l'istanza di QApplication viene configurata per usare lo stile Fusion invece che quello nativo del sistema.

Seguono le istruzioni relative alla creazione di una istanza della finestra principale, che viene mostrata a schermo a seguito dell'invocazione del metodo show().

Infine, il valore di ritorno della funzione main() è quello restituito del metodo exec() dell'istanza di QApplication. L'invocazione del metodo exec() è bloccante fino alla ricezione di un segnale di terminazione del programma, ad esempio la chiusura normale dell'applicazion e costituisce il punto di inizio dell'event loop principale, deputato alla gestione di tutti gli eventi generati dall'interfaccia grafica.

La struttura di una classe widget-based

La definizione delle caratteristiche della finestra principale e la sua implementazione si articola su più file. La vista ad albero del progetto di Qt Creator include le sezioni Headers e Sources dalle quali è possibile accedere rispettivamente al file header (.h) ed a quello di implementazione (.cpp) della classe MainWindow.

Nella sezione Forms inoltre è presente il file di layout (.ui) che descrive l'aspetto della widget in formato XML. Per default, all'apertura di un file .ui, Qt Creator passa alla modalità design per consentire la definizione dell'interaccia in stile RAD. Per visualizzare in sola lettura il contenuto del file in forma testuale è possibile forzare il passaggio alla modalità editing.

L'analisi dei listati .h e .cpp della classe MainWindow generati automaticamente da Qt Creator, consente di evidenziare alcune carattistiche sia del modello dati sia del funzionamento del framework Qt.

Innanzi tutto si osservi la presenza della macro Q_OBJECT che ricorre per via del legame di diretta discendenza che lega la classe QWidget alla classe QObject.

#ifndef MAINWINDOW_H
	#define MAINWINDOW_H
	#include <QMainWindow>
	// forward declaration della classe Ui::MainWindow
	namespace Ui {
	class MainWindow;
	}
	class MainWindow : public QMainWindow
	{
		Q_OBJECT
	public:
		explicit MainWindow(QWidget *parent = nullptr);
		~MainWindow();
	private:
		// le caratteristiche dell'oggeto ui sono determinate da Qt Designer
		Ui::MainWindow *ui;
	};
	#endif // MAINWINDOW_H

Inoltre, la definizione della classe include il membro ui di tipo Ui::MainWindow, da non confondere con il tipo MainWindow. Si noti in questo caso, l'uso del namespace Ui per riutilizzare lo stesso nome (in questo caso "MainWindow") per la dichiarazione di tipi differenti.

Si evince già a questo punto che alcune porzioni del codice, cui la definizione della classe MainWindow fa riferimento, sono da ricercarsi altrove, tra i file autogenerati dai tool moc (Meta Object Compiler) e uic (User Interface Compiler) distribuiti con le librerie del framework.

In particolare, la definizione del il tipo Ui::MainWindow si trova nel file ui_mainwindow.h generato automaticamente da uic a partire dal file mainwindow.ui. Ui::MainWindow è una classe che include un puntatore ad ogni widget presente nel layout della finestra principale e la definizione del metodo setupUi() nel quale avviene l'inizializzazione di tali oggetti secondo la parametrizzazione fatta da Qt Designer.

L'inizializzazione e la distruzione del membro ui è demandata rispettivamente al costruttore ed al distruttore di MainWindow.

#include "mainwindow.h"
	#include "ui_mainwindow.h"
	MainWindow::MainWindow(QWidget *parent) :
		QMainWindow(parent),
		ui(new Ui::MainWindow)
	{
		ui->setupUi(this);
		// ui include riferimenti a tutte le widget che compongono
		// il layout della finestra, ad esempio la barra di stato.
		ui->statusBar->showMessage(tr("Ready"));
	}
	MainWindow::~MainWindow()
	{
		delete ui;
	}

A seguito dell'inizializzazione dei componenti dell'interfaccia è quindi possibile accedere ad ogni elemento mediante i riferimenti contenuti in ui. Ad esempio, in questo caso, la barra di stato viene usata per mostrare un messaggio all'avvio dell'applicazione, come mostrato nella figura seguente.

Una parte dell'implementazione della classe MainWindow è infine contenuta nel file moc_mainwindow.cpp, generato da moc, per la gestione di tutti gli aspetti inerenti la definizione dei metadati dell'istanza e di segnali e slot.

Qt Creator non enumera questi file tra le risorse di progetto poichè essi vengono generati automaticamente prima di invocare il compilatore, sovrascrivendo ogni modifica manuale. Tuttavia entrambi concorrono all'implementazione delle funzionalità supportate dal framework, e pertanto questo schema si ripropone per ogni classe che deriva da QWidget. L'IDE che accompagna il framework prende in carico la gestione di questo aspetto dello sviluppo, esonerando il programmatore dalla necessità di svolgere un lavoro ripetitivo e facilmente soggetto a possibilità di errore.

Considerazioni finali

La soluzione adottata dal framework Qt per la generazione di interfacce grafiche è vincolata all'uso di alcuni strumenti di sviluppo come uic e moc, imprescindibili per la generazione dell'eseguibile finale. Sebbene questa dipendenza comporti inevitabilemente alcune complicazioni rispetto il modello adottato da altri framework, essa è tuttavia funzionale sia alla separazione della business logic della nostra applicazione dalla sua interfaccia, sia alla sua longevità in relazione ai cambiamanti del framework stesso da una versione all'altra.

Di fatto, l'uso di un file XML per la definizione del layout grafico di una finestra o widget implica una commistione tra il paradigma imperativo tipico della programmazione in C++ ed il paradigma dichiarativo, tipicamente associato ad esempio allo sviluppo di interfacce web.

A parte il vantaggio di disporre di uno strumento RAD per la generazione di interfacce grafiche, come alternativa alla tediosa codifica di tutte le istruzioni necessarie alla definizione degli elementi grafici della nostra interfaccia, l'uso del paradigma dichiarativo per la descrizione dell'interfaccia consente di demandare a strumenti come uic e moc l'implementazione effettiva di alcune parti della nostra applicazione. Questo implica il fatto che, l'aggiornamento o la modifica di alcune API del modulo widget che riguardano ad esempio l'inizializzazione di una widget del framework, non comporta per il programmatore la necessità di aggiornare il codice corrispondente. Per integrare versioni aggiornate del modulo Qt Widget, anche in presenza di API modificate rispetto la versione precendente, è infatti sufficiente rigenerare i file prodotti da uic e moc, con grande risparmio di tempo e di altre risorse.

Nelle prossime lezioni esamineremo la modalità di definizione del layout grafico dell'applicazione e popoleremo altre sezioni della classe MainWindow per mostrare alcune delle funzionalità del modulo Qt Widget.

Ti consigliamo anche