La gestione dei menu in GTK+

La gestione dei menu in GTK+ è affidata al tipo `GtkMenuShell´ che è un contenitore. Quest'ultimo non viene utilizzato direttamente da GTK+ per costruire i menu, ma identifica un tipo astratto per `GtkMenu´ e `GtkMenuBar´.

`GtkMenuBar´ può contenere widget `GtkMenuItem´ che costituiscono le etichette dei menu, siano esse principali che secondarie.

Le funzioni chiave di GtkMenuBar sono `gtk_menu_bar_new()´ e `gtk_menu_bar_append()´. La prima restituisce un tipo `GtkWidget´ che punta alla barra di menu. A questa barra vanno aggiunti tanti GtkMenuItem quante sono le etichette del menu principale (tipo: File, Modifica, ...). La seconda aggiunge un nuovo `GtkMenuItem´ nel menu precedentemente creato. In modo analogo esistono funzioni come `gtk_menu_bar_insert()´ e `get_menu_bar_prepend()´: esse sono utili per avere barre di menu «dinamiche» che cambiano secondo il contesto operativo.

Le voci secondarie (tipo: Apri, Salva, Esci...) sono anch'esse tipi `GtkMenuItem´ e sono contenuti da `GtkMenu´ che identifica un menu a scorrimento. Al solito le funzioni sono simili a quelle che creano le barre: `gtk_menu_new()´, `gtk_menu_append()´... Questo tipo contiene le anche le funzioni per creare i menu di popup (per intenderci quelli che si aprono con il tasto destro del mouse).

Il widget restituito da `gtk_menu_bar()´ andrebbe contenuto in un tipo `GtkHandleBox´: il suo utilizzo serve per rendere la barra dei menu «fluttuante» e quindi sensibile agli spostamenti attraverso il movimento del mouse.

Contrariamente agli articoli precedenti, non ci sarà un listato con un semplice esempio funzionante ma, solo una porzione del codice sorgente (vedi Listato 1). Il puntatore `vbox´ contiene un tipo `GtkVBox´, ossia un altro contenitore (nell´articolo precdente furono introdotti i contenitori a tabelle).

Ogni etichetta di menu può essere collegata ad una funzione di ritorno (callback). Quest´ultima si attiva ad un evento di tipo `activate´ e i parametri formali sono rispettivamente il puntatore al tipo `GtkMenuItem´ che ha generato l´evento e, ovviamente, un puntatore ad un dato utente. L´elemento `separator´ è una etichetta vuota; è utile per dividere il menu a scorrimento in due o più parti con una linea.


/* Listato 1 */

...

handlebox = gtk_handle_box_new ();

gtk_widget_show (handlebox);

gtk_box_pack_start (GTK_BOX (vbox), handlebox, FALSE, TRUE, 0);


/* la barra del menu principale */

menubar = gtk_menu_bar_new ();

gtk_widget_show (menubar);

gtk_container_add (GTK_CONTAINER (handlebox), menubar);


/* le etichette della barra del menu principale */

file = gtk_menu_item_new_with_label ("File");

gtk_widget_show (file);

gtk_container_add (GTK_CONTAINER (menubar), file);


modifica = gtk_menu_item_new_with_label ("Modifica");

gtk_widget_show (modifica);

gtk_container_add (GTK_CONTAINER (menubar), modifica);


/* i menu a scorrimento */

file_menu = gtk_menu_new ();

gtk_menu_item_set_submenu (GTK_MENU_ITEM (file), file_menu);

apri = gtk_menu_item_new_with_label ("Apri");

gtk_widget_show (apri);

gtk_container_add (GTK_CONTAINER (file_menu), apri);


salva = gtk_menu_item_new_with_label ("Salva");

gtk_widget_show (salva);

gtk_container_add (GTK_CONTAINER (file_menu), salva);


separator = gtk_menu_item_new ();

gtk_widget_show (separator);

gtk_container_add (GTK_CONTAINER (file_menu), separator);

gtk_widget_set_sensitive (separator, FALSE);


