Tutorial Qt software Applicazione di esempio Premessa Questo tutorial è rilasciato sotto Licenza Creative Commons: Attribution-NonCommercial-NoDerivativeWorks (http://creativecommons.org/licenses/by-nc-nd/3.0/deed.it). Questo documento può quindi essere riprodotto senza violare nessuna legge, sia in versione elettronica, sia in versione cartacea, purché sia riprodotto integralmente in tutte le sue parti, compresa la pagina che contiene queste informazioni: Versione originale scaricabile dal sito / Tutti i marchi riportati in questa pubblicazione appartengono ai rispettivi proprietari. Scriviamo la nostra applicazione con le librerie Qt In questo articolo vedremo come usare le classi fondamentali QMainWindow, QMenuBar e QToolBar per realizzare un'applicazione di visualizzazione immagini di tipo MDI (Multiple Document Interface) cioè in grado di aprire contemporaneamente più finestre corrispondenti alle diverse immagini che caricheremo da disco. Un'applicazione Qt di tipo MDI, si realizza tramite la classe QMainWindow. In altre parole, se scriviamo il codice seguente: #include <qapplication.h> #include <qmainwindow.h> main(int argc, char *argv[]) QApplication app(argc, argv) ; QMainWindow *mainwindow = new QMainWindow; app.setmainwidget(app); mainwindow->show(); return app.exec(); Abbiamo già realizzato la finestra principale della nostra applicazione con funzionalità minime. Il meccanismo per realizzare un'applicazione MDI si basa tutto su questa classe, dovremo infatti derivare una nuova classe, partendo da QMainWindow ed aggiungerci le funzioni che ci servono.
Derivare QMainWindow come già detto, per creare la finestra principale di un'applicazione si parte da QMainWindow; esistono fondamentalmente due modi per creare una main window: tramite Qt Designer oppure in modo completamente manuale. In questo articolo adotteremo la seconda soluzione poiché essa ci permette di analizzare più aspetti di dettaglio e, in ultima analisi, di meglio comprendere il funzionamento del Qt toolkit. // Nome : mainwindow.h #ifndef MAIN_WINDOW_H_ #define MAIN_WINDOW_H_ #include "mdichild.h" #include <qmainwindow.h> class QAction; class QPopupMenu; class QCloseEvent; class QWorkspace; class QToolBar; class MainWindow : public QMainWindow Q_OBJECT public: MainWindow (QWidget *parent = 0, const char *name = 0); private slots: void openfile(); void zoomin(); void zoomout(); private: void createactions(); void createmenus(); void createtoolbar(); void loadfile(qstring filename); MdiChild *activechild(); ; #endif QPopupMenu *filemenu; QAction *openact; QAction *zoominact, *zoomoutact; QWorkspace *workspace; QToolBar *filetoolbar, *zoomtoolbar; mainwindow.h è perciò il file di header della classe MainWindow il cui costruttore prende come al solito due parametri: il puntatore al padre e il nome mnemonico. La classe MainWindow espone gli slot pubblici openfile, zoomin e zoomout. Come intuibile dai nomi, il primo verrà peremtterà di aprire un file di immagine e gli ultimi due consentiranno operazioni di zoom sull'immagine stessa. Proseguendo nell'analisi del file, incontriamo i metodi privati necessari a creare le azioni, menu e toolbar. Il concetto di azione in Qt è molto importante, poiché tramite la classe QAction realizziamo
il collegamento tra gli aspetti più grafici dell'applicazione (menu, toolbar) e i metodi che eseguono il compito richiesto (apertura file, zoom). Tra i metodi privati troviamo infine loadfile(), ovvero il metodo di più basso livello che si occupa di eseguire fisicamente la lettura da disco e il metodo di activechild(). Quest'ultimo è particolarmente importante in quanto permette di individuare quale finestra child è correntemente attiva nel workspace dell'applicazione e di richiamarne i metodi opportuni. Per quanto complicato possa sembrare ciò, analizzando il codice sorgente si scoprirà molto semplice ed intuitivo. Completano la classe MainWindow le proprietà che essa stessa usa per memorizzare le informazioni relative ai componenti grafici in essa contenuti, troviamo quindi il puntatore al menu, alle azioni, al workspace (ovvero quella classe che si occuperà di contenere visivamente tutte le immagini che vorremo caricare da disco) e le toolbar. Vediamo ora in dettaglio ogni singolo metodo prima illustrato, ovvero analizziamo il contenuto del file mainwindow.cpp MainWindow::MainWindow(QWidget *parent, const char *name) : QMainWindow(parent,name) createactions(); createmenus(); createtoolbar(); workspace = new QWorkspace(this); setcentralwidget(workspace); setcaption("applicazione di esempio"); Per prima cosa il costruttore di MainWindow richiamerà il costruttore della sua classe base, ovvero QMainWindow, il quale provvederà a creare una finestra vuota entro cui poter inserire tutti gli elementi grafici e comportamentali dell'applicazione. Successivamente, verranno richiamati i metodi interni a MainWindow per creare le azioni, la menubar e le toolbar e di seguito verrà creato dinamicamente mediante l'operatore new un oggetto di classe QWorkspace, incaricato di contenere tutte le finestre figlie (cioè le immagini che caricheremo da disco), workspace diverrà il widget centrale della finestra principale ed occuperà tutto lo spazio a disposizione (quella che in genere viene chiamata la client area) e si incarichera' di posizionare le immagini, gestire il ridimensionamento e creera' all'occorrenza le scrollbar orizzontali e verticali necessarie quanto le immagini visualizzate sono di dimensioni superiori all'area visibile. La figura seguente ci mostra una mainwindow contenente la classica menu bar (menu File), due tool bars immediatamente sotto la menubar (icone di open e di zoom) e un'area centrale di color grigio, corrispondente al widget workspace. All'interno di quest'area grigia verranno visualizzate le finestre contenenti le immagini.
Figura 1 : workspace Creazione di menu e tool bars void MainWindow::createActions() openact = new QAction("&Apri",tr("Ctrl+A"),this); openact->seticonset(qpixmap::frommimesource("./images/open.png")); openact->setstatustip("apri file immagine"); connect(openact,signal(activated()),this,slot(openfile())); zoominact = new QAction("Zoom&In",tr("Ctrl+I"),this); zoominact->seticonset(qpixmap::frommimesource("./images/zoomin.png")); zoominact->setstatustip(tr("zoom In")); connect(zoominact,signal(activated()),this,slot(zoomin())); zoomoutact = new QAction("Zoom&Out",tr("Ctrl+O"),this); zoomoutact->seticonset(qpixmap::frommimesource("./images/zoomout.png")); zoomoutact->setstatustip(tr("zoom Out")); connect(zoomoutact,signal(activated()),this,slot(zoomout())); Come detto prima, le azioni ci consentono di collegare ai componenti grafici dell'interfaccia (menu, icone di una toolbar) i metodi che eseguono effettivamente le azioni richieste. Questo compito è svolto dalla classe Qaction. Il metodo createaction si occupa di creare dinamicamente tre azioni (corrispondenti all'apertura di un file e agli zoom), i cui puntatori sono proprietà della classe
stessa, come visto in precedenza. Analizziamo nel dettaglio cosa avviene per la azione openact. 1 openact = new QAction("&Apri",tr("Ctrl+A"),this); 2 openact->seticonset(qpixmap::frommimesource("./images/open.png")); 3 openact->setstatustip("apri file immagine"); 4 connect(openact,signal(activated()),this,slot(openfile())); Per prima cosa (linea numero 1) viene allocata una QAction tramite la new e salvato il puntatore in openact. I parametri passati al costruttore di Qaction sono nell'ordine, l'etichetta testuale associata all'azione (etichetta che comparira' ad esempio nella menu bar, come vedremo successivamente), il secondo parametro rapresenta lo shortcut associato all'azione (nel caso in esame Ctrl+I) ed infine, il puntatore al padre dell'azione, che come sempre avviene, è l'oggetto chiamante (il cui puntatore è appunto this ). Dopo aver allocato l'azione, provvediamo a dotarla di un'icona tramite il metodo seticonset; poiché questo metodo prende un parametro di tipo QPixmap, dovremo preoccuparci di convertire la nostra immagine bitmap (./images/open.png) in pixmap e per fare ciò ci affideremo ad un metodo messo a disposizione proprio da QPixmap, in altre parole : Qpixmap::fromMimeSource("./images/open.png"). La linea numero 3 ci mostra come possiamo associare una frase da far comparire nella status bar dell'applicazione ogni volta che il mouse scorre sopra l'azione stessa, ovvero lo status tip. Finalmente, la linea numero 4 ci permette di capire come viene realizzato il collegamento tra l'azione stessa e lo slot di MainWindow incaricato di eseguire l'azione stessa. Tramite la ben nota connect, andremo a collegare il segnale di activated(), emesso dall'azione openact, con lo slot openfile messo a disposizione da MainWindow. Analogamente a quanto visto per openact, lo stesso si potrà dire per zoominact e zoomoutact. A questo punto le azioni sono state create, ciò che dobbiamo fare ora è inserirle nella menu bar e nella tool bar dell applicazione. void MainWindow::createMenus() 1 filemenu = new QPopupMenu(this); 2 openact->addto(filemenu); 3 menubar()->insertitem(tr("&file"),filemenu); createmenus è molto semplice, per prima cosa crea dinamicamente un menu di tipo popup, che sarà come sempre figlio di mainwindow (parametro this) e ne salva il puntatore in filemenu. Successivamente mediante il metodo addto dell'azione openact, va ad inserire la voce di menu Apri. Un pizzico di attenzione in più va poi dedicata alla linea numero 3: tramite il metodo menubar(), messo a disposizione di QMainWindow (cioe' la classe base da cui abbiamo derivato la nostra MainWindow), otteniamo il puntatore alla menu bar preventivamente creata (in modo a noi invisibile) dal costruttore stesso di QMainWindow e ne richiamiamo il metodo insertitem. Quest'ultima istruzione permette di inserire il popup menu poco prima creato nella menu bar dell'applicazione. Al termine di createmenus, esistera' una sola voce di menu, con etichetta File, contenente al suo interno un solo elemento, corrispondente ad Apri e collegato al metodo openfile. Ogni volta che selezioneremo con il mouse l'elemento Apri dal menu File, richiameremo (tramite la connect analizzata nel codice di createactions) il metodo descritto più avanti per aprire un file
immagine e visualizzarlo. void MainWindow::createToolBar() 1 filetoolbar = new QToolBar("File",this); 2 openact->addto(filetoolbar); 3 zoomtoolbar = new QToolBar("Zoom",this); 4 zoominact->addto(zoomtoolbar); 5 zoomoutact->addto(zoomtoolbar); createtoolbar crea due toolbars: una per le operazioni di apertura dei files (il cui comportamento è quindi uguale alla menu bar) e una seconda toolbar per le operazioni di zoom. La linea 1 di createtoolbar crea dinamicamente un oggetto di tipo QToolBar di nome File avente come padre l'oggetto chiamante (il solito puntatore this) e ne salva il puntatore in filetoolbar. Alla linea numero 2 ritroviamo il metodo AddTo di openact che, come già visto per la menu bar, ci permette di inserire l'azione stessa nella tool bar che abbiamo prima creato. Le linee 3,4 e 5 creeranno la zoomtoolbar e inseriranno le azioni di zoom In ed Out. Implementare le funzionalità A questo punto del codice sorgente tutti gli aspetti grafici di MainWindow sono stati creati, occorre ora concentrarci sull'implementazione delle funzionalità e cioè sugli slots openfile, zoomin e zoomout. Apertura di un file void MainWindow::openFile() QString filename = QFileDialog::getOpenFileName(".", "Immagini (*.bmp *.jpg *.jpeg *.png *.pbm *.pgm *.ppm *.xbm *.xpm)", this, "Apri", "Selezionare un file"); if (!filename.isempty()) loadfile(filename); OpenFile, impiega il metodo di libreria getopenfilename, fornito dalla classe QFileDialog. In tal modo, verrà aperta una dialog window come quella di figura 2, per consentire la selezione del file
Figura 2 : QFileDialog::getOpenFileName La dialog window di selezione di un file terminerà quando verrà premuto il bottone di ok o di escape e depositerà il file selezionato nella variabile di tipo QString filename. Qstring è uno strumento molto evoluto e completo che le Qt ci mettono a disposizione per trattare le stringhe. Nel nostro caso ad esempio useremo il metodo isempty() per verificare se la stringa è vuota e in caso contrario andremo a richiamare il metodo loadfile con il parametro filename. void MainWindow::loadFile(QString filename) 1 MdiChild *child = new MdiChild(workspace,fileName); 2 child->openfile(filename); 3 child->show(); loadfile ci permette di affrontare l'argomento cardine di tutta l'applicazione: le finestre child. Ogni file di immagine che viene letto da disco, viene visualizzato in una finestra contenuta nell'area di workspace dell'applicazione (l'oggetto workspace è stato creato nel costruttore di MainWindow). Nel nostro esempio tali finestre sono rappresentate dalla classe MdiChild e non sono altro che un custom widget, creato appositamente per visualizzare immagini e permettere su di esse le operazioni di zoom. Il dettaglio implementativo della classe MdiChild verrà trattato tra breve, per ora ci basti sapere che quando il metodo loadfile viene invocato, esso provvederà a creare dinamicamente, tramite l'istruzione di linea 1, un oggetto di tipo MdiChild il cui padre è workspace e il cui nome è il nome di file stesso. Tramite l'istruzione di linea 2 si va invece ad caricare fisicamente l'immagine da disco alla finestra appena creata ed infine, tramite l'istruzione di linea 3 si visualizza su monitor la finestra figlia (e relativa immagine appena caricata da disco). Dopo aver caricato da disco il file di immagine ed averlo visualizzato, l'applicazione ci mette a disposizione due ulteriori comandi tramite tool bar: zoomin e zoomout. In base a quanto si è visto in precedenza, richiamare da tool bar le azioni di zoom corrisponde ad invocare i metodi qui di seguito riportati.
void MainWindow::zoomIn() MdiChild *child = activechild(); if(child!=0) child->zoomin(); void MainWindow::zoomOut() MdiChild *child = activechild(); if(child!=0) child->zoomout(); MdiChild *MainWindow::activeChild() return (MdiChild *)workspace->activewindow(); I metodi di zoom ci permettono di scoprire un ulteriore aspetto delle applicazioni MDI. Supponiamo di aver caricato da disco due files di immagine. La nostra applicazione le sta visualizzando nella sua workspace area ed ora noi vogliamo eseguire lo zoomin di una delle due; da un punto di vista dell'utente ci aspettiamo che eseguendo un click del mouse sulla finestra che ci interessa (e quindi concedendole il focus dell'applicazione) e poi selezionando dalla tool bar l'icona dello zoomin ci aspettiamo che succeda qualcosa sulla finestra. Da un punto di vista di programmazione, le operazioni sopra citate ci pongono nelle seguenti condizioni: la finestra figlia che ha il focus è la finestra correntemente attiva e il click dell'icona di zoomin invoca il metodo di zoomin fornito da MainWindow. Se uniamo queste due cose possiamo comprendere il codice degli slots di zoom, per prima cosa tramite il metodo activechild otteniamo il puntatore della finestra figlia attiva e qualora tale puntatore non sia nullo invochiamo il metodo pubblico messo a disposizione da MdiChild per eseguire lo zoom. In altre parole, tutte le finestre figlie sono oggetti di tipo MdiChild e quindi tutte le operazioni che vogliamo eseguire sulle immagini visualizzate si traducono nell'invocazione di un metodo specifico offerto appunto da MdiChild. Questo è in sintesi il modo adottato da Qt per implementare la funzionalità di MDI. Finestre child Una finestra child non è altro che un custom widget derivato da QWidget su cui si è reimplementato il metodo di paint. Qui di seguito viene riportato il file header di mdichild. // Nome : mdichild.h #ifndef MDI_CHILD_H_ #define MDI_CHILD_H_ #include <qwidget.h> class QString; class QImage; class MdiChild : public QWidget
Q_OBJECT public: MdiChild (QWidget *parent = 0, const char *name = 0); void openfile(qstring filename); void zoomin(), zoomout(); private: void paintevent(qpaintevent *); void zoomimage(int zoomfactor); ; #endif int zoom; QImage *image; MdiChild insieme con il costruttore, offre i metodi per aprire il file di immagine (openfile) e per le operazioni di zoom (zoomin e zoomout). Oltre ai metodi pubblici, viene implementato il metodo zoom che consente di zoomare l'immagine di un fattore intero passato come parametro (zoomfactor). MdiChild memorizza inoltre l'immagine stessa (Qimage *image) e il fattore di zoom corrente (int zoom) come proprietà private e quindi accessibili solo ai metodi di MdiChild stessa. Implementazione di una child window Il costruttore di MdiChild è molto semplice, si limita a richiamare il costruttore della classe da cui deriva (QWidget) ed imposta il fattore di zoom al valore di 100%. MdiChild::MdiChild(QWidget *parent, const char *name) : QWidget(parent,name) zoom=100; Vediamo ora più in dettagli i metodi pubblici forniti. OpenFile void MdiChild::openFile(QString filename) 1 image = new QImage(fileName); 2 QFileInfo fileinfo(filename); 3 setcaption(fileinfo.filename()); 4 setname(filename); Per prima cosa, viene allocata tramite l'istruzione della linea 1 una QImage contenente l'immagine (che verrà automaticamente caricata dal costruttore di Qimage) specificata dal parametro filename. Qualora l'immagine fosse danneggiata, il file illeggibile o incompatibile, verrà creata una immagine vuota. Le istruzioni delle linee 2 e 3 ci permettono di impostare il titolo per la finestra di immagine. Occorre ricordare che filename contiene non solo il nome dell'immagine da caricare, bensì tutto il path. Per evitare di avere un titolo di finestra illeggibile (ad es. /home/...) si è fatto ricorso alla classe QfileInfo per estrarre il nome del file dall'intero path (mediante il metodo filename). Come detto sopra, QFileInfo risulta utile in molti casi, poiché ci consente di ricavare molte
informazioni su di un file, come ad esempio il nome, il path assoluto, la data di creazione gli attributi e molte altre ancora. Tornando al metodo openfile, notiamo alla linea 3 l'uso del metodo setcaption, offerto da QWidget per impostare il titolo del widget stesso (nel nostro caso la finestra figlia) e alla linea 4 l'uso del metodo setname per impostare il nome mnemonico del widget (quest'ultima istruzione è stata inserita più che altro per ricordare l'utilità del nome di ogni oggetto Qt durante le sessioni di debugging...) Zoom Le azioni di zoom richieste da MainWindow si traducono nell'invocazione dei metodi pubblici zoomin e zoomout di MdiChild. Questi metodi consentono di effettuare zoom incrementando o diminuendo le dimensioni della finestra del 20% mantenendo il fattore di zoom tra 5% e 1000%. void MdiChild::zoomOut() if(zoom>5) zoomimage((int)((double)zoom/1.2)); Il codice di zoomout può essere commentato nel modo seguente: zoomout richiama zoomimage con un fattore di zoom pari a zoom/1.2 qualora il fattore di zoom corrente sia maggiore di 5%. void MdiChild::zoomIn() if(zoom<1000) zoomimage((int)((double)zoom*1.2)); Il codice di zoomin può essere commentato nel modo seguente: zoomin richiama zoomimage con un fattore di zoom pari a zoom*1.2 qualora il fattore di zoom corrente sia minore del 1000%. void MdiChild::zoomImage(int zoomfactor) 1 zoom=zoomfactor; 2 setminimumsize(image->size()*zoom/100); 3 setmaximumsize(image->size()*zoom/100); 4 resize(image->width()*zoom/100,image->height()*zoom/100); 5 update(); Per prima cosa viene memorizzato il nuovo valore di zoom (linea 1). Le linee 2 e 3 impostano la size minima e massima della finestra figlia sulla dimensione dell'immagine scalata in base al fattore di zoom. I metodi setminimumsize e setmaximumsize vengono forniti da QWidget e ci consentono appunto di rendere non ridimensionabile la finestra figlia, poiché, di fatto quando le dimensioni minime e massime coincidono con la dimensione corrente non sarà possibile ridimensionare la finestra figlia con il mouse. La linea 4 esegue il ridimensionamento della finestra mediante il metodo di resize (anche questo offerto dalla classe base QWidget). L'ultima linea di codice viene impiegata per far emettere il segnale di paint alla finestra in modo da forzare il kernel Qt a ridisegnare la finestra.
Occorre ricordare infatti quando si scrive un custom widget di forzare il ridisegno del widget stesso dopo ogni modifica del suo aspetto grafico. Il Qt toolkit ci viene in aiuto in quanto la classe QWidget fornisce un metodo pubblico atto allo scopo. Richiamare update() equivale ad emettere un segnale che forza l'invocazione del metodo di paintevent incaricato di eseguire il disegno del widget stesso. void MdiChild::paintEvent(QPaintEvent *) 1 QPainter painter(this); 2 int w=image->width(); 3 int h=image->height(); 4 int width=(int)((double)(w*zoom)/100.0); 5 int height=(int)((double)(h*zoom)/100.0); 6 setminimumsize(image->size()*zoom/100); 7 setmaximumsize(image->size()*zoom/100); 8 resize(width,height); 9 QImage image2=*image; 10 image2=image->scale(width,height,qimage::scalefree); 11 painter.drawimage(0,0,image2); Tutte le operazioni di disegno vengono gestite dal Qt toolkit tramite una classe apposita: QPainter. Partendo da un sistema di coordinate cartesiane XY, QPainter fornisce funzioni ottimizzate per eseguire le operazioni di disegno che un qualsiasi programma di interfaccia grafica utente può richiedere; questa classe può disegnare qualsiasi cosa, da semplici linee a corde ed archi, sino ad eseguire il rendering di immagini. QPainter fornisce alcuni metodi per disegnare caratteri di testo e le relative trasformazioni (ad esempio testo in orizzontale o verticale) e permette infine le trasformazioni del sistema di coordinate (spostamento dell'origine, rotazioni degli assi e così via). Il codice di paintevent usa QPainter per eseguire il rendering dell'immagine, questo è appunto lo scopo della dichiarazione di linea 1. Come si può osservare, viene dichiarata una variabile painter di tipo Qpainter figlia della classe chiamante (il solito puntatore a this). Dopo aver dichiarato painter, siamo pronti ad eseguire le operazioni di disegno necessarie per visualizzare l'immagine, prima di fare ciò dobbiamo però ricordare che la visualizzazione corrente è legata anche al fattore di zoom; ciò vuol dire che dobbiamo scalare le dimensioni dell'immagine vera di un fattore pari a zoom e dopo averla scalata, possiamo procedere al disegno. Le linee 2 e 3, ci permettono di conoscere le dimensioni reali dell'immagine. Tramite le istruzioni delle linee 4 e 5 ricalcoliamo quali devono essere le dimensioni dell'immagine da visualizzare basandosi sul valore di zoom. Le istruzioni delle linee 6, 7 e 8 ci consentono di impostare le dimensioni minima e massima che la finestra contenente l'immagine può assumere. Questa pratica è in realtà un trucco per impedire il ridimensionamento della finestra figlia, in quanto impostando la dimensione massima della finestra, uguale alla dimensione minima ed infine uguale alla dimensione dell'immagine scalata di un fattore zoom, impediamo che l'operazione di ridimensionamento abbia effetto. Ricordandoci che la nostra finestra di visualizzazione di immagine è un Qwidget, abbiamo che SetMinimumSize e setmaximumsize sono due metodi messi a disposizione da Qwidget stesso per impostare i limiti di dimensioni entro cui mantenersi durante le operazioni di ridimensionamento con il mouse. Resize invece è un metodo messo a disposizione per eseguire fisicamente il ridimensionamento. Poichè non vogliamo che le operazioni di zoom influiscano sull'immagine stessa,la dobbiamo mantenere separata la visualizzazione dall'immagine stessa, quindi le operazioni di scale non
dovranno essere eseguite su image, bensi su una sua copia (pena la modifica di image ad ogni zoom). Questo è appunto lo scopo di image2, ovvero essere usata come copia di lavoro su cui eseguire lo scaling in base al fattore di zoom. L'istruzione image2=image->scale(width,height,qimage::scalefree); scala image2 sulla base delle nuove dimensioni calcolate in base a zoom (width ed height). Il parametro Qimage::ScaleFree viene utilizzato in quanto non è necessario chiedere al metodo scale di preservare il ratio (rapporto larghezza/lunghezza dell'immagine), in quanto ciò è garantito dal fatto che si applica un unico fattore di zoom per entrambe i valori (vedere linee 4 e 5). Infine, la linea 11 ci consente di disegnare finalmente l'immagine scalata nella nostra finestra figlia. L'istruzione painter.drawimage(0,0,image2); richiama il metodo drawimage offerto dalla classe QPainter per il disegno di oggetti di tipo Qimage all'interno di un widget. Con i primi due parametri, entrambi a zero, richiediamo a drawimage di disegnare l'immagine partendo dalle coordinate 0,0 del sistema di riferimento cartesiano usato per le operazioni di disegno. A titolo informativo, occorre ricordare che il sistema cartesiano di riferimento usato per tutte le operazioni di disegno prevede come origine (punto a coordinate 0,0) il punto in alto a sinistra. File main.cpp Qui di seguito viene riportato il codice di main.cpp. #include <qapplication.h> #include "mainwindow.h" int main (int argc, char *argv[]) 1 QApplication app(argc,argv); 2 MainWindow *mainwindow = new MainWindow; 3 app.setmainwidget(mainwindow); 4 mainwindow->show(); 5 return app.exec(); Come si può osservare main() è molto semplice e consiste nella creazione di un oggetto QApplication che rappresenta il main loop dell'applicazione stessa (linea 1) e nella creazione di una istanza di MainWindow alla linea 2. La linea 3 permette di associare al main loop dell'applicazione l'aspetto grafico: il metodo setmainwidget, offerto da QApplication prende come parametro mainwindow stessa e ad essa girerà tutti gli eventi provenienti dal sistema (ad es. eventi di mouse, di tastiera). La linea 4 permette di visualizzare a schermo la nostra applicazione e, tramite la linea numero 5 avviamo il loop di esecuzione di MainWindow. Tale loop terminerà qunado verrà premuto il bottone in alto a destra della finestra X-Window (il bottone di terminazione appunto). Qmake file Il file di qmake per la nostra applicazione è davvero banale: ci limitiamo ad indicare che l'eseguibile da produrre sarà una applicazione (TEMPLATE = app) il path da usare per la ricerca dei file di header è quello corrente, oltre naturalmente al path delle librerie Qt (INCLUDEPATH +=.) ed infine elenchiamo i sorgenti che costituiscono la nostra applicazione.
TEMPLATE = app INCLUDEPATH +=. # Input HEADERS += mainwindow.h mdichild.h SOURCES += main.cpp mainwindow.cpp mdichild.cpp Il risultato nel nostro lavoro sarà quindi quello visibile in figura 3 Figura 3: applicazione MDI di visualizzazione immagini Conclusioni Si conclude con la presentazione di questa semplice applicazione la serie di articoli dedicata alla programmazione del Qt toolkit. L'applicazione è stata tenuta volontariamente molto semplice e si presta a molte modifiche ed approfondimenti, l'autore spera di aver suscitato l'interesse nel lettore per un ulteriore approfondimento dell'argomento e si augura di poter trovare un giorno qualche nuovo progetto open source basato sulle Qt o per l'ambiente KDE di qualche lettore. Come ripetuto più volte, la serie di articoli sulle Qt sin qui proposta, è stata una prima timida introduzione, l'argomento Qt è straordinariamente affascinante ed inoltre, è stata rilasciata da pochi giorni la minor release Qt 4.2; come dichiarato da Aaron Seigo mesi or sono, con questa release, a breve potremo aspettarci il rilascio ufficiale della major release di KDE 4 e con essa un nuovo fiorire di applicazioni evolute e dalla grafica sconcertante.