Traduzione a cura di Fabrizio Angius [qtsolutions -A-T- gmx.net]
English TOC.

5. Un'applicazione Qt di base

In questo capitolo inizieremo ad usare Qt per creare un'applicazione un po' piu' ricca. Costruiremo una semplice finestra con una lista in cui l'utente puo' inserire degli elementi. Sara' anche possibile rimuovere elementi dalla lista.

La figura 5-1 mostra l'applicazione completa. Useremo il Designer di Qt per disegnare la finestra e per produrre il codice.

La nostra semplice applicazione

Figura 5-1 La nostra semplice applicazione.

Il primo passo consiste nell'aprire una console e creare una cartella per il progetto. Io ho deciso di chiamarla ex05, ma potete usare qualsiasi nome. Usate cd per spostarvi nella cartella e avviate il Designer digitando designer & (oppure designer-qt3 & in alcune distribuzioni). E' possibile avviare il Designer dai menu forniti con le distribuzioni moderne, ma useremo altri tool dalla riga di commando, per cui vi consiglio di eseguirlo in questo modo. Se tutto e' andato per il verso giusto vi dovreste trovare con la finestra mostrata nella figura 5-2.

Qt Designer

Figura 5-2 Il Designer di Qt.

Iniziamo creando un nuovo progetto C++. Selezionate semplicemente File - New, quindi "C++ Project" e premete il pulsante "continue". Nella finestra successiva (figura 5-3), inserite un nome per il progetto (usate il pulsante "..." per selezionare un file). Io ho deciso di chiamarlo simple-dialog.pro. per ora non e' necessario cambiare altro, ma date pure un'occhiata a tutte le opzioni disponibili prima di fare click su OK.

Le impostazioni per il progetto

Figura 5-3 Le impostazioni per il progetto.

