Skip to main content

Qt Creator Lez. 3

Posted in

Scopo di questa terza lezione è arricchire l’applicazione creata nella seconda lezione con alcune utili funzionalità. Questo esempio non vuole essere un’applicazione completa e con molte funzionalità, si vuole cioè evitare di sommare troppi concetti per un’unica lezione e si vuol lasciare al lettore la curiosità di scoprire nuove funzioni del Qt application framework.

Passo 1

Per prima cosa partiamo dalla main window della seconda lezione visibile in figura qui sotto:

Aggiungiamo ora (in Qt Creator) una MDIArea alla nostra main window (MdiArea si trova nella toolbar a sinistra, subito dopo la lista files, alla voce Containers), il risultato dovrà essere più o meno così:

Passo 2

Scriviamo ora nel file mainwindow.cpp il codice seguente:

 

Passo 3

Analizziamo ora nel dettaglio ogni metodo...

Il costruttore:

MainWindow::MainWindow(QWidget *parent)

: QMainWindow(parent), ui(new Ui::MainWindow)
{
   ui->setupUi(this);
   connect(ui->actionOpen,SIGNAL(triggered()),this, SLOT(openFile())); 
}
Fin qui nulla di nuovo rispetto la seconda lezione.
setupUI è il metodo incaricato di inizializzare l’intera interfaccia utente creata da Qt Creator.
connect realizza la connessione con la QAction di nome actionOpen del menu (File->Open) che abbiamo
creato da Qt Creator. Nella lezione 2 avevamo fatto una cosa analoga per la actionExit, ovvero il menu
responsabile di chiudere l’aplicazione; ora abbiamo creato un altro menu (File->Open) per l’apertura di un
file. Scopo della connect è “chiamare” un metodo in corrispondenza di un segnale generato dalla QAction;
questo metodo lo chiameremo openFile e sarà responsabile di aprire il nostro file immagine che andremo a
visualizzare.
 
Il distruttore:
 
MainWindow::~MainWindow()
{
    delete ui;
}
Anche qui nulla di nuovo rispetto la lezione 2. Il distruttore si occupa di cancellare tutto ciò che era stato
creato in precedenza.
 
Il metodo int MainWindow::openFile():
 
Per prima cosa analizziamo le seguenti righe di codice:
QList <QByteArray> supportedFilters;
QString filters;
QString defaultFilter;
QImageReader reader;
supportedFilters = reader.supportedImageFormats();
 
Si tratta delle dichiarazioni necessarie per permettere successivamente alla nostra applicazione di
riconoscere quali sono i file immagine supportati (ad es PNG, JPG, BMP, etc...). Tutto si realizza attraverso la
classe QImageReader che restituisce nella lista di ByteArray (cioè QList <QByteArray>) tutte le estensioni
dei files immagine riconosciuti. In altre parole, con la linea di codice
supportedFilters = reader.supportedImageFormats();
Andiamo a riempire la lista “supportedfilters” con tutte quelle estensioni di file che il nostro sistema può
leggere (cioè che le Qt sanno riconoscere grazie ai “decoder” di immagine installati).
Per approfondire questo argomento si può consultare la documentazione sul sito qtsoftware o il Qt
Assistant.
 
A questo punto, consideriamo il codice seguente:
for (int i = 0; i < supportedFilters.size(); ++i)
{
   defaultFilter.append("*.");
   defaultFilter.append(supportedFilters[i].toUpper());
   defaultFilter.append(" ");
   filters.append(supportedFilters[i].toUpper());
   filters.append(" (*.");
   filters.append(supportedFilters[i]);
   filters.append(" );;");
}
 
