Scuola Politecnica e delle Scienze di Base Corso di Laurea in Ingegneria Informatica Elaborato finale in Programmazione I
Ambienti e librerie grafiche per il C++
Anno Accademico 2014/2015 Candidato: Mario Napoletano matr. N46/1654
Indice
Indice .............................................................................................................................................. III
Introduzione ..................................................................................................................................... 4
Capitolo 1: Librerie e interfacce grafiche ........................................................................................ 6
1.1 Il modello ad eventi con delegati ........................................................................................... 7
1.2 I widgets, elementi costitutivi di un’interfaccia grafica ......................................................... 8
1.3 Librerie grafiche per il C++ ................................................................................................... 9
Capitolo 2: GIMP ToolKit (GTK+) ............................................................................................... 10
2.1 Architettura........................................................................................................................... 11
2.2 Hello World in GTK+ .......................................................................................................... 12
Capitolo 3: Allegro......................................................................................................................... 14
3.1 Hello World in Allegro ........................................................................................................ 15
Capitolo 4: Qt ................................................................................................................................. 16
4.1 Hello World in Qt ................................................................................................................. 17
Capitolo 5: Sviluppo di un esempio ............................................................................................... 19
5.1 Ambienti di sviluppo ............................................................................................................ 19
5.2 Visione concettuale .............................................................................................................. 20
5.3 Allegro ................................................................................................................................. 21
5.4 gtkmm .................................................................................................................................. 22
5.5 Qt .......................................................................................................................................... 23 5.6 Confronto ............................................................................................................................. 25
Conclusioni .................................................................................................................................... 26
Bibliografia .................................................................................................................................... 27
4
Introduzione
Nel presente lavoro di tesi si vanno a trattare, da un’ottica differente rispetto a quella cui
si è abituati nel percorso di studi universitario, le potenzialità del linguaggio di
programmazione C++: si intende porre l’attenzione sullo sviluppo di applicazioni
provviste di interfaccia grafica (GUI - Graphical User Interface), con le quali dunque
l’utente può comodamente e intuitivamente interagire.
Il C++ nasce ufficialmente nel 1983 da un’iniziativa di Bjarne Stourstrup nei laboratori
Bell allo scopo di integrare nel linguaggio di programmazione C la logica del paradigma
object-oriented.
Prendendo a modello il Simula (uno dei primi linguaggi orientati agli oggetti), il C with
classes – poi diventato C++ – introduce costrutti e concetti prima sconosciuti in un
linguaggio di programmazione, quale il C, in prevalenza procedurale, influenzato dal
Pascal e per particolari applicazioni avente corrispondenza 1:1 con codice assembly.
In particolare ricordiamo, per l’appunto, il concetto di classe, una sorta di contenitore di
proprietà ed azioni riconducibili ad una medesima entità, la quale, tipicamente,
corrisponde al modello di un’entità appartenente al dominio applicativo reale in cui il
sistema software è utilizzato; e poi ereditarietà e polimorfismo, che permettono di definire
gerarchie e proprietà comuni a più entità simili fra loro nel proprio contesto d’azione, in
modo da ridurre anche il numero di linee di codice ‘ripetitive’ in progetti che, per
applicazioni complesse, possono anche risultare di dimensioni molto estese, con relative
difficoltà di debugging e fault detection.
Volendo prendere in prestito il motto di Java, « write once, run everywhere » può
5
adattarsi anche a quello che è stato (e che prosegue tuttora, data la continua evoluzione
dei campi d’applicazione, e conseguentemente della complessità delle applicazioni
prodotte) lo sviluppo delle librerie software, vere e proprie ‘banche dati’ sfruttabili, ad
esempio, per l’interazione della propria applicazione con il sistema operativo o con i
dispositivi di I/O (di fatto loro scopo originario); esse rappresentano dei raccoglitori di
strutture dati e funzioni utili per particolari applicazioni (basti pensare alle librerie
OpenCV, per permettere specificamente lo sviluppo della cosiddetta computer vision e
l’interazione uomo-macchina) o anche, tendenza che è andata a incrementarsi
successivamente all’ideazione e standardizzazione del linguaggio C++, strutture dati e
funzioni per così dire general purpose: esempio particolarmente calzante è quello delle
Standard Template Libraries (STL), entrate a far parte a tutti gli effetti dello standard
ANSI/ISO nel 1995, che definiscono classi generiche (in particolare templates) e
particolari algoritmi di uso comune a un ampio spettro di applicazioni, così da permettere
di concentrare gli sforzi sullo sviluppo della logica applicativa.
Accanto alle librerie, possiamo prendere in considerazione la nascita degli ambienti
integrati di sviluppo (IDE – Integrated Development Environment), aventi il fine di
fornire strumenti per una programmazione più comoda, intuitiva e talvolta guidata, oltre
ad incapsulare le complesse e talvolta tediose operazioni di compilazione dei file sorgenti
e collegamento dei diversi file oggetto derivanti.
Conclusa questa panoramica storico-introduttiva, il presente lavoro di tesi si concentrerà
su come utilizzare le nozioni appena descritte al fine di sviluppare un’applicazione
grafica, andando a presentare alcune librerie nate allo scopo di creare interfacce grafiche e
a permettere l’interattività dell’utente con esse e, in più, facendone una sorta di confronto;
a tale scopo, si sono configurati diversi ambienti ciascuno con una diversa libreria, così da
fornire una trattazione quanto più ampia possibile.
Come caso di studio, è stato scelto lo sviluppo di un semplice videogame, il noto ‘Tic Tac
Toe’ (denominato anche ‘Tris’).
6
Capitolo 1: Librerie e interfacce grafiche
Da diverso tempo, l’utilizzo dei calcolatori è divenuto pervasivo nella vita di tutti i giorni
anche di chi non ha una conoscenza estesa del mondo informatico o non ne è coinvolto
dal punto di vista lavorativo o di studio. Per agevolare l’interfacciamento tra dispositivi
elettronici (nello specifico calcolatori) e utenti potenzialmente poco o per nulla esperti,
l’ideazione e realizzazione di interfacce grafiche permette di colmare quel gap che,
invece, l’interfaccia testuale (CLI – Command Line Interface) non può annullare se non
in minima parte, pur restando importante per diverse applicazioni.
Una libreria grafica fornisce una serie di componenti elementari per la costruzione di
interfacce grafiche; in che modo tali componenti vengano rappresentati ai fini
dell’elaborazione da parte delle unità di calcolo è celato al programmatore, che può
dunque vestire i panni del designer concentrandosi più sul realizzare applicazioni user-
friendly e sulla gestione delle interazioni uomo-macchina.
Progettare la composizione visiva e il comportamento di una GUI riveste una parte
importante all’interno dello sviluppo di un software, qualunque sia il target
dell’applicazione, dagli smartphone di ultima generazione ai touchscreens di musei e
stazioni, finanche ai sistemi embedded per applicazioni hard real-time safety-critical;
l’obiettivo di qualsiasi GUI è quello di migliorare l’efficienza e la semplicità nell’utilizzo
di un sistema software dal punto di vista dell’utente finale: l’usabilità rientra infatti a tutti
gli effetti tra i fattori di qualità di un software e la filosofia di progettazione centrata
sull’utente mira a risolvere nel modo migliore le problematiche d’interazione.
7
1.1 Il modello ad eventi con delegati
La presenza di un’interfaccia grafica all’interno di un’applicazione presuppone che lo
sviluppo che il programma segue nel corso della sua esecuzione è del tutto o in parte
subordinato agli input e in generale alle interazioni che l’utente ha con esso. Pertanto,
oltre a definire gli elementi costitutivi della GUI, le librerie grafiche si occupano anche di
fornire le metodologie attraverso le quali poter ‘sentire’ l’azione dell’utilizzatore e
definire i conseguenti comportamenti dell’applicazione.
L’approccio più adatto – e perciò più diffuso – è quello event-driven: questo paradigma
impone all’applicazione di essere sempre in ascolto di possibili eventi e di definire
porzioni di codice preposte alla gestione di tali eventi: i punti di ascolto sono spesso e
volentieri rappresentati dai widgets che compongono l’interfaccia, i quali recepiscono
l’evento e innescano l’esecuzione di quella che rappresenta, di fatto, una sorta di interrupt
service routine ad alto livello dedicata a quella specifica tipologia di evento. Possibili
eventi sono il click o il semplice passaggio del mouse, la pressione di un particolare tasto
su una tastiera, un doppio tocco su dispositivi con touchscreen, etc. Una visione
schematica di tale modello è proposta in Figura 1.
La gestione degli eventi avviene mediante listeners, ovvero delle entità di programma
associate ad una determinata sequenza di istruzioni che implementano la logica
dell’applicazione: una volta verificatosi l’evento, i listeners iscritti vengono notificati, e la
sequenza di istruzioni associata viene eseguita, mettendo in tal modo in piedi il
meccanismo tipico del pattern Observer.
A seconda del linguaggio di programmazione e della libreria grafica utilizzata, un listener
- Figura 1 -
Diagramma E-R descrivente in maniera semplificata il modello concettuale
8
può essere una funzione o un oggetto che esponga nella sua interfaccia i metodi necessari
affinché il collegamento tra il widget, cioè la sorgente dell’evento, e il gestore vero e
proprio (event handler) possa concretamente avvenire; i criteri e le modalità con cui tale
collegamento va messo in piedi sono definiti da ciascuna libreria grafica.
La tripla (sorgente, evento, gestore) rappresenta il modello ad eventi con delegati, dove
la sorgente corrisponde al componente grafico che ha acquisito l’interazione esterna,
l’evento è un oggetto o comunque un’entità descrittiva di tale interazione e il gestore è il
delegato a occuparsi d’implementare la business logic associata all’evento.
A livello architetturale, questo modello corrisponde di fatto al pattern Model-View-
Controller, in cui il Model corrisponde alla logica applicativa incapsulata dalla View,
grazie alla quale l’utente può visualizzare graficamente le parti salienti del Model,
manipolabili mediante il modulo Controller, corrispondente in pratica ai componenti
grafici pronti a raccogliere l’interazione, notificandola ai listeners (o observers, volendo
utilizzare la terminologia del design pattern fondamentale).
1.2 I widgets, elementi costitutivi di un’interfaccia grafica
Elementi fondamentali di un’interfaccia grafica sono i widgets, ossia dei componenti
messi a disposizione da una libreria grafica dalla cui costruzione e messa in relazione può
esser prodotto al meglio lo strato di presentazione del software: essi permettono all’utente
di interagire direttamente con l’applicazione, tramite lettura d’informazioni, selezione tra
opzioni e più in generale attraverso input per modificare e personalizzare l’esperienza
- Figura 2 -
Diagramma di sequenza che offre una visione dinamica del modello,
sfruttando come esempio il click di un bottone
9
d’uso. Ogni widget (termine nato come acronimo di window gadget) facilita una
particolare tipologia di interazione tra l’utente e il calcolatore e condivide con gli altri
componenti della GUI un dato tema, ovvero una veste grafica comune avente lo scopo di
farli aderire ad un medesimo design estetico, offrendo così coesione all’intera
presentazione del prodotto; inoltre, strutturare un’interfaccia grafica mediante widgets
permette da un lato agli sviluppatori di riusare oggetti aventi determinati compiti,
dall’altro agli utenti di sviluppare un’abitudine a determinate caratteristiche estetiche e
dimistichezza con un vocabolario comune alle diverse applicazioni che si troverà ad
utilizzare. Tra i vari widgets che si possono comunemente riscontrare annoveriamo
bottoni, finestre, etichette, caselle di testo, menu e anche immagini ed icone.
1.3 Librerie grafiche per il C++
Allegro Libreria software sviluppata in C/C++ orientata allo sviluppo di videogiochi
CGAL Libreria di algoritmi di geometria computazionale, utilizzata per il rendering
grafico di forme 2D/3D
FLTK Libreria orientata allo sviluppo di interfacce grafiche ‘snelle’
GTK+ Libreria grafica scritta in C orientata allo sviluppo di interfacce grafiche
OpenGL Libreria volta in particolare allo sviluppo di grafica tridimensionale
Qt Framework per lo sviluppo di applicazioni con interfaccia utente
wxWidgets Libreria grafica scritta in C++ orientata allo sviluppo di interfacce grafiche
Si è scelto di approfondire 3 di queste librerie, ciascuna delle quali differente dalle altre:
GTK+ è estremamente diffusa, in grado di donare alle applicazioni tratti grafici distintivi,
oltre ad essere molto utilizzata per le interfacce dei sistemi operativi Linux; Allegro è
pensata per lo sviluppo di videogames ed ha riscosso non poco successo in tale ambito; Qt
si presenta come un robusto framework, completo di IDE e graphic designer, estremamente
sfruttato per lo sviluppo di applicazioni sia in ambito open-source che commerciale.
10
Capitolo 2: GIMP ToolKit (GTK+)
Tra le librerie grafiche che hanno riscosso maggiori consensi per quanto riguarda la
creazione e gestione di interfacce grafiche, GIMP ToolKit (ben più conosciuta come
GTK+) s’impone come una delle più complete ed efficaci.
Come il nome del progetto indica, GTK+ nasce come libreria grafica di ausilio per lo
sviluppo del software di manipolazione di immagini GIMP (GNU Image Manipulation
Program) nei laboratori dell’università americana di Berkeley, dalle menti di Peter Mattis,
Spencer Kimball e Josh McDonald.
Dopo il rilascio di GIMP, lo sviluppo di GTK+ non si è fermato, ed è diventato parte
integrante del progetto GNU, condividendone pienamente la filosofia di dare vita a
software riusabile, ridistribuibile e modificabile in piena libertà: infatti, le librerie GTK+
sono rilasciate con licenza GNU LGPL, i cui termini ne permettono l’utilizzo per la
creazione di software sia liberi che proprietari o commerciali.
Benché nativamente pensato come integrazione alla piattaforma di gestione grafica X
Window System (tuttora standard de facto per i sistemi operativi Unix-like, Linux
incluso), è utilizzabile anche su Microsoft Windows e sul motore grafico di Mac OS X
Quartz, il che rende GTK+ una libreria grafica multipiattaforma, in grado di assicurare
elevata portabilità tra i vari sistemi operativi alle applicazioni realizzate basandosi sui
costrutti da essa definiti.
GTK+ è scritta in linguaggio C, esteso al paradigma object-oriented grazie alla libreria
GLib (e al sistema di emulazione di oggetti in essa incluso, GObject); ciononostante, è
possibile programmare mediante GTK+ anche in altri linguaggi, quali C++, JavaScript e
11
Python, grazie a un meccanismo di binding garantito dallo strato middleware
GObjectIntrospection, sfruttato dalle rispettive librerie d’interfacciamento gtkmm, Gjs (o
Seed) e PyGObject.
Su GTK+ si basano gli ambienti desktop GNOME (ambiente grafico utilizzato da diverse
versioni di Linux Ubuntu) e Xcfe (tipico di xUbuntu), oltre a numerose applicazioni, tra
cui il già citato editor di immagini GIMP, il web-browser Mozilla Firefox, il client di
posta elettronica Mozilla Thunderbird, i software di virtualizzazione della famiglia
VMware, l’editor di testo gedit e lo sniffer Wireshark.
2.1 Architettura
La libreria grafica GTK+ è strutturata in maniera modulare; ogni componente assolve uno
specifico compito ed è attivato all’occorrenza.
GLib è la libreria base, che interagisce direttamente con il sistema operativo su cui è
eseguita l’applicazione, astraendone le caratteristiche mediante tipi di dato wrapper che
assicurano la portabilità del codice su più piattaforme. Essa è responsabile della
definizione di strutture dati e procedure non strettamente legate alla grafica.
Cairo è la libreria utilizzata per la creazione di grafica vettoriale bidimensionale, sulla
quale si poggia di fatto il disegno vero e proprio dei vari elementi grafici
dell’applicazione sul display di riferimento.
GDK si occupa di incapsulare il sistema di gestione delle finestre e dei widgets della
piattaforma ospite, oltreché degli eventi dovuti alle interazioni dell’utente.
Pango è la libreria responsabile della resa testuale dell’applicazione, ivi compresa la
possibilità di internazionalizzazione del testo.
- Figura 3 -
Visione schematica dell’architettura GTK+
12
GIO si occupa di virtualizzare il file-system ospite e di fornire un’interfaccia standard
alle applicazioni GTK+ per le operazioni di I/O, anche su rete.
ATK è la libreria atta a predisporre l’applicazione affinché possa essere efficientemente
utilizzata anche dagli utenti con disabilità.
GTK+, infine, è lo strato più esterno, che si occupa di integrare tutti i componenti e di
comunicare direttamente con l’applicazione, offrendo interfacce per la programmazione
orientata agli oggetti; permette inoltre il caricamento dinamico della GUI, tramite il
GtkBuilder che può ricavarla da descrizioni in linguaggio XML, derivanti spesso e
volentieri da strumenti grafici di strutturazione di interfacce.
2.2 Hello World in GTK+
Di seguito si va a proporre un semplice esempio di utilizzo della libreria GTK+ per la
programmazione C++: a tal fine si fa uso dell’estensione gtkmm e della versione 3 della
libreria. Sono stati prodotti 3 file:
- helloworld.h : il nostro header
- helloworld.cpp : file sorgente contenente la definizione del costruttore e dell’handler
associato al click del mouse sul bottone
- main.cpp : file sorgente contenente la funzione main
/*** helloworld.h ***/
#ifndef HELLOWORLD_H
#define HELLOWORLD_H
#include <gtkmm/button.h>
#include <gtkmm/window.h>
/* la finestra principale eredita pubblicamente dalla classe Window definita nel namespace Gtk */ class HelloWorld : public Gtk::Window
{
public:
HelloWorld();
~HelloWorld(){};
protected:
void on_button_clicked(); // dichiarazione dell’handler da invocare
Gtk::Button button; // widget contenuto nella finestra (un solo bottone)
};
#endif
13
/*** helloworld.cpp ***/
#include "helloworld.h"
#include <iostream>
HelloWorld::HelloWorld() : button("Hello World") // creazione bottone con etichetta "Hello World" {
set_border_width(10);
// collegamento dell’handler all’evento click (eventi = segnali) button.signal_clicked().connect(sigc::mem_fun(*this,
&HelloWorld::on_button_clicked));
add(button); // aggiunta del bottone alla finestra
button.show(); // ora il bottone può essere mostrato
}
void HelloWorld::on_button_clicked()
{
std::cout<<"Hello world!"<<std::endl; }
/*** main.cpp ***/
#include "helloworld.h"
#include <gtkmm/application.h>
int main (int argc, char* argv[])
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv,
"org.gtkmm.example"); // creazione dell’applicazione
HelloWorld hellowindow; // dichiarazione della finestra principale
return app->run(hellowindow); // esecuzione dell’applicazione
}
- Figura 4 -
Screenshot del programma in esecuzione su Ubuntu 15.10
14
Capitolo 3: Allegro
Un gran numero di applicazioni multimediali, ed in particolare videogames, che affollano
la rete sono realizzate usufruendo della libreria grafica Allegro.
Allegro (Allegro low level game routines) è una libreria grafica nata e sviluppata per
fornire supporto allo sviluppo di applicazioni videoludiche e multimediali in generale;
nata per iniziativa di Shawn Hargreaves negli anni ’90, in seguito ha coinvolto
sviluppatori di ogni nazionalità, riunitisi in un’unica community7 che tuttora contribuisce
aggiungendo funzionalità a una libreria open source ancora in crescita e pubblicando i
propri progetti corredati di codice sorgente.
La libreria si occupa di incapsulare la realizzazione di operazioni quali la creazione e
gestione delle finestre, il disegno e caricamento di immagini, l’ascolto e risposta agli
input dell’utente, la riproduzione di effetti sonori, e più in generale tutte quelle
operazioni di ‘basso livello’ (come rivela il nome della libreria) propedeutiche allo
sviluppo di applicazioni afferenti al mondo del multimedia. Il sito ufficiale della libreria6
si premura di specificare che Allegro non è un game-engine: ciò significa che tutto il
lavoro riguardante la logica del gioco, la progettazione grafica, lo schema che
l’interazione uomo-macchina deve seguire è demandato ai programmatori.
Caratteristica da rimarcare di Allegro è l’essere cross-platform, il che permette, per la
realizzazione delle routines di basso livello di cui sopra, di usufruire del medesimo
codice, utilizzabile per diverse piattaforme: Linux, Windows, MacOS X, iPhone,
Android (in via di sviluppo) e persino DOS (piattaforma nativa); Allegro risulta inoltre
estremamente modulare ed estensibile, in maniera tale da aggiungere funzionalità (ad
15
esempio un supporto alla grafica 3D mediante OpenGL o la gestione di diversi fonts) e
non solo, tant’è vero che la libreria è scritta in C / C++ ma è utilizzabile mediante
meccanismi di binding anche con altri linguaggi, come Python e .NET.
3.1 Hello World in Allegro
Per avere una fugace visione pratica della libreria, di seguito è proposto un esempio di
programma che mostra la scritta ‘Hello World!’. Si nota immediatamente la logica molto
legata al paradigma procedurale tipico del C, benché il linguaggio utilizzato sia a tutti gli
effetti il C++.
/*** helloworld.cpp ***/
#include <allegro5/allegro.h>
#include <allegro5/allegro_font.h> #include <allegro5/allegro_ttf.h>
int main(int argc, char* argv[]){
if(!al_init()) // inizializzazione di Allegro return -1;
al_init_font_addon(); // inizializzazione del componente aggiuntivo per il font al_init_ttf_addon(); // inizializzazione del componente aggiuntivo ttf
ALLEGRO_DISPLAY* display = al_create_display(640,480); // finestra principale if(!display) return -1;
ALLEGRO_FONT* font = al_load_ttf_font("Minimal.ttf",72,0); // caricamento del font if(!font)
return -1;
al_clear_to_color(al_map_rgb(0,0,152)); // sfondo blu al_draw_text(font, al_map_rgb(255,255,255), 640/2, 480/3, ALLEGRO_ALIGN_CENTRE, "Hello
World!"); // scrittura del testo
al_flip_display(); // la finestra è mostrata a video… al_rest(10.0); // …per 10 secondi al_destroy_display(display); // pulizia della memoria return 0;
}
- Figura 5 -
Screenshot del programma in esecuzione su Windows 8.1
16
Capitolo 4: Qt
Qt rappresenta uno dei framework maggiormente utilizzati per la realizzazione di
applicazioni, sia con che senza fini di lucro.
Rilasciata per la prima volta nel 1995 sotto l’egida della Trolltech, la libreria Qt è nata
dall’idea partorita da 2 sviluppatori, Haavard Nord ed Eirik Chambe-Eng, che hanno
pensato di realizzare un sistema di visualizzazione object-oriented. Qt è attualmente
sviluppata sia dalla Qt Company, sussidiaria della Digia, che ne detiene il copyright, sia
dalla community open-source Qt Project, ed è rilasciata sia in licenza commerciale che
open-source, a seconda del fine per il quale è sfruttata.
Più che una ‘semplice’ libreria grafica, Qt ingloba un insieme di softwares e tecnologie
aventi la finalità di garantire uno sviluppo di applicazioni quanto più completo ed
efficace possibile: risulta essere, infatti, un vero e proprio framework, all’interno del
quale sono compresi sia le librerie, sia l’IDE attraverso cui poterle utilizzare (Qt
Creator), sia un software di modellazione dell’interfaccia grafica (Qt Designer).
Come riportato dal sito ufficiale8, Qt è creata « da sviluppatori per sviluppatori » per
poter garantire un’esperienza di sviluppo comoda ed efficiente; la programmazione
tramite Qt permette di isolarsi dalla piattaforma di riferimento, essendo la libreria
multipiattaforma, con supporto anche per dispositivi mobili e sistemi embedded.
Sviluppata in C++, Qt mette a disposizione interfacce per l’utilizzo con altri linguaggi di
programmazone, quali Python e JavaScript (QML). Essa inoltre ‘estende’ il linguaggio
C++, mettendo a disposizione costrutti e parole chiave atti a fornire un livello di
astrazione ancora più alto (come ad esempio il meccanismo di signals e slots9 mediante il
17
quale si permette l’implementazione del pattern Observer): questo è reso possibile grazie
all’utilizzo del moc (metaobject compiler), un compilatore ‘intermedio’ che genera
codice aggiuntivo necessario ai fini della compilazione mediante il compilatore C++
tradizionale sottostante.
Grazie alle sue caratteristiche, il framework Qt è forse il più utilizzato per le applicazioni
commerciali e dalle grandi corporations dell’industria multimediale: alcuni esempi sono
Samsung, Walt Disney, Philips, Dreamworks, Electronic Arts, mentre tra le applicazioni
che utilizzano Qt per la propria interfaccia grafica si possono menzionare il riproduttore
multimediale VLC, Google Earth e Spotify per Linux. Anche l’Agenzia Spaziale
Europea ha scelto Qt per i propri softwares di modellazione e simulazione.
4.1 Hello World in Qt
Di seguito si mostra un esempio pratico di utilizzo della libreria: si realizza una semplice
applicazione che mostra un bottone recante la scritta ‘Hello World!’, cliccando il quale
viene mostrato un messaggio a video. Si sono prodotti 3 files: un header file per le
dichiarazioni necessarie (hellowindow.h) e 2 source files (hellowindow.cpp, che
implementa quanto dichiarato nell’header, e main.cpp).
/*** hellowindow.h ***/
#ifndef HELLOWINDOW_H
#define HELLOWINDOW_H
#include <QMainWindow>
namespace Ui {
class HelloWindow; }
class HelloWindow : public QMainWindow
{
Q_OBJECT // macro che verrà ‘scompattata’ dal metaobject compiler public:
HelloWindow(QWidget* parent = 0);
~HelloWindow();
private slots:
void on_pushButton_clicked(); // handler per la pressione del pulsante
private:
Ui::HelloWindow* ui; // user interface
};
#endif
18
/*** hellowindow.cpp ***/
#include "hellowindow.h"
#include "ui_hellowindow.h" // header autogenerato per l’interfaccia grafica #include <QMessageBox>
HelloWindow::HelloWindow(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::HelloWindow)
{
ui->setupUi(this); /* l’interfaccia definita mediante Qt Designer viene automaticamente codificata in C++ */ }
HelloWindow::~HelloWindow()
{
delete ui; }
void HelloWindow::on_pushButton_clicked()
{
// creazione e visualizzazione del messaggio QMessageBox::information(this, “helloWorld”, “Hello World!”);
}
/*** main.cpp ***/
#include "hellowindow.h"
#include <QApplication>
int main(int argc, char* argv[]) {
QApplication a(argc, argv); // creazione dell’applicazione HelloWindow w; // creazione… w.show(); // …e visualizzazione della finestra
return a.exec(); // esecuzione dell’applicazione }
- Figura 6 -
Screenshot del programma in esecuzione su Windows 8.1
19
Capitolo 5: Sviluppo di un esempio
Come anticipato nel capitolo introduttivo, si va ora a porre l’accento sugli aspetti salienti
dello sviluppo del videogioco ‘Tic Tac Toe’, realizzato con ciascuna delle librerie
approfondite, e su un confronto fra queste.
5.1 Ambienti di sviluppo
Sono stati scelti 3 diversi IDE per portare avanti la programmazione. L’utilizzo di un IDE
risulta raccomandabile per incapsulare le operazioni di compilazione e linking, rese
complesse dalla presenza di queste librerie, non nativamente supportate dai compilatori
tradizionali (in particolare, nel caso di studio si è utilizzato il GCC), oltreché per poter
usufruire degli strumenti di ausilio alla programmazione che essi offrono.
Codelite è stato configurato per l’utilizzo di GTK+ (in particolare nella versione C++
gtkmm), operazione non molto complessa, in quanto l’ambiente permette la creazione
guidata di un progetto che fa uso di tale libreria grafica.
Code::Blocks è l’ambiente scelto per Allegro: questo IDE, oltre ad avere dei templates
già pronti, permette di definire le caratteristiche del proprio progetto, creando un wizard
ad hoc per le esigenze del programmatore.
Qt, come detto, si presenta già integrata nell’ambiente Qt Creator, il quale include anche
Qt Designer, utile ai fini della definizione per via grafica del layout e degli elementi che
costituiscono l’interfaccia; analogamente, per il progetto con gtkmm sono stati sfruttati i
file XML di descrizione prodotti dal software di modellazione Glade10
, caricati e
‘interpretati’ dinamicamente dall’applicazione.
20
5.2 Visione concettuale
A livello teorico, il gioco segue due fasi fondamentali: si sceglie il simbolo (X o O) del
giocatore iniziale, dopodiché ci si alterna nel porre i rispettivi simboli all’interno della
griglia di gioco: non appena uno dei giocatori riesce a mettere in fila tre suoi simboli,
guadagna un punto, la griglia viene ‘ripulita’ e si riparte con il perdente a cominciare per
primo, e così via finché uno dei due non raggiunge il punteggio massimo (in caso di parità
vige la regola dell’alternanza).
Pertanto l’applicazione è strutturata in due schermate fondamentali: la prima schermata
permette di selezionare il simbolo del Giocatore 1, il primo ad iniziare; la seconda,
mostrata a video solo a scelta avvenuta, presenta lo schema di gioco, la griglia in cui
verranno posti i simboli, ciascuno dei quali verrà disegnato nella cella in cui è stato
rilevato il click del mouse, nel rispetto del turno di gioco. Una volta disegnato il simbolo,
l’applicazione provvede a verificare se sono stati messi in fila (in diagonale, orizzontale o
verticale) tre simboli uguali: in caso negativo, la mano prosegue; altrimenti, appare un
- Figura 8 -
La schermata iniziale, ovvero un’immagine estremamente
semplice realizzata con il programma Paint
- Figura 7 -
Diagramma UML in cui si mostrano i macro-componenti che schematizzano il
comportamento dell’applicazione, indipendentemente dalla libreria
21
messaggio in cui si avvisa dell’avvenuto ‘tris’ e si mostra l’aggiornamento del punteggio.
Raggiunto il punteggio massimo, l’applicazione si congratula con il giocatore vincitore
per poi terminare.
5.3 Allegro
Allegro permette di tenere sotto controllo tutta la fase di inizializzazione delle
funzionalità offerte: dal nucleo della libreria al componente adibito alla gestione delle
immagini – punto forte della libreria – fino ai driver per la comunicazione con le
periferiche. Fondamentale per poter registrare le interazioni con l’utente è la creazione di
una ‘coda di eventi’ (ALLEGRO_EVENT_QUEUE) da popolare con le possibili sorgenti di
eventi che possono essere ad esempio la periferica mouse oppure il display: un
ALLEGRO_EVENT è una struttura dati che contiene tutte le informazioni riguardanti
l’evento registrato dalla piattaforma, codificando in un campo type la natura
dell’interazione, rispetto alla quale si possono valutare altri campi significativi.
Andando nello specifico, l’applicazione si mette in attesa di un ALLEGRO_EVENT di tipo
ALLEGRO_EVENT_MOUSE_BUTTON_DOWN, giunto il quale si può accedere al campo
mouse della struttura-evento e valutarne la posizione pixel-by-pixel: a seconda delle
coordinate x e y corrispondenti al click, il simbolo del Giocatore 1 sarà O oppure X.
Sullo stesso principio si basa poi la dinamica del gioco vero e proprio: viene caricata
l’immagine (ALLEGRO_BITMAP) della griglia e nella cella in cui giunge il click viene
mostrata l’immagine del simbolo corretto. Ogni ALLEGRO_BITMAP viene mostrata a
video solo all’invocazione della funzione al_flip_display(), grazie alla quale tutte le
elaborazioni riguardanti gli aspetti grafici che stanno avvenendo ‘alle spalle’ di quanto è
in quel momento mostrato a video terminano e il risultato può essere visualizzato.
Dall’utilizzo della libreria Allegro si nota subito la logica estremamente procedurale che
essa tende a far mantenere al programmatore; naturalmente nulla vieterebbe di
‘incapsulare’ le diverse funzioni all’interno di un approccio object-oriented, la cui
corretta gestione cadrebbe in toto nelle responsabilità del programmatore. D’altronde il
fine che la libreria si pone, ovvero fornire ‘procedure di basso livello’, non metodologie
22
d’alto livello o classi di cui usufruire, è abbastanza chiaro sin dall’acronimo ricorsivo
della libreria (Allegro low level game routines).
5.4 gtkmm
La programmazione tramite gtkmm permette di utilizzare nativamente tutti quei
meccanismi coi quali si è imposto il C++: ereditarietà, polimorfismo, namespaces, etc.
La prima schermata è stata progettata in Glade sotto forma di una Gtk::Image, inclusa
all’interno di un Gtk::EventBox per poter registrare il click del mouse, che invece
l’immagine da sola non avrebbe potuto ricevere. A livello di codice, per potersi legare
all’interfaccia volendo aggiungere comportamenti e proprietà aggiuntive ai widgets che la
compongono è necessario ottenere un riferimento al file XML (formato .glade) da salvare
all’interno di un Glib::RefPtr<Gtk::Builder> che viene poi sfruttato per legarsi agli
oggetti dell’interfaccia a runtime, tramite gli id assegnatigli in fase di progettazione. La
libreria GLib appena vista è estremamente utile per le classi e i metodi che permette di
utilizzare, come il RefPtr<>, uno smart pointer auto-distruttivo, o la classe ustring, che
permette un utilizzo efficiente delle stringhe in standard UTF. Nello specifico del nostro
‘Tic Tac Toe’, si è derivata la classe Gtk::EventBox in una classe EventBoxSimb allo
scopo di ridefinire l’handler associato al click, scrivendo all’interno di esso le istruzioni
necessarie per il salvataggio della scelta dei simboli.
La seconda schermata che viene visualizzata presenta un layout ‘a griglia’, dunque
predisponendo già lo scheletro dello schema di gioco; ciascuna cella della griglia 3x3
presenta una Gtk::DrawingArea, un particolare widget in cui è possibile effettuare
disegni di forme geometriche più o meno complesse a tempo di esecuzione: ciò è
possibile grazie a Cairo, una libreria orientata alla grafica vettoriale inclusa nella ‘macro-
libreria’ GTK+ (e dunque in gtkmm) della quale si è usufruito per il disegno dei simboli.
Lo schema che si è implementato in poche parole è il seguente: all’avvio della seconda
schermata, indipendentemente da turni o clicks, l’applicazione disegna la griglia di gioco;
cliccata una cella vuota, si attiva quella specifica ‘area di disegno’, viene resa vera una
speciale condizione logica e viene inviato il segnale di draw (queue_draw()), il cui
23
handler stavolta sarà autorizzato a disegnare il simbolo corrispondente al turno corrente.
Quanto era realizzato in Allegro con un paradigma procedurale, in gtkmm è stato
facilmente ‘tramutato’ in object orientation: a testimonianza di questo, mentre in Allegro
tutte le condizioni e le variabili necessarie per il proseguimento del gioco sono gestite dal
main, il progetto in gtkmm è provvisto di una classe GamePlayController, che si
occupa di gestire tutto il necessario, dalla matrice su cui le funzioni interne
all’applicazione eseguono le elaborazioni alle variabili di gestione dei turni, fino al
metodo di fine gioco; si è scelto di implementare il controller secondo il pattern
Singleton, per far sì che ne esista una e una sola istanza con più punti d’invocazione
all’interno del codice. Inoltre gtkmm incapsula diverse operazioni, quali il continuo ciclo
di attesa di eventi e relative inizializzazioni, tutte incluse nella creazione di una
Gtk::Window (magari prelevandola dal file di design) e di una Gtk::Application, di cui
invocare il metodo run(), passandogli la finestra da visualizzare.
5.5 Qt
La scrittura dell’applicazione mediante Qt si è rivelata rapida e intuitiva: a renderla tale
ha contribuito l’integrazione totale tra libreria e ambiente di sviluppo, che offre una facile
creazione di un progetto con annessa interfaccia grafica, la quale può essere manipolata
graficamente mediante Qt Designer, anch’esso incorporato nell’ambiente.
Gran parte della logica applicativa è stata riportata pari pari dall’applicazione scritta
secondo gtkmm - essendo entrambe incentrate sull’utilizzo di un paradigma ad oggetti -
salvo naturalmente effettuare i robusti accorgimenti necessari per adattarsi alla diversa
libreria. Anche in Qt, si è sfruttata l’ereditarietà per aggiungere comportamenti e
proprietà ai widgets definiti nel designer, col quale il legame risulta più automatico agli
occhi del programmatore: l’interfaccia, codificata in XML (formato .ui), viene tradotta in
C++, facendo diventare le strutture XML classi e variabili membro e producendo i files
d’intestazione e oggetto necessari; un puntatore alla classe-interfaccia compilata
automaticamente è memorizzato all’interno della corrispondente classe in cui poter
esplicitare i comportamenti dinamici che le si vuole assegnare, quali le operazioni da
24
svolgere in caso di click e di ridisegno della griglia e dei simboli. Nell’applicazione, la
classe SimbArea (ovvero la cella del layout a griglia) istanzia un oggetto QPainter,
adibito alla realizzazione di grafica vettoriale, il quale provvede a disegnare lo schema di
gioco e, se la condizione logica ad hoc è stata resa vera dal click, anche il simbolo del
giocatore che ha il turno in tale momento.
Nella descrizione fatta nel Capitolo 4, si è osservato che Qt prevede un compilatore
‘intermedio’, il moc; esso viene sfruttato per ‘spacchettare’ parole-chiave, introdotte
nell’ambiente per aumentare la semantica e la comprensione del codice, non riconosciute
dal compilatore GCC; tra queste nell’applicazione si è fatto uso della ‘dichiarazione’
Q_DECL_OVERRIDE, con la quale si specifica che il metodo cui si riferisce è soggetto a
override, di Q_OBJECT, già mostrata nell’esempio al paragrafo 4.1, e della parola-chiave
emit, avente l’unico scopo di precedere l’invocazione di un metodo che farà scaturire uno
o più segnali, e dunque modifiche alla resa grafica dell’applicazione: in particolare, emit
è stata utilizzata insieme ad update() per permettere il disegno del simbolo a seguito del
click da parte dell’utente.
Analogamente a gtkmm, Qt offre classi rivelatesi utili per la scrittura dell’applicazione,
quali QApplication (simile a Gtk::Application), QString (simile a Glib::ustring) e il
container QList<> (simile ai contenitori STL).
- Figura 9 -
Un confronto tra le diverse rese grafiche di una medesima situazione di gioco.
Da sinistra a destra: Qt su Windows 8.1, Allegro su Windows 8.1 e gtkmm su Ubuntu 15.10
25
5.6 Confronto
Ci si appresta a proporre una tabella riepilogativo-comparativa, affinché possano esser
messi in luce differenze, peculiarità e punti di contatto delle librerie grafiche con le quali
si è avuto modo di cimentarsi.
- Tabella riepilogativa -
Caratteristiche Allegro gtkmm Qt Portabilità del codice
Documentazione
Semplicità di configurazione
Definizione grafica dell'interfaccia
Ausilio alla programmazione
Facilità di utilizzo
Resa grafica
Una volta concluso il periodo di training necessario per una corretta comprensione delle
funzionalità offerte, coadiuvato dalle esaustive documentazioni reperibili nei rispettivi siti
ufficiali, ciascuna libreria si presenta relativamente semplice da utilizzare, oltreché
portabile su diverse piattaforme, come si è descritto nei capitoli dedicati.
Tuttavia, Allegro necessita un minore sforzo di comprensione iniziale, non avendo una
grande complessità, e perlopiù lasciando libertà di implementazione agli sviluppatori: in
virtù di questa prerogativa, risulta spiegata la pochezza di strumenti di ausilio alla
programmazione, sui quali invece si concentrano gtkmm e in modo particolare Qt,
mettendo a disposizione strutture dati utili per l’interazione con la piattaforma grafica.
Per quanto detto nei capitoli precedenti, Qt è un ambiente di sviluppo con la libreria
completamente integrata, il che azzera di fatto le operazioni di configurazione, e con la
possibilità di definire graficamente l’interfaccia dell’applicazione, attuabile anche con
gtkmm, libreria mediante la quale è sembrato possibile produrre una grafica più
accattivante e piacevole agli occhi dell’utente finale.
26
Conclusioni
Con l’elaborato appena presentato si è cercato di mostrare l’ampia potenzialità e
diffusione che il C++ continua a preservare - nonostante lo sviluppo e diffusione di
linguaggi di programmazione più ‘di alto livello’ e intuitivi (si pensi a Java o Python) -
anche per applicazioni moderne e persino ludiche come quella che ci si è impegnati a
realizzare da zero.
Considerata l’ampia gamma di librerie grafiche per C++ esistenti, l’utilizzo dell’una
piuttosto che dell’altra è estremamente vincolato al giudizio di chi andrà a progettare e/o
sviluppare l’applicazione e al suo scopo d’uso: se si desidera un’applicazione con
un’interfaccia grafica il meno invasiva possibile, si può scegliere ad esempio FLTK (non
approfondita in quest’elaborato); se si è alla ricerca di una libreria completa di strumenti
per la produzione di una grafica complessa, utile sia per progetti semplici/didattici che per
applicazioni di una certa entità, GTK+ rappresenta una scelta consona, così come Qt, che
porta con sé l’idea di un intero framework al servizio delle esigenze di sviluppo; Allegro
risulta invece ideale per chi intende creare in particolar modo videogames, conservando
estrema libertà di integrazione con altri componenti o per chi è più legato a un approccio
procedurale piuttosto che object-oriented e desidera una libreria che si occupi soltanto
della gestione di finestre, immagini e interazioni, senza ulteriori strumenti e appoggi.
27
Bibliografia
[1] The C++ Resources Network, http://www.cplusplus.com/info/history/, 14/12/15
[2] The Linux Information Project, http://www.linfo.org/widget.html, 14/12/15
[3] The GTK+ Project, http://www.gtk.org/, 17/12/15
[4] GTK+ Overview, https://developer.gnome.org/gtk3/stable/gtk.html, 18/12/15
[5] gtkmm – C++ Interfaces for GTK+ and GNOME, http://www.gtkmm.org/, 04/01/16
[6] Allegro – Introduction, http://liballeg.org/readme.html, 22/12/15
[7] Community ufficiale di Allegro, https://www.allegro.cc/about, 22/12/15
[8] Qt – Home, http://www.qt.io/, 23/12/15
[9] Signals & Slots, http://doc.qt.io/qt-5/signalsandslots.html, 23/12/15
[10] Glade – A User Interface Designer, https://glade.gnome.org/, 04/01/16
[11] Allegro 5.0 reference manual, https://www.allegro.cc/manual/5/, 05/01/16
[12] Programming with gtkmm 3, https://developer.gnome.org/gtkmm-tutorial/stable/,
05/01/16
[13] gtkmm Reference Manual, https://developer.gnome.org/gtkmm/stable/, 05/01/16
[14] Qt Documentation, http://doc.qt.io/qt-4.8/index.html, 05/01/16