venerdì 2 dicembre 2011

Programmare con GTK+ in linguaggio C++: creare la prima applicazione!

Questo tutorial vi guiderà alla creazione di un programma con interfaccia grafica utilizzando il linguaggio C++ e la libreria Gtkmm, ma a differenza di molti altri tutorial sulla rete, utilizzeremo Glade e GtkBuilder per creare l'interfaccia.
Prima di iniziare, assicuratevi di aver installato Anjuta, Glade e la libreria libgtkmm, se non avete provveduto potete installarli tramite Ubuntu Software Center (se sei alle prime armi leggi questo ).
Faremo un programma semplice che illustrerà l'utilizzo di tre semplici elementi dell'interfaccia utente: un'etichetta per visualizzare del testo, un campo di inserimento per inserire una stringa di testo ed un pulsante. Alla pressione del pulsante, il testo inserito nel campo verrà visualizzato nell'etichetta.

La prima cosa da fare e' creare un nuovo progetto con Anjuta
  • Iniziamo con lanciare Anjuta e selezionare NuovoProgetto nel menu File o sulla barra degli strumenti.
  • Quando compare la finestra di selezione del tipo di progetto, selezionate C++ e quindi GTKmm, quindi cliccate su continua.
  • Nella schermata successiva date un nome al progetto, ad esempio tutorial, quindi se volete il vostro nome ed indirizzo email. Il numero di versione non e' importante, andiamo avanti.
  • Nel campo destinazione cliccate sul tasto apri e selezionate la posizione dove mettere il progetto. Vi consiglio di creare una cartella apposita.
  • Le altre opzioni le lasciamo con i valori di default, assicuriamoci soltanto che sia attiva la voce “Utilizzare GtkBuilder per l'interfaccia utente”, clicchiamo su continua e successivamente su applica.
Creazione di un progetto C++ GTKmm