esci = gtk_menu_item_new_with_label ("Esci");

gtk_widget_show (esci);

gtk_container_add (GTK_CONTAINER (file_menu), esci);

...

Alcune nozioni su GDK

La componente GDK comunica con il servente X. Questa libreria è indispensabile per la manipolazione della grafica a basso livello.

La libreria continene tipi e funzioni per manipolare punti, linee, mappe di colori, caratteri, tracciare linee, gestire aree grafiche. GDK prevede uno strato per la gestione dei formati bitmap, tuttavia non è molto avanzato; per questo scopo è preferibile utilizzare la libreria `gdk-pixbuf´.

Le fondazioni del disegno sono costituite dai contesti grafici; essi sono un tipo `GdkGC´. La funzione che restituisce il puntatore relativo è `gdk_gc_new()´. In ogni contesto grafico è possibile definire il colore di primo piano o di sfondo, il tipo di motivo da applicare su una linea, definire una regione e così via. Ogni operazione di tracciatura dovrà essere eseguita su un contesto dato.

I widget, in generale, sono soggetti ad eventi di `expose´ e di `configure´; questi succedono quando una parte visibile di questi deve essere per qualche motivo aggiornata, oppure ridimensionata.

Il tipo che gestisce una finesta di disegno è `GtkDrawingArea´. La funzione `gtk_drawing_area_new()´ restituisce un puntatore al tipo.

Una volta ottenuto possiamo collegarlo agli eventi `expose´ ed `event´ e gestire l´area grafica.


/* Listato 2 */

gboolean drawing_area_configure_event

(GtkWidget* widget, GdkEventConfigure *event, gpointer user_data)

...

GdkPixmap* pixmap;

/*

* Crea la nuova pixmap

*/

if (pixmap) {

gdk_pixmap_unref(pixmap);

}

...

pixmap = gdk_pixmap_new(widget->window,

widget->allocation.width,

widget->allocation.height, -1);


La variabile `pixmap´ è un puntatore a un tipo `GdkPixmap´. Questa è l´area di lavoro dove è possibile utilizzare gli strumenti di disegno. La variabile `widget´ è il puntatore al tipo `GtkDrawingArea´. La dimensione dell´area di disegno può non essere stabilita a priori; in questo caso si utilizzano le dimensioni del widget stesso: queste sono ricavate dal tipo `GtkWidget´. Queste variano se il widget viene ridimensionato. Per questo il puntatore al tipo `GdkPixmap´ restituito da `gdk_pixmap_new()´ deve essere cancellato e riassegnato ad ogni evento (si veda il listato 2). Questo comporta, in caso di disegni o grafici, di mantenere una area di memoria con copia dei punti in un riferimento generico: si pensi ad un grafico in coordinate x, y che dovrà essere scalato oppurtanamente. La gestione dinamica della memoria può essere affidata alla libreria `GLib´ con l´impiego degli array tipo `GArray´ a dimensione variabile.


/* Listato 3 */

...

GdkColor color_fg = { 0, 65535, 0, 0 };

GdkColor color_white;


GdkColormap *colormap;

GdkGC* context = NULL;


/* alloca il colore */

colormap = gdk_colormap_get_system ();

gdk_colormap_alloc_color (colormap, &color_fg, TRUE, TRUE);

gdk_color_white (colormap, &color_white);


/* crea un nuovo contesto grafico */

if (context == NULL) {

context = gdk_gc_new (widget->window);

gdk_gc_set_background (context, &color_white);

}


gdk_draw_rectangle (pixmap, widget->style->white_gc, TRUE, 10, 10,

50, 50);

...


In listato 3 viene creato un nuovo contesto, il colore scelto per lo sfondo è il bianco. Questo avviene con la funzione `gdk_gc_set_background()´. Il colore bianco viene prelevato dalla mappa di colori predefinita. Per memorizzare i parametri di un colore è necessario utilizzare un tipo `GdkColor´. In modo analogo viene richiesto un nuovo colore con `gdk_colormap_alloc_color()´. Si noti che i colori sono memorizzati con componenti a 16 bit. Infine con la funzione `gdk_draw_rectangle()´ si traccia un rettangolo di coordinate (10, 10, 50, 50). Il primo parametro formale della funzione è il puntatore ad un tipo `GdkPixmap´; il secondo parametro formale è il puntatore ad un contesto. In questo caso si sfrutta il contesto `white_gc´ predefinito dello stile dove il colore di primo piano è il nero.

