Le finestre di dialogo sono molto noiose se implementate unicamente con GTK+: ogni volta che dovete mostrare un messaggio all'utente, dovete create una finestra, i pulsanti, le stringhe, inserire i pulsanti e le stringhe dentro la finestra, impostare le callback, ricordarvi di catturare "delete_event" e così via. È molto fastidioso. Gnome risolve questo problema, fornendo un widget per le finestre di dialogo facile da usare e facilmente riutilizzabile, e varie sotto-classi di questo che implementano i vari tipi di finestra di dialogo. Gnome inoltre ha facili funzioni per i dialoghi modali.
Dato che le finestre di dialogo in puro GTK+ sono ogni volta scritte da zero, esistono molti modi e stili di scriverle. Il programmatore deve decidere dove posizionare la finestre sullo schermo, le sue dimensioni, se inserire o meno un separatore sopra i pulsanti, il tipo di contenitore per i pulsanti, e così via. Il fine del widget GnomeDialog è che il programmatore stesso non deve preoccuparsi di queste cose. Se sono variabili, allora lasciamo che sia l'utente a decidere questi particolari. Dal punto di vista dello sviluppatore le finestre di dialogo "funzionano e basta".
Create il widget utilizzando gnome_dialog_new(). Passate a questa funzione il titolo della finestra di dialogo (visualizzato dal gestore di finestre) e il nome di ciascun pulsante che desiderate creare.
Inserite in GNOME_DIALOG(dialog)->vbox il contenuto della vostra finestra.
Pensate a cosa dovrà servire questa finestra. Potete collegare il segnale "close" oppure "clicked" secondo le vostre necessità. La finestra potrà nascondersi oppure distruggersi quando viene chiusa. Potete inolte fare in modo che venga chiusa automaticamente quando cliccata, oppure gestire questo evento manualmente. Esistono molti modi in cui l'utente può dialogare con questo tipo di finestra, è quindi importante assicurarsi che la vostra impostazione funzioni correttamente qualunque cosa venga eseguita da parte dell'utente.
Per creare una finestra di dialogo chiamate la funzione gnome_dialog_new(), come mostrato in
Figura 1
. La lista degli argomenti è una lista, terminata da NULL, dei pulsanti da inserire nella finestra. Ad esempio, potete utilizzare:
GtkWidget* dialog;
dialog = gnome_dialog_new(_("Miiii la mia finestra preferita"),
_("OK"),
_("Annulla"),
NULL);
Questa chiamata crea una finestra dal titolo "Miiii la mia finestra preferita" con un pulsante OK e uno Annulla. Le stringhe sono marcate per la traduzione con _(). Il pulsante OK verrà inserito a sinistra dentro la finestra.
La API di GnomeDialog enumera i pulsanti che vengono aggiunti iniziando da 0. Utilizzate questi numeri per far riferimento, in un momento successivo, ai pulsanti, dato che non avete un puntatore ai widget che vengono creati automaticamente. In questo caso, il pulsante OK è il numero 0, mentre il pulsante Annulla è il numero 1. (Da notare che questa è un pratica standard all'interno di Gnome, dove OK o Sì vengono inseriti per primi, seguiti da Annulla o No. Di fatto libgnomeui/gnome-uidefs.h contiene le macro GNOME_YES, GNOME_OK, GNOME_NO, e GNOME_CANCEL che rappresentano la numerazione dei pulsanti di una finestra di dialogo con due di questi al suo interno.
L'esempio mostrato, che elenca i pulsanti con etichetta "OK" e "Annulla", non è molto corretto dal punto di vista della produttività. Gnome fornisce un set di pulsanti "stock" per l'utilizzo comune. Questo assicura che tutti utilizzino l'etichetta "OK"invece di "Ok" oppure "OK!". In questo modo si permette ai traduttori di tradurre queste stringhe una sola volta, e la possibilità di renderli più accattivanti con piccole icone inserite all'interno. Se disponibili, dovreste sempre utilizzare i pulsanti "stock".
Per utilizzarli in gnome_dialog_new(), sostituite le macro dei pulsanti stock al posto dei semplici nomi:
dialog = gnome_dialog_new(_("Miiii la mia finestra preferita"),
GNOME_STOCK_BUTTON_OK,
GNOME_STOCK_BUTTON_CANCEL,
NULL);
Gnome fornisce, nel suo set "stock", svariati pulsanti, voci per i menu, e immagini. È una buona idea di controllare quali siano disponibili in modo da non dover reinventare la ruota. La lista completa è disponibile nel file libgnomeui/gnome-stock.h.
Dopo la creazione della finestra, dovete probabilmente inserire qualcosa al suo interno. Se siete interessati ad una semplice etichetta, allora dovreste utilizzare GnomeMessageBox, oppure alcuni funzioni di libreria (come ad esempio gnome_ok_dialog()) invece di costruire manualmente l'interna finestra. Altrimenti, riempire la finestra di dialogo è molto semplice:
GtkWidget* button;
/* ... creare il pulsante da mostrare successivamente ... */
button = gtk_button_new_with_label(_("Premi qui"));
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox)),
button,
TRUE,
TRUE,
0);
Ovviamente siete liberi di impacchettare il contenuto di dialog->vbox con le opzioni che preferite, questo codice è semplicemente un esempio.
Figura 2
mostra una finestra di dialog dal foglio di calcolo Gnumeric, con le etichette per i suoi componenti.
Figura 2. Un GnomeDialog del foglio di calcolo di Gnumeric
Ecco adesso la parte difficile. Dovete gestire manualmente tutto ciò che l'utente può fare con la finestra. Ecco una piccola lista di possibilità:
Chiudere la finestra premendo il tasto Escape.
Chiudere la finestra premendo sul tasto apposito fornito al gestore di finestre.
Premere uno dei pulsanti presenti.
Interagire con il contenuto della finestra.
Se il dialogo non è modale, interagire con il resto dell'applicazione.
GnomeDialog emette due segnali in aggiunta a quelli ereditati dalla sua classe superiore. Se l'utente preme uno dei pulsanti della finestra, un segnale di tipo "clicked" viene emesso. (Questo non è il signale "clicked" del GtkButton. È un segnale differente, emesso dal GnomeDialog). Il gestore del segnale "clicked" di un GnomeDialog deve avere tre argomenti: la finestra che ha emesso il segnale, il numero del pulsante premuto e i dati per la callback.
GnomeDialog implementa inoltre un segnale "close". Questo viene emesso quando viene chiamata la funzione gnome_dialog_close(). Tutti i gestori interni per gli eventi (ad esempio il tasto Escape) chiamano questa funzione per chiudere la finestra. I gestori standard per il segnale "close" di GnomeDialog hanno due possibili funzioni superiori: questi possono chiamare sia gtk_widget_hide() che gtk_widget_destroy() con argomento la finestra stessa. La prima è possibile chiamarla attraverso gnome_dialog_close_hides(), come mostrato in
Figura 3
.
Per default, il segnale "close" distrugge la finestra. Questa è infatti la modalità più utilizzata. Ad ogni modo, se una finestra di dialogo impiega molto tempo per crearsi, sarà più comodo nasconderla e mostrarla per l'utilizzo, senza mai distruggerla e senza mai doverla ricreare nuovamente. Potrete inoltre voler nascondere la finestra all'utente, estrarre il contenuto di qualunque widget al suo interno, e poi distruggerla utilizzando gtk_widget_destroy(). Questa decisione ricade su come è strutturato il vostro codice. In generale, comunque, distruggere la finestra quando viene emesso il segnale "clicked" risulta molto più semplice, riducendo anche il rischio di possibili errori nel codice. Potete inoltre monitorare il segnale "clicked" per interrogare lo stato dei widget dentro la finesta.
Se associate un gestore al segnale "close", questo dovrà restituire un valore booleano. Se restituisce TRUE, la finestra non verrà distrutta o nascosta. Utilizzate questa caratteristica per evitare che l'utente chiuda prematuramente la finestra, ad esempio se non sono stati compilati i campi di un modulo.
Il segnale "close" è stato progettato per
gestire, attraverso un singolo handler, più azioni che l'utente può
compiere: deve essere emesso quando l'utente preme il tasto Escape oppure
quando l'apposito pulsante di chiusura del gestore di finestre viene
premuto. È inoltre consigliato emettere questo segnale ogni qual volta un pulsante della finesta viene premuto. È possibile richiedere a GnomeDialog di emetterlo utilizzando la funzione gnome_dialog_set_close() (
Figura 3
). Se l'argomento setting è TRUE, il widget emetterà il segnale "close" assieme al segnale "clicked", quindi ogni volta che un pulsante viene premuto. Per default questo argomento è FALSE per ogni GnomeDialog, ma per la maggior parte delle finestre di dialogo speciali questo è impostato a TRUE.
Da notare che il segnale "close" viene emesso quando la finestra riceve un "delete_event". Questo significa che dovrete scrivere un unico gestore per controllare la chiusura della finesta. Non c'è assolutamente bisogno di gestire il "delete_event" separatamente.
La differenza fra una buona finestra di dialogo e una magnifica sono i dettagli. GnomeDialog fornisce alcune istruzioni per semplificare i ritocchi finali. L'elenco di queste è disponibile a
Figura 4
.
Le finestre di dialogo hanno un padre logico, solitamente la finestra principale dell'applicazione. Potete descrivere attraverso la libreria la relazione padre-figlio di queste finestre. Questo permette a Gnome di vantarsi di determinate configurazioni a cui l'utente può accedere, e gestire anche le relazioni con il gestore di finestre. La maggior parte di questi riducono a icone le finestre di dialogo se la finestra padre è essa stessa ridotta, e posizionano i figli all'interno della finestra padre.
È importante utilizzare la funzione gnome_dialog_set_parent() unicamente per le finestre transient. Una finestre di dialogo transient sono quelle che vengono mostrate per un breve lasso di tempo (GnomeDialog è stata progettata per essere una finestra transient). Alcuni "dialoghi" sono semplici piccole finestre, come, ad esempio, la barra degli strumenti di Gimp. Questi dialoghi persistenti devono poter essere ridotti a icona senza ridurre anche la finestra padre, e non devono essere forzatamente posizionati sopra questa.
La vostra finestra deve possedere un pulsante di default, sensibile, che l'utente attiva premendo il tasto Invio. gnome_dialog_set_default() specifica questo tipo di pulsante. È a vostro giudizio stabilire quale sia questo pulsante all'interno della finesta (solitamente "Annulla" piuttosto che "OK").
Tipicamente le operazioni come l'eliminazione di dati oppure l'uscita da un applicativo hanno "Annulla" oppure "No" come default. I dialoghi che invece richiedono l'inserimento di testo da parte dell'utente sono impostati per avere "OK" come default. Ricordate che molti gestori di finestre spostano il fuoco alle nuove finestre, quindi le scorciatoie da tastiere che l'utente utilizza nella applicazione dovrebbero essere utilizzati anche nel dialogo. Se la vostra finestra contiene come default il tasto "Distruggi il contenuto del mio disco" riceverete strani messaggi di email.
I widget modificabili emettono il segnale "activate" quando viene premuto il tasto Invio. L'utente si aspetta solitamente che la pressione del tasto Invio attivi il pulsanti di default della finestra di dialogo, MA, se all'interno della vostra finestra si trova uno dei widget modificabili, come GtkEntry, questo catturerà per se la pressione del tasto Invio, impendendo hai pulsanti di ricevere l'evento. gnome_dialog_editable_enters() attiva il pulsante di default quando il widget GtkEntry viene attivato, risolvendo il problema.
gnome_dialog_set_sensitive() chiama
gtk_widget_set_sensitive() sul pulsante. Se la pressione del pulsante in determinato momento non ha senso è bene allora che questo sia desensibilizzato.
Infine, dovete assicurarvi di non creare instanze multiple di questo tipo di finestre. Comuni applicazioni permettono di aprire contemporaneamente più finestre di preferenze o di aiuto. Gli utenti ono si accorgono sempre di questo errore, ma è bene evitarlo. I seguente codice di esempio risolve questo problema in modo molto semplice (sono stati omessi i dettagli sulla creazione e visualizzazione della finestra) :
void
do_dialog()
{
static GtkWidget* dialog = NULL;
if (dialog != NULL)
{
/* Queste istruzioni tentano di ripristinare
* la finestra di dialogo.
* Si assume che la finestra sia stata realizzata
* se non potete assicurarvi di ciò, controllate che
* dialog->window != NULL.
*/
gdk_window_show(dialog->window);
gdk_window_raise(dialog->window);
}
else
{
dialog = gnome_dialog_new(); /* Arguments elided. */
gtk_signal_connect(GTK_OBJECT(dialog),
"destroy",
GTK_SIGNAL_FUNC(gtk_widget_destroyed),
&dialog);
/* Inserire qui la visualizzazione della finestra,
* l'associazione delle callback etc
*/
}
}
La funzione gtk_widget_destroyed() è definita in gtk/gtkwidget.h, e assegna, molto semplicemente, NULL come secondo argomento. Questo codice azzera lal variabile dialog ogni volta che l'utente chiude la finestra, e tenta di ripristinarla se tenta di aprirne un'altra mentre la prima è gia attiva. Attenzione: il gestore di finestre può gestire diversamente la procedura di ripristino, quindi non è garantito che questo accada.