Creare l'interfaccia utente con Glade

  • Adesso abbiamo un progetto, se proviamo ad eseguire il programma, dal menu EseguiEsegui o dalla barra degli strumenti ( l'icona con gli ingranaggi ), si aprirà una finestra intitolata “Hello world!”. Chiudendo la finestra il programma terminerà.
  • Lanciate Glade, il disegnatore di interfacce, e aprite il file che definisce l'interfaccia del vostro programma. Se avete chiamato il progetto tutorial, lo troverete in tutorial/src/tutorial.ui
  • Il file contiene solo una finestra vuota. Selezionando la finestra nell'elenco in alto a destra, potrete vedere le proprietà nel riquadro in basso a destra. Il nome della finestra main_window e' quello di riferimento usato dal vostro codice per ottenere il puntatore alla finestra. Il titolo della finestra e' “Hello World!”, cambiamolo in “Tutorial 1”.
  • Il nostro programma necessita di tre elementi: un'etichetta, un campo inserimento ed un pulsante. Abbiamo quindi bisogno di un contenitore che contenga tre elementi. Nella colonna a sinistra di Glade potete vedere un pannello degli strumenti. Nella sezione Contenitori, selezionate il primo contenitore, quello denominato Casella, e' un widget di tipo Gtk::Box. Adesso cliccate all'interno della finestra del vostro programma. Vi verrà chiesto il numero di elementi, inserite 3 e cliccate su Crea.
  • Ora la nostra finestra può contenere tre elementi. Nel pannello degli strumenti, nella sezione Controllo e visualizzazione, selezionate Inserimento testo. La nostra finestra e' divisa in tre parti, cliccate sulla prima parte in alto, avete aggiunto il campo di inserimento testo. E' un widget di tipo Gtk::Entry.
  • Ora selezionate il widget Etichetta, posta nella sezione Controllo e visualizzazione del pannello degli strumenti. Quindi cliccate nel secondo spazio libero della vostra finestra. Avete così aggiunto l'etichetta, e' un widget di tipo Gtk::Label.
  • Per finire selezionate il widget Pulsante e cliccate nell'ultimo spazio libero della finestra. Il pulsante e' un widget di tipo Gtk::Button.
finestra vuota

aggiunto Gtk::Box di tre elementi

aggiunto Gtk::Entry

aggiunto Gtk::Label

aggiunto Gtk::Button

Adesso la nostra interfaccia e' completa, la sua composizione e' riassumibile con questo schema:

  • Gtk::Window
    • Gtk::Box
      • Gtk::Entry
      • Gtk::Label
      • Gtk::Button

Salvate l'interfaccia cliccando su Salva il progetto corrente nella barra degli strumenti in alto o dal menu File – Salva e tornate ad Anjuta.

Creare la classe di controllo dell'interfaccia Controller

Ora che avete salvato la nuova interfaccia, se provate ad eseguire il programma da Anjuta, vedrete comparire la finestra intitolata “Tutorial 1”, contenente i tre widget che avete aggiunto. Adesso dobbiamo creare una classe che si occuperà di gestire gli elementi dell'interfaccia grafica.

  • Create una nuova classe cliccando su Nuovo – Classe nella barra degli strumenti o dal menu File Nuovo – Classe. Selezionate la sezione Classe C++ generica, chiamate la classe Controller, quindi cliccate su Crea. Si aprira un'altra finestra intitolata “Aggiungi sorgente”, nel riquadro sotto l'etichetta “Selezionare l'obbiettivo per i nuovi file sorgente:”, aprite la cartella src cliccando sul triangolino a sinistra, quindi selezionate tutorial e cliccate su Aggiungi. Ora abbiamo una nuova classe Controller, iniziamo ad implementarla.





  • Nel nostro main.cc potete vedere che viene creato un'istanza della classe Gtk::Builder leggendo il file tutorial.ui della nostra interfaccia. Dobbiamo quindi implementare un costruttore pubblico della classe Controller che riceva come parametro un puntatore a Gtk::Builder. Aggiungiamo quindi:
    inline Controller( Glib::RefPtr<Gtk::Builder> _bldr );
  • Dimenticavo, la nostra classe Controller dovrà lavorare con gli elementi dell'interfaccia, quindi dobbiamo includere il file header di gtkmm.
    Aggiungiamo quindi
    #include <gtkmm.h>
  • Controller necessita di tre variabili per contenere i puntatori degli elementi dell'interfaccia. Aggiungiamo quindi le seguenti variabili come private:
    Gtk::Entry *campoInserimento;
    Gtk::Label *campoEtichetta;
    Gtk::Button *pulsante;
  • Il compito del costruttore e' ottenere i puntatori dei tre elementi dell'interfaccia tramite l'istanza di Gtk::Builder e memorizzarli nelle tre variabili che abbiamo dichiarato come private. Aggiungiamo in Controller.h la definizione del costruttore:

    inline Controller::
    Controller ( Glib::RefPtr<Gtk::Builder> _bldr )
    {

    _bldr->get_widget ("entry1", campoInserimento);

    _bldr->get_widget ("label1", campoEtichetta);

    _bldr->get_widget ("button1", pulsante);
    }
    get_widget(nome, puntatore) e' un metodo di Gtk::Builder che richiama l'elemento con il nome posto nella stringa usata come primo parametro e mette il puntatore dentro alla variabile fornita come secondo parametro. entry1, label1 e button1 sono i nomi dei nostri widget, se tornate in Glade e selezionate gli elementi potrete verificarne i nomi. Ovviamente se modificate i nomi ricordatevi di modificare i nomi anche nel vostro codice sorgente.

Adesso il vostro Controller.h dovrebbe essere come questo:

#ifndef _CONTROLLER_H_
#define _CONTROLLER_H_

#include <gtkmm.h>

class Controller
{
      public:
            inline Controller( Glib::RefPtr<Gtk::Builder> _bldr );

      protected:

      private:
            Gtk::Entry *campoInserimento;
            Gtk::Label *campoEtichetta;
            Gtk::Button *pulsante;

};

inline Controller::
Controller ( Glib::RefPtr<Gtk::Builder> _bldr )
{
      _bldr->get_widget ("entry1", campoInserimento);
      _bldr->get_widget ("label1", campoEtichetta);
      _bldr->get_widget ("button1", pulsante);
}

#endif // _CONTROLLER_H_

Implementare il metodo aggiornaEtichetta

Il metodo aggiornaEtichetta ha il compito di prelevare la stringa inserita nel campo di inserimento e metterla nell'etichetta, vediamo come.

  • Dichiariamo il metodo aggiornaEtichetta come protetto nella nostra classe Controller, aggiungiamo quindi la dichiarazione:
    void aggiornaEtichetta ( void );
    Questo metodo non prende alcun parametro e non rilascia alcun valore alla sua uscita.
  • Adesso implementiamo la definizione di aggiornaEtichetta nel file controller.cc

    void Controller::
    aggiornaEtichetta ( void )
    {
          Glib::ustring stringa = campoInserimento->get_text ();
          campoEtichetta->set_text ( stringa );
    }

    Il funzionamento e' banale, prende la stringa contenuta in campoInserimento con il metodo get_text() e la mette in una variabile di tipo Glib::ustring*, quindi passa la stringa al campoEtichetta con il metodo set_text().

Collegare il pulsante al metodo aggiornaEtichetta

Adesso dobbiamo fare in modo che quando si clicca sul pulsante venga chiamato il metodo aggiornaEtichetta.

  • Andiamo a modificare il costruttore della classe Controller per aggiungere il collegamento.

    pulsante->signal_clicked ().connect (sigc::mem_fun (this, &Controller::aggiornaEtichetta) );

    Questa istruzione collega il segnale signal_clicked() del pulsante al metodo aggiornaEtichetta della nostra classe Controller.
  • La nostra classe Controller e' completa, ora modifichiamo il file main.cc per utilizzarla.
    Prima cosa da fare e' includere il file header controller.h

    #include “controller.h”
  • Quindi inseriamo la creazione di un'istanza di Controller invocando il costruttore che abbiamo implementato.

    Controller *controllo = new Controller ( builder );

    Dobbiamo passare al costruttore il puntatore dell'istanza di Gtk::Builder, quindi va messo dopo la creazione della stessa.
    Prima della fine di main() bisogna deallocare l'istanza di Controller

    delete controllo;

    main.cc sarà più o meno così

    #include <gtkmm.h>
    #include <iostream>
    #include "config.h"
    #include "controller.h"
    #ifdef ENABLE_NLS
    # include <libintl.h>
    #endif
    /* For testing propose use the local (not installed) ui file */
    /* #define UI_FILE PACKAGE_DATA_DIR"/tutorial_1/ui/tutorial_1.ui" */
    #define UI_FILE "src/tutorial_1.ui"
    int
    main (int argc, char *argv[])
    {
          Gtk::Main kit(argc, argv);
          //Load the Glade file and instiate its widgets:
          Glib::RefPtr<Gtk::Builder> builder;
          try
          {
                builder = Gtk::Builder::create_from_file(UI_FILE);
          }
          catch (const Glib::FileError & ex)
          {
                std::cerr << ex.what() << std::endl;
                return 1;
          }
          Gtk::Window* main_win = 0;
          builder->get_widget("main_window", main_win);
          Controller *controllo = new Controller ( builder );
          if (main_win)
          {
                kit.run(*main_win);
          }
          delete controllo;
          return 0;
    }

Compilazione e test del programma Tutorial

Il programma e' completo, potete compilare cliccando sull'icona di compilazione nella barra degli strumenti o sul menu Genera – Compila. Lanciate il programma e provate a scrivere qualcosa nel campo di inserimento, quindi cliccherete sul pulsante, vedrete l'etichetta visualizzare la stringa che avete inserito.

Il programma Tutorial 1 e' completo


Questo piccolo programma e' banale, ma penso che dia un'idea di come utilizzare Gtk::Builder.