La gestione degli eventi del mouse

Gli eventi del mouse sono anch'essi gestiti dalla libreria GDK. L'utilizzo tipico è la possibilità di distinguere gli eventi legati ai singoli pulsanti: come il tasto sinistro, centrale o destro che è stato premuto, quante volte («singolo click», «doppio click») e così via...

Con il tipo 'GtkEventButton' si possono filtrare gli eventi; in questo caso l'evento per un «singolo click» è 'GDK_BUTTON_PRESS' per il «doppio click» è 'GDK_2BUTTON_PRESS'. La variabile 'button' del tipo memorizza il numero del pulsante premuto. In listato 4 viene proposta una funzione di ritorno di un 'widget' che distingue la pressione del tasto destro (generalmente legata ad un menu fluttuante) e un generico «doppio click».


/* Listato 4 */

void

on_button_press_event (GtkWidget* widget, GdkEventButton* event, gpointer user_data)

{

g_return_val_if_fail (widget, TRUE);

g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);


if ((event->type & GDK_BUTTON_PRESS) == GDK_BUTTON_PRESS) {

if (event->button == 3) {

/* gestione dell'evento */

menu_pop_up = create_menu_pop_up ();

if (GTK_IS_MENU (menu_pop_up)) {

gtk_menu_popup (GTK_MENU (menu_pop_up), NULL,

NULL, NULL, NULL, event->button, event->time);

}

}

}


if((event->type & GDK_2BUTTON_PRESS) == GDK_2BUTTON_PRESS) {

/* gestione del doppio click */

}

}


La funzione 'create_menu_pop_up()' non appartiene alla libreria GTK+ ed è fitizzia quindi, dovrà essere progettata. Il suo scopo è inteso nel restituire un puntatore contente un menu che viene visualizzato con la funzione 'gtk_menu_popup()'.

Le GTK+ 2.0

Questi articoli hanno introdotto la programmazione con le GTK 1.2. Gli sviluppatori di questa libreria hanno di recente rilasciato la versione 2.0. Essa comprende molte novità per gli sviluppatori, come l'introduzione della liberia `pango´ per una gestione migliorata del testo e la possibilità di gestire in modo efficiente alfabeti diversi. La liberia 'atk' è uno strumento che aiuta a sviluppare interfacce utenti fruibili anche da portatori di handicap o da utenti disagiati.

Riferimenti

Strumenti e documentazione per la libreria GTK+ si possono trovare all´indirizzo Internet http://www.gtk.org; in esso trovate la documentazione, aggiornamenti sullo stato di sviluppo delle librerie, vari link relativi ai progetti nati con le GTK+. Le informazioni sono aggiornate all´ultima versione: la 2.0; tuttavia rimangono attivi i riferimenti fino alla versione 1.2.

Per chi è interessato allo sviluppo di applicazioni Gnome il sito di riferimento è http://www.gnomedesktop.org oppure http://developer.gnome.org. Havoc Pennington ha scritto un libro, tradotto in italiano da Christopher R. Gabriel e distribuito dalla Apogeo dal titolo: «GTK+/Gnome Sviluppo di applicazioni». Nonostante non sia aggiornato, getta le fondazioni per un facile approccio alla programmazione GTK+/GDK e Gnome.

Conclusioni

Gli articoli su GTK+/GDK sono terminati con questo articolo. Non è stato possibile dimostrare tutte le capacità di GTK+ in quando non potrebbe che essere argomento di un corso completo che durebbe, in una rivista, molti mesi se non anni! Gli argomenti trattati mi auguro siano stati utili per poter scrivere applicazioni sapendo dove attingere velocemente alle nozioni corrette.