si tratta di un ciclo for che itera sulla dimensione della lista “supportedfilters”. Questa lista infatti mette a
disposizione un elevato numero di metodi, tutti molto utili, tra cui il metodo size() che ci informa sul
numero di elementi contenuti nella lista.
Obiettivo del ciclo for è quello di creare una stringa (QString) contenente qualcosa del tipo: “*.PNG *.BMP
*.JPG” e così via. Questa strana stringa ci servirà nel resto del codice per filtrare (da qui il nome filter…)
quali files vogliamo andare ad aprire con la openFile.
Nota: le linee di codice di questo ciclo loop non devono essere considerate superficialmente, proviamo a
cambiare qualcosa (ad esempio a rimuovere l’istruzione filters.append(" );;"); e osservate cosa
succede.
 
Dopo il ciclo for concentriamoci ora su:
defaultFilter.append(");;");
filters.append(tr("Any File( * )"));
filters.prepend(defaultFilter);
fileName=QFileDialog::getOpenFileName(this,tr("Open"),currentPath,filters);
 
le prime 3 linee di codice servono per preparare la stringa filters da passare come parametro a QFileDialog
per selezionare solamente i files che ci interessa aprire (e cioè i files immagine supportati, ad esempio JPG,
BMP, PNG etc.)
 
Fermiamoci ora su:
fileName=QFileDialog::getOpenFileName(this,tr("Open"),currentPath,filters);
questa linea di codice è molto importante! Essa infatti ci permette di far comparire la dialog box standard di apertura files illustrato in figura seguente:
 
  
come si può osservare il campo Tipo File mostra l’indicazione Images (*. BMP *.GIF *.ICO…
Questa è appunto la sequenza di filtri che abbiamo identificato grazie alle linee di codice che abbiamo visto
precedentemente.
Vediamo ora i parametri passati alla QFileDialog::getOpenFileName tr("Open")
è il titolo della dialog box. Non si è scelto di scrivere direttamente la stringa (è cioè “Open”) ma si è voluto
passare attraverso il meccanismo della tr() per consentire la traduzione in lingue diverse dell’applicazione.
Può sembrare prematuro parlare subito di localizzazione, ma se ci abituiamo sin da subito a NON scrivere
direttamente le nostre stringhe nel codice ma le mettiamo sempre dentro ad una tr(), ci toveremo poi
pronti ad eseguire Qt Linguist (con lrelease/lupdate) per tradurre la nostra interfaccia utente. Per ora non ci
addentriamo nei dettagli della localizzazione, ma ricordiamoci di scrivere tutte le nostre stringhe dentro ad
una tr(). SEMPRE!
 
currentPath
questo parametro serve ad indicare quale path usare alla getOpenFileName per visualizzare i files.
Per questo esempio currentPath è stato dichiarato ma non usato. Lascio al lettore il compito di
inizializzarlo.
 
filters 
è la nostra lista di filtri per la selezione del tipo di file da aprire.
 
Arriviamo ora all’ultimo blocco di istruzioni:
if (!fileName.isEmpty()) // if fileName is not empty
{
   child = new QLabel(0);
   child->setPixmap(fileName);
   ui->mdiArea->addSubWindow(child);
   child->show();
}
 
quando viene selezionato un file, la getOpenFileName restituisce in fileName una stringa (vuota nel caso di
nessun file selezionato).
L’istruzione: if (!fileName.isEmpty())
serve appunto a verificare se un file è stato selezionato ed in tal caso si procede con il resto del codice,
altrimenti il metodo openFile termina senza caricare alcun file.
isEmpty() è uno dei tanti metodi della classe QString (i metodi sono molti e tutti utilissimi!) e serve per
sapere se la stringa è vuota.
 
Nel caso sia stato selezionato un file immagine verrà eseguito il codice seguente:
child = new QLabel(0);
child->setPixmap(fileName);
ui->mdiArea->addSubWindow(child);
child->show();
e qui dobbiamo soffermarci un po’ per capire.
 
child è una istanza di QLabel, classe molto utile per visualizzare qualsiasi cosa: da una semplice stringa ad
un’ immagine (che è proprio il nostro caso!)
La classe QLabel può visualizzare le immagini Pixmap; infatti il metodo setPixmap() ci consente proprio di
caricare un’immagine il cui “fileName” (cioè il path) è il parametro passato come argomento
 
child->setPixmap(fileName); ).
 
A questo punto dobbiamo indicare alla mdiArea che c’è una nuova subwindow da visualizzare e questro
viene fatto tramite la:
 
ui->mdiArea->addSubWindow(child);
 
e per ultimo chiamiamo il metodo show() della QLabel ( child->show() ) per visualizzare la finestra child ed il
gioco è fatto.
 
Paolo Sereno
 

Creative Commons License
Questa opera è pubblicata sotto una Licenza Creative Commons.