Ora abbiamo un progetto, per cui non ci resta altro che inserirci dentro qualcosa. Selezionate nuovamente File - New, ma questa volta aggiungete una finestra di tipo "dialog" al progetto. Vi ritroverete con un dialog vuoto chiamato Form1. Inizieremo rinominandolo nell'editor delle proprieta', generalmente visibile nella parte destra della finestra principale del Designer. Se non lo trovate, assicuratevi che sia visibile controllando nel menu Windows - Views. La voce "property editor/signal handlers" dovrebbe essere selezionata. (Il prefisso dlg ci ricorda che abbiamo a che fare con un dialogo. E' una tipica convenzione Microsoft, ma ritengo che semplifichi le cose quando si tratta di riutilizzare il codice.)

NOTA! Se volete cambiare il nome di widget, dialoghi o finestre, fatelo prima di scrivere il codice che li riguarda, altrimenti confonderete il Designer.

La tabella 5-1 riassume i cambiamenti fatti alle proprieta' del dialog:

Widget Proprieta' Nuovo valore
dlgMain Name dlgMain
dlgMain Caption Simple Dialog Example

Tabella 5-1

Ora possiamo iniziare ad aggiungere widget al dialog. Aggiungere un group box con un list box, un line edit e due pulsanti. Aggiungete un'altro pulsante sotto al group box. I widget si possono scegliere dalla barra degli strumenti e i loro nomi sono visibili se spostate il puntatore del mouse sopra di essi per qualche istante.

La figura 5-4 mostra dei possibili nomi e un possibile posizionamento dei widget all'interno del dialog.

Nomi assegnati ai widget

Figura 5-4 Nomi assegnati ai widget.

Il pulsante sotto al group box e' stato chiamato pbOk. Gli altri due pulsanti pbAdd e pbRemove. Il list box e' stato chiamato lbItems, il line edit leItem. La tabella 5-2 riassume i cambiamenti fatti alle proprieta'.

Widget Proprieta' Nuovo valore
pbAdd Name pbAdd
pbAdd Text Add
pbAdd Default True
pbRemove Name pbRemove
pbRemove Text Remove
pbOk Name pbOk
pbOk Text Ok
lbItems Name lbItems
leItem Name leItem
GroupBox1 Title (vuoto)

Tabella 5-2

Per provare il dialog, selezionate uno stile a piacere dal menu Preview (provate i vari stili e confrontateli). La figura 5-5 mostra il mio risultato con lo stile Windows, ma il vostro potrebbe anche essere molto diverso. L'importante e' che abbiate messo gli stessi widget nel dialog.

La prima anteprima

Figura 5-5 La prima anteprima.

Credo che sarete d'accordo con me se dico che e' decisamente brutto. Prima di iniziare a sistemare i widget per migliorarne l'aspetto, dobbiamo discutere un argomento specifico di Qt. Qt e' stato progettato per funzionare su molti sistemi diversi, dai palmari ai grandi server Unix. Supporta anche l'internazionalizzazione per qualsiasi lingua possiate immaginare. Per poter eseguire un'applicazione Qt con messaggi di testo [in altre parole, pensate a un messaggio che tradotto in un altra lingua occupa il doppio dello spazio - n.d.t.] e risoluzioni dello schermo variabili, sono stati introdotti i layout. Invece di specificare precisamente dove deve stare un widget, diciamo solo in che relazione stanno tra di loro. Capirete presto cosa significa tutto cio'.

Prima di applicare un layout, dobbiamo aggiungere degli spacer per riempire gli spazi vuoti del dialog. Gli spacer vengono usati come dei widget, ma non sono visibili quando eseguite la vostra applicazione. Vanno selezionati dalla barra degli strumenti e inseriti nel dialog come qualsiasi altro widget. La figura 5-6 mostra i due spacer usati in questo esempio.

Dove posizionare gli spacer

Figura 5-6 Dove posizionare gli spacer.

Per selezionare piu' widget contemporaneamente, selezionate il primo, quindi mantenete premuto il tasto shift (quello per le maiuscole insomma) mentre selezionate gli altri. Ora selezionate lo spacer a sinistra del pulsante Ok e il pulsante stesso. Ora fate click su "layout horizzontally". La figura 5-7 mostra i pulsanti per i diversi tipi di layout nella barra degli strumenti del Designer (notate che diventano blu quando sono attivi).

I vari tipi di layout

Figura 5-7 I vari tipi di layout.

Ora selezionate il line edit, i due pulsanti nel group box insieme allo spacer e assegnate loro un layout verticale.

Ora selezionate tutto il group box e assegnategli un layout orizzontale (che verra' applicato a tutti i widget contenuto nel group box stesso).

Per concludere, selezionate il dialog [ossia un'area vuota del dialog - n.d.T] e assegnategli un layout verticale. Se sbagliate qualcosa assegnando i layout o se volete fare un po' di esperimenti, basta selezionare il layout e quindi fare click su "break layout" per distruggere quel layout.

L'anteprima dovrebbe mostrarvi qualcosa di simile al dialog mostrato nella figura 5-8. Cambiate la dimensione della finestra per osservare la flessibilita' dei layout. Ora immaginate un po' se tutto cio' fosse possibile anche in quelle applicazioni win32 con i wigdet tutti ammassati!

Il dialog con i layout

Figura 5-8 Il dialog con i layout.

Ora abbiamo completato l'aspetto visivo della finestra. Ci restano solo due cose che e' possibile fare in questo modo prima di proseguire e di scrivere del codice.

La prima cosa da fare e' sistemare l'ordine con cui i widget vengono selezionati quando premiamo il tab sulla tastiera. Selezionate semplicemente il pulsante "tab order" (rappresenta tre linee blu con i numeri 1, 2 e tre sulla sinistra), quindi fate click sui widget nell'ordine in cui volete vengano selezionati premendo tab. Per terminare l'operazione fate click sulla freccia nella barra degli strumenti (il tooltip per quel pulsante dice "Pointer").

Ora, date un'occhiata all'object explorer che generalmente si trova sopra il property editor. Selezionate la pagina ("tab") "members" (chiamata "source" nelle versioni piu' vecchie di Qt) e aggiungete due slot pubblici (click destro sulla voce "public" nella sezione "slots"). La figura 5-9 mostra gli slot che dobbiamo aggiungere. Ricordatevi le parentesi quando dichiarate gli slot.

Gli slot del dialog

Figura 5-9 Gli slot del dialog.

Ora e' arrivato il momento di aggiungere un po' di codice. Chiudete il dialog premendo il pulsante Ok e iniziate faccendo click su uno degli slot che avete appena creato. Apparira' una finestra per inserire del codice, come potete vedere dall'esempio 5-1.

/****************************************************************************
** ui.h extension file, included from the uic-generated form implementation.
**
** If you wish to add, delete or rename slots use Qt Designer which will
** update this file, preserving your code. Create an init() slot in place of
** a constructor, and a destroy() slot in place of a destructor.
*****************************************************************************/

void dlgMain::addItem()
{

}

void dlgMain::removeItem()
{

}

Esempio 5-1

Prima di cambiare il codice, aggiungeremo un ultimo slot. Questa volta con uno con accesso protected chiamato init(). Lo slot verra' aggiunto automaticamente anche alla finestra con il codice. Questo e' uno dei due slot speciali aggiunti al Designer per evitare il vecchio (Qt versione 2.x) approccio in cui era necessario sottoclassare qualsiasi dialog per poter aggiungere dei costruttori o distruttori. Gli slot protected init() e destroy() ci permettono di ovviare [anche se in un modo un po' contorto - n.d.T] a questo problema. L'approccio e' piu' pragmatico di quello usato in precedenza, e rimuove uno degli inconvenienti di un'interfaccia troppo 'pulita'.

Nello slot addItem(), inseriremo le operazioni da eseguire quando un utente preme il pulsante 'add'. Si tratta di controllare se il line edit contiene del testo e, in caso positivo, di aggiungerlo alla lista. Quindi bisognera' svuotare il line edit e dargli il focus in modo che l'utente possa inserire subito dell'altro testo.

Lo slot removeItem() controlla semplicemente se c'e' qualche elemento della lista selezionato e, in caso positivo, lo rimuove dalla lista stessa.

Lo slot init() ci assicura infine che la list box sia vuota e che il line edit abbia il focus dall'inizio.

Mentre scrivete il codice, noterete che la funzione di completamento automatico del Designer elenca solamente proprieta' e slot, senza mostrare i metodi.

Il codice finale viene mostrato nell'esempio 5-2.

/****************************************************************************
** ui.h extension file, included from the uic-generated form implementation.
**
** If you wish to add, delete or rename slots use Qt Designer which will
** update this file, preserving your code. Create an init() slot in place of
** a constructor, and a destroy() slot in place of a destructor.
*****************************************************************************/

void dlgMain::addItem()
{
  if( leItem->text().length() > 0 )
  {
    lbItems->insertItem( leItem->text() );
    leItem->clear();
  }

  leItem->setFocus();
}

void dlgMain::removeItem()
{
  if( lbItems->currentItem() > -1 )
    lbItems->removeItem( lbItems->currentItem() );
}

void dlgMain::init()
{
  lbItems->clear();
  leItem->setFocus();
}

Esempio 5-2

Per poter compilare l'esempio, dobbiamo aggiungere un metodo main() al progetto. E' buona norma separare il codice in moduli diversi, mantenendo il codice per il dialog in file separati. Aggiungeremo quindi un'altro file C++ (usate File - New come prima, ma selezionate un file C++).

Inserite il codice dell'esempio 5-3 nel nuovo file e salvatelo come main.cpp. Leggete i commenti per capirne il funzionamento.

// Header per la classe QApplication
#include <qapplication.h>

// Header per il nostro dialog
#include "dlgmain.h"

// Ricordatevi di usare ( int, char** ) dato che serve a QApplication
int main( int argc, char **argv )
{
  // E' sempre necessario avere un oggetto QApplication
  QApplication a( argc, argv );

  dlgMain *m = new dlgMain();   // Creiamo il nostro dialog
  a.setMainWidget( m );         // E' il nostro widget principale
  m->show();                    // Mostralo...

  return a.exec();              // Ed eseguilo!
}

Esempio 5-3

Ora siamo pronti per compilare il progetto, ma prima dobbiamo creare un Makefile. Ricordatevi di salvare tutto nel Designer (usate File - Save All), quindi passate ad una console e spostatevi nella cartella del progetto. Ora eseguite qmake sul file .pro del progetto creato dal designer. Per esempio digitate qmake simple-dialog.pro, quindi eseguite make. Se non ci sono errori nel codice, il risultato sara' un eseguibile con lo stesso nome del progetto, p.es. simple-dialog, nel mio caso.

Se eseguite il file vedrete che l'aspetto e' corretto, ma che niente funziona. Questo perche' non abbiamo connesso nessun segnale agli slot. Per farlo tornate al Designer e riaprite il progetto nel caso lo aveste chiuso precedentemente.

Selezionate lo strumento "connect signals/slots" (tra il pulsante con il puntatore e quello per il tab order). Dal momento che sia il dialog (dlgMain) che i widget che contiene hanno gia' i segnali che ci servono, non ci resta che scegliere quelli giusti e collegarli agli slot appropriati, il tutto per via grafica. E' sufficiente fare click su un widget di partenza e trascinare il mouse fino al widget di destinazione. Nella finestra' che apparira' selezionate il segnale "clicked" dei pulsanti e lo slot appropriato. Il segnale del pulsante pbAdd andrebbe connesso con lo slot addItem, pbRemove con removeItem e pbOk con close. per evitare di dover selezionare ogni volta il tool per le connessioni, potete selezionarlo con un doppio click la prima volta.

Per vedere se le connessioni sono corrette, fate click destro sul dialog e selezionate la voce "connections". Vi apparira' una finestra simile a quella della figura 5-10.

Connettere segnali e slot

Figura 5-10 Connettere segnali e slot.

Ora, tornate alla console, eseguite make e provate a lanciare l'eseguibile prodotto. Se tutto e' andato bene, dovrebbe funzionare!

Quando premete invio sul line edit, verra' attivato uno dei pulsanti. Questo comportamento e' stato discusso in questo messaggio nella mailing list qt-interest. Controllate in questa mailing list se avete problemi e magari iscrivetevi anche. E' davvero interessante.

Prima di concludere questo capitolo, voglio fare qualche osservazione sull'architettura di quest'applicazione. Non abbiamo un message loop o un posto in cui le cose vengono gestite. Invece creiamo un'istanza di un dialog, colleghiamo degli eventi a degli slot e inseriamo tutte le funzionalita' negli slot. Questa e' programmazione guidata dagli eventi!

Riassunto

Il codice dell'esempio puo' essere scaricato qui.

Questo capitolo discute un approccio di base al Designer. Questo e' l'approccio che seguiremo nella maggior parte dei casi nel resto del capitolo.

Esercizi

  1. Perche' la seconda volta non abbiamo eseguito anche qmake prima di eseguire make?
  2. Aggiungete un pulsante per ordinare la lista e un check box per scegliere un tra ordinamento crescente e decrescente. L'utente dovra' fare solo click sul pulsante per ordinare la lista, cioe' sara' necessario aggiungere solo un'altro slot.
  3. Aggiungete un contatore nella classe del dialog per contare il numero di elementi aggiunti (ignorando gli elementi rimossi) e sostituite lbItems con una list view. Usate due colonne: testo e numero. Ora riscrivete le funzioni addItem e removeItem affinche' usino la list view mostrando anche l'ordine con cui gli elementi vengono inseriti o rimossi.
  4. Fate in modo che si possano modificare gli elementi in lbItems mostrando l'elemento corrente in liItem e applicando i cambiamenti anche alla list box. Il pulsante add dovra' quindi aggiungere un elemento vuoto da modificare successivamente.

This is a part of digitalfanatics.org and is valid XHTML.