1 <!doctype linuxdoc system>
4 <author>Ian Main <tt><htmlurl url="mailto:imain@gtk.org"
5 name="<imain@gtk.org>"></tt>,
6 Tony Gale <tt><htmlurl url="mailto:gale@gtk.org"
7 name="<gale@gtk.org>"></tt>
8 <date>May 24th, 1998 - Traduzione aggiornata al 27 Maggio 1998
10 <abstract>Tradotto da Michel Morelli, <tt><htmlurl url="mailto:ziobudda@chiara.dei.unipd.it" name="ziobudda@chiara.dei.unipd.it"></tt>, Daniele Canazza, <tt><htmlurl url="mailto:dcanazz@tin.it" name="dcanazz@tin.it"></tt> e Antonio Schifano, <tt><htmlurl url="mailto:schifano@cli.di.unipi.it" name="schifano@cli.di.unipi.it"></tt>
12 <!-- ***************************************************************** -->
14 <!-- ***************************************************************** -->
16 GTK (GIMP Toolkit) è stato orginariamente sviluppato come toolkit per
17 il programma GIMP (General Image Manipulation Program). GTK è costruito
18 sulla base del kit di disegno di GIMP, il GDK (GIMP Drawing Kit) il quale
19 è costruito a sua volta attorno alle funzioni della Xlib. E' chiamato
20 ``toolkit di GIMP'' perché era inizialmente scritto per sviluppare GIMP,
21 ma ora viene utilizzato nello sviluppo di molti progetti software ``free''.
24 <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
25 name="petm@xcf.berkeley.edu"></tt>
26 <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
27 name="spencer@xcf.berkeley.edu"></tt>
28 <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
29 name="jmacd@xcf.berkeley.edu"></tt>
33 GTK è essenzialmente una API (application programmers interface)
34 orientata agli oggetti.
35 Anche se scritto completamente in C, è implementato usando l'idea delle
36 classi e delle funzioni di callback (puntatori a funzioni).
39 C'è anche una terza componente chiamata glib che contiene una serie di
40 implementazioni differenti di alcune chiamate di funzioni standard e anche
41 alcune funzioni aggiuntive, per esempio per la manipolazione delle liste
42 collegate. Le funzioni sostitutive sono usate per migliorare la
43 portabilità di GTK. Alcune delle funzioni implementate qui non sono
44 disponibili o non sono standard, altre sono uniche come g_strerror().
45 Altre contengono miglioramenti alle stesse della libc come g_malloc che ha
46 delle utility di debugging migliorate.
49 Questo tutorial è un tentativo di documentare il meglio possibile la
50 libreria gtk e non pretende di essere completo. Questo tutorial suppone una
51 buona conoscenza del linugaggio C e di come creare programmi in C. Saranno
52 facilitati i lettori che hanno una precedente esperienza nella programmazione
53 in X. Se il GTK è il primo insieme di widget che studiate, vi prego di
54 dirmi come avete trovato questo tutorial e che tipo di problemi avete avuto.
55 Notate che c'è anche una versione per il C++ della libreria GTK (chiamata
56 GTK--), quindi se preferite utilizzare questo linguaggio al posto del C potreste
57 cercare questa versione al posto della GTK normale.
58 Ci sono poi un ``wrapper'' Objective C e un collegamento a Guile, ma non ne
62 Mi farebbe molto piacere conoscere qualsiasi problema che abbiate avuto
63 nell'imparare il GTK da questo documento e apprezzerei anche critiche sul come
66 <!-- ***************************************************************** -->
68 <!-- ***************************************************************** -->
70 La prima cosa da fare è certamente quella di scaricare il GTK e installarlo.
71 Potete prendere l'ultima versione dal sito ftp.gtk.org in /pub/gtk. Un'altra
72 possibile sorgente di informazioni è il sito
73 <htmlurl url="http://www.gtk.org/" name="http://www.gtk.org/">.
75 GTK usa il comando GNU autoconf per autoconfigurarsi.
76 Una volta estratti i file dall'archivio tar, eseguite configure --help per
77 vedere una lista delle opzioni del comando configure.
80 Per iniziare la nostra introduzione a GTK, cominceremo con il più semplice
81 programma possibile. Questo programma crea una finestra con dimensioni (in pixel)
82 di 200x200 e l'unica possibilità di uscita è di ucciderlo usando la
83 shell o il Window Manager.
88 int main (int argc, char *argv[])
92 gtk_init (&argc, &argv);
94 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
95 gtk_widget_show (window);
103 Tutti i programmi GTK includeranno sicuramente <gtk/gtk.h> in cui vengono
104 dichiarate le variabili, le funzioni, le strutture, etc. che saranno usate nella
105 tua applicazione GTK.
111 gtk_init (&argc, &argv);
114 invoca la funzione gtk_init(gint *argc, gchar ***argv) che sarà usata in
115 tutte le applicazioni GTK. Questa funzione sistema alcune cose al posto nostro,
116 come la visuale predefinita e la mappa dei colori, e procede poi chiamando
117 gdk_init(gint *argc, gchar ***argv).
118 Questa funzione inizializza la libreria per l'uso, setta il gestore predefinito
119 dei segnali e guarda negli argomenti, passati via linea di comando alla vostra
120 applicazione, alla ricerca di uno di questi argomenti:
122 <item> <tt/--display/
123 <item> <tt/--debug-level/
124 <item> <tt/--no-xshm/
126 <item> <tt/--show-events/
127 <item> <tt/--no-show-events/
130 Rimuove poi questi argomenti dalla lista degli argomenti passati, lasciando
131 quelli non riconosciuti a disposizione della vostra applicazione che potrà
132 tenerne conto o ignorarli.
133 In questo modo si crea un set di argomenti standard accettato da tutte le
137 Le seguenti 2 linee di codice creano e mostrano la finestra.
140 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
141 gtk_widget_show (window);
144 L'argomento GTK_WINDOW_TOPLEVEL specifica che noi vogliamo che la nostra finestra
145 si sottometta alle decorazioni del windows manager e alla posizione che quest'ultimo
146 indicherà. Invece di creare una finestra avente dimensioni 0x0, la dimensione
147 di una finestra senza figli (altri widget, come i bottoni, etc) è predefinita
148 a 200x200 così che si possa manipolarla.
149 La funzione gtk_widget_show() fa sì che GTK sappia che abbiamo finito di
150 settare gli attributi di questo widget e che quindi quest'ultimo può essere
154 L'ultima linea ci fa entrare nel ciclo principale del GTK.
160 gtk_main() è un'altra chiamata che vedrete in tutte le applicazioni GTK.
161 Quando il controllo raggiunge questo punto, l'applicazione si metterà a
162 dormire aspettando che si verifichino eventi di X (come la pressione di un bottone
163 o di un tasto), timeout o notifiche di Input/Output dai file
164 Nel nostro esempio, comunque, tutti gli eventi vengono ignorati.
166 <!-- ----------------------------------------------------------------- -->
167 <sect1>Hello World in GTK
168 <!-- ----------------------------------------------------------------- -->
170 Ok, ora un programma con un widget (un bottone). E' il classico ``Hello World''
178 /* E' una funzione di ritorno (callback). Gli argomenti passati sono ignorati in questo
180 * Piu' informazioni sulle callback in seguito. */
182 void hello (GtkWidget *widget, gpointer data)
184 g_print ("Hello World\n");
187 gint delete_event(GtkWidget *widget, gpointer data)
189 g_print ("delete event occured\n");
190 /* Se si dà FALSE al gestore del segnale ``delete_event'', GTK emettera' il segnale
191 * ``destroy''. Fornire TRUE significa non volere che la finestra sia distrutta.
192 * Questo e' utile per far uscire delle finestre di dialogo del tipo:
193 * 'sei sicuro di voler uscire ?'
194 * Cambia TRUE in FALSE e la finestra principale sara' distrutta con un "delete_event"
201 /* Un'altra callback */
202 void destroy (GtkWidget *widget, gpointer data)
207 int main (int argc, char *argv[])
209 /* GtkWidget e' il tipo di dato per i Widget */
213 /* Questa e' una chiamata presente in tutte le applicazioni GTK. Gli argomenti della
214 linea di comando vengono scorsi e restituiti alla applicazione */
215 gtk_init (&argc, &argv);
217 /* Crea una nuova finestra */
218 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
220 /* Quando alla finestra viene passato il segnale ``delete_event'' (questo
221 * segnale viene passato Windows Manager di solito con l'opzione 'close'
222 * o con la barra del titolo (title bar)) noi chiediamo che la funzione
223 * delete_event() (definita sopra) venga invocata.
224 * Il dato passato come argomento alla funzione di ritorno é NULL
225 * ed é ignorato dalla funzione stessa. */
226 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
227 GTK_SIGNAL_FUNC (delete_event), NULL);
229 /* Qui connettiamo l'evento ``destroy'' al gestore del segnale.
230 * Questo evento accade quando noi chiamimo la funzione gtk_widget_destroy()
231 * sulla finestra o se ritorniamo FALSE dalla callback ``delete_event''. */
232 gtk_signal_connect (GTK_OBJECT (window), "destroy",
233 GTK_SIGNAL_FUNC (destroy), NULL);
235 /* Setta il bordo interno della finestra */
236 gtk_container_border_width (GTK_CONTAINER (window), 10);
238 /* Crea un nuovo bottone avente etichetta (label) uguale a ``Hello World'' */
239 button = gtk_button_new_with_label ("Hello World");
241 /* Quando il bottone riceve il segnale ``clicked'', invochera' la funzione
242 * hello() passando NULL come argomento della funzione. La funzione
243 * hello() é definita sopra. */
244 gtk_signal_connect (GTK_OBJECT (button), "clicked",
245 GTK_SIGNAL_FUNC (hello), NULL);
247 /* Questo farà sì che la finestra venga distrutta dalla chiamata
248 * gtk_widget_destroy(window) quando il bottone verrà premuto. Ancora,
249 * questo segnale (``destroy'') puo' arrivare da qui o dal windows
251 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
252 GTK_SIGNAL_FUNC (gtk_widget_destroy),
253 GTK_OBJECT (window));
255 /* Questo inserisce il bottone nella finestra
256 * (un contenitore GTK) */
257 gtk_container_add (GTK_CONTAINER (window), button);
259 /* Il passo finale é il mostrare questo nuovo widget appena creato */
260 gtk_widget_show (button);
263 gtk_widget_show (window);
265 /* Tutte le applicazioni GTK devono avere la funzione gtk_main().
266 * Il controllo finisce qui e attende un evento (come la pressione
267 * di un tasto o l'evento di un mouse). */
274 <!-- ----------------------------------------------------------------- -->
275 <sect1>Compilare hello World
276 <!-- ----------------------------------------------------------------- -->
278 Per compilare si utilizza :
282 gcc -Wall -g helloworld.c -o hello_world `gtk-config --cflags` \
285 (N.d.T.: se lanciato da linea di comando, il precedente comando di
286 compilazione va messo su di una unica linea eliminando il backslash)
288 In questo modo, si usa il progamma <tt>gtk-config</>, che viene
289 distribuito con gtk. Questo programma 'sa' che opzioni di compilatore
290 sono necessarie per compilare i programmi che usano gtk.
291 <tt>gtk-config --cflags</> dà come risultato una lista di directory
292 in cui i file di include devono essere cercati, e <tt>gtk-config --libs</>
293 fornisce invece la lista delle librerie che devono essere linkate con le
294 directory in cui devono essere cercate.
297 Le librerie che normalmente vengono linkate sono:
299 <item> la libreria glib (-lglib), contiene varie funzioni, ma solo
300 g_print() é usato in questo esempio. GTK si appoggia a questa
301 libreria, quindi essa viene sempre, comunque, linkata. Vedi comunque
302 la sezione sulla <ref id="sec_glib" name="glib"> per altri dettagli.
303 <item>La libreria GDK (-lgdk), la copertura della X11.
304 <item>La libreria GTK (-lgtk), la libreria dei widget, basata sulla GDK.
305 <item>La libreria Xlib(-lX11) la quale è usata dalla GDK.
306 <item>La libreria Xext(-lXext). Questa contiene il codice per le pixmap a
307 memoria condivisa e altre estensioni di X.
308 <item>La libreria matematica (-lm). Questa é usata dalla GTK per
312 <!-- ----------------------------------------------------------------- -->
313 <sect1>Teoria dei segnali e delle funzioni di ritorno (callback)
315 Prima di guardare in dettaglio ``Hello World'', parleremo un po' degli eventi
316 e delle funzioni di ritorno. GTK è un toolkit guidato dagli eventi,
317 il che significa che se ne starà a dorimire in gtk_main finché
318 non succede un evento ed il controllo viene passato alla funzione appropriata.
321 Questo passaggio di controllo è basato sull'idea dei segnali.
322 Quando si ha un evento, come la pressione di un bottone del mouse, verrà
323 emesso il segnale appropriato, per esempio dal widget che é stato premuto.
324 Questo è il modo in cui GTK fa molto del suo utile lavoro. Per far
325 sì che un bottone esegua una azione, prepareremo un gestore del segnale
326 che catturi questi segnali e chiami la funzione corretta. Questo viene fatto
327 usando una funzione del tipo:
330 gint gtk_signal_connect (GtkObject *object,
336 in cui il primo argomento è il widget che emetterà il segnale,
337 il secondo è il nome del segnale che si vuole catturare, il terzo è
338 la funzione che verrà invocata quando il segnale sarà catturato e
339 il quarto è il dato che potrà essere passato a questa funzione.
341 La funzione specificata come terzo argomento è chiamata ``funzione di
342 ritorno (callback)'', e dovrebbe essere della forma:
345 void callback_func(GtkWidget *widget, gpointer callback_data);
348 Dove il primo argomento sarà un puntatore al widget che emette il segnale
349 e il secondo un puntatore al dato passato come ultimo argomento della funzione
350 gtk_signal_connect() come descritto sopra.
352 Un'altra chiamata usata nell'esempio Hello World è:
355 gint gtk_signal_connect_object (GtkObject *object,
358 GtkObject *slot_object);
361 gtk_signal_connect_object() è uguale a gtk_signal_connect() eccetto che
362 la funzione di callback usa solo un argomento, un puntatore ad un'oggetto GTK.
363 Così quando si usa questa funzione per connettere i segnali, la callback
364 dovrebbe essere della forma :
367 void callback_func (GtkObject *object);
370 dove object è normalmente un widget. Generalmente, non si assegna
371 una callback per gtk_signal_connect_object. Queste sono invocate, usualmente,
372 per chiamare una funzione GTK che accetta un widget singolo o un oggetto come
373 argomento, come nel caso dell'esempio Hello World.
375 Lo scopo di avere due funzioni per connettere i segnali è semplicemente
376 quello di permettere alla funzione di callback di avere un numero di argomenti
377 diverso. Molte funzioni della libreria GTK accettano solo un singolo puntatore
378 ad un widget GTK come argomento, così per queste si può usare la
379 funzione gtk_signal_connect_object(), mentre per le vostre funzioni potreste
380 aver bisogno di passare dati supplementari alle funzioni di ritorno.
382 <sect1>Attraverso Hello World passo per passo
384 Ora che conosciamo la teoria che vi è dietro, iniziamo ad essere più
385 chiari camminando attraverso il programma di Hello World.
387 Questa è la funzione di callback che sarà invocata quando il bottone
389 Noi, in questo esempio, ignoriamo sia il widget che i dati passati, ma non è
390 difficile farci invece qualcosa. Il prossimo esempio userà l'argomento passato
391 per dire quale bottone è stato premuto.
394 void hello (GtkWidget *widget, gpointer data)
396 g_print ("Hello World\n");
401 Questa callback è un po' speciale. L'evento ``delete'' avviene quanto
402 il Window Manager manda questo evento all'applicazione. Qui abbiamo una scelta
403 da fare: cosa fare di questo evento. Possiamo ignorarlo, creare qualche tipo di
404 risposta, o semplicemente terminare l'applicazione.
406 Il valore che si restituisce in questa callback fa sì che la GTK sappia
407 cosa fare. Restituire TRUE significa che non vogliamo che il segnale ``destroy''
408 sia emesso, quindi far sì che la nostra applicazione proceda normalmente.
409 Ritornare FALSE vuole dire far emettere il segnale ``destroy'' il quale
410 chiamerà la nostra funzione di callback che gestisce il segnale ``destroy''.
413 gint delete_event(GtkWidget *widget, gpointer data)
415 g_print ("delete event occured\n");
421 Questa è un'altra funzione di callback la quale fa uscire dal programma
422 chiamando gtk_main_quit(). Questa funzione dice a GTK che deve uscire da gtk_main
423 quando gli viene restituito il controllo.
426 void destroy (GtkWidget *widget, gpointer data)
432 Ritengo che conosciate la funzione main()... si, come tutte le altre applicazioni
433 anche le applicazioni GTK hanno questa funzione.
436 int main (int argc, char *argv[])
440 Questa parte dichiara un puntatore ad una struttura di tipo GtkWidget. Queste sono
441 usate più sotto per creare una finestra ed un bottone.
448 Qui vi è ancora la nostra gtk_init. Come prima questa inizializza il toolkit
449 e analizza gli argomenti trovati nella linea di comando. Tutti gli argomenti
450 riconosciuti nella linea di comando sono rimossi dalla lista degli argomenti e
451 vengono così modificati argc e argv per far sì che sembri che questi
452 non siano mai esisiti e permettere alla vostra applicazione di analizzare gli
456 gtk_init (&argc, &argv);
459 Crea una nuova finestra. Questo viene spiegato abbastanza approfonditamente
460 più avanti. Viene allocata la memoria per la struttura GtkWidget *window
461 così che si punti ad una struttura valida. In questo modo si predispone
462 la nuova finestra, ma non la si visualizza fino a sotto dove, quasi alla fine
463 del nostro programma, invochiamo gtk_widget_show(window).
465 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
468 Questo è un esempio di come connettere un gestore dei segnali con un oggetto,
469 in questo caso la finestra. Qui viene catturato il segnale ``destroy''. Questo
470 viene emesso quando usiamo il Window Manager per uccidere la finestra (e noi
471 restituiamo TRUE dal gestore di ``delete_event'') o quando emettiamo la chiamata
472 gtk_widget_destroy() passando l'oggetto finestra come oggetto da distruggere.
473 Sistemando le cose così, trattiamo entrambi i casi con una singola
474 chiamata. Qui è giusto invocare la funzione destroy() definita sopra con
475 NULL come argomento, la quale termina l'applicazione GTK per noi.
476 Questo ci permetterà di utilizzare il Window Manager per uccidere il programma.
478 GTK_OBJECT e GTK_SIGNAL_FUNC sono macro che interpretano il casting e il controllo
479 di tipo per noi, così da rendere piu' leggibile il codice.
482 gtk_signal_connect (GTK_OBJECT (window), "destroy",
483 GTK_SIGNAL_FUNC (destroy), NULL);
486 La prossima funzione è usata per settare un attributo di un oggetto
487 contenitore. Questo sistema la finestra così da avere un'area vuota
488 all'interno della finestrra larga 10 pixel dove non potrà andare nessun
489 widget. Ci sono altre funzioni simili che vedremo nella
490 sezione <ref id="sec_setting_widget_attributes" name="Settare gli attributi del Widget.">
492 E ancora, GTK_CONTAINER è una macro per interpretare il casting di tipo.
495 gtk_container_border_width (GTK_CONTAINER (window), 10);
498 Questa chiamata crea un nuovo bottone. Alloca spazio in memoria per un nuovo
499 GtkWidget, inizializzandolo e facendo sì che il puntatore a bottone punti
501 Quando sarà visualizzato, avrà etichetta ``Hello World''.
504 button = gtk_button_new_with_label ("Hello World");
507 Qui prendiamo il bottone e gli facciamo fare qualcosa di utile.
508 Gli colleghiamo un gestore di segnale in modo che quando emetterà il
509 segnale ``clicked'', verrà invocata la nostra funzione hello(). Il
510 dato passato alla funzione è ignorato, cosicché alla funzione
511 di callback hello() passiamo semplicemente NULL. Evidentemente il segnale
512 ``clicked'' viene emesso quando premiamo il bottone con il mouse.
515 gtk_signal_connect (GTK_OBJECT (button), "clicked",
516 GTK_SIGNAL_FUNC (hello), NULL);
519 Usiamo questo bottone anche per uscire dal programma. Questo illustrerà
520 come il segnale ``destroy'' può arrivare sia dal Window Manager che dal
521 nostro programma. Quando il bottone viene cliccato come descritto sopra,
522 chiamerà la funzione di callback hello() e poi quest'ultima nell'ordine
523 in cui sono definite. Si possono cioé avere tante funzioni di callback
524 quante sono necessarie, e saranno eseguite nell'ordine in cui sono connesse.
525 Visto che la funzione gtk_widget_destroy() accetta come argomento solo un GtkWidget *widget, usiamo la funzione
526 gtk_signal_connect_object() al posto della normale gtk_signal_connect().
529 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
530 GTK_SIGNAL_FUNC (gtk_widget_destroy),
531 GTK_OBJECT (window));
534 Questa é una chiamata di ``impacchettamento'' che sarà spiegata
535 più avanti. Ma è molto facile da capire. Semplicemente dice alla
536 libreria GTK che il bottone è da mettere nella finestra dove sarà
540 gtk_container_add (GTK_CONTAINER (window), button);
543 A questo punto abbiamo predisposto tutto quello che ci eravamo prefissati.
544 Con tutti i gestori di segnale a posto e il bottone messo nella finestra in cui
545 dovrebbe essere, possiamo dire a GTK di mostrare gli oggetti sullo schermo.
546 L'oggetto finestra viene mostrato per ultimo così che la finestra
547 completa di tutti i suoi oggetti verrà mostrata tutta in una volta,
548 invece di vedere prima la finestra spoglia e poi la comparsa del bottone
549 all'interno di essa. Per quanto, con questi semplici esempi, questo l'avrete
552 gtk_widget_show (button);
554 gtk_widget_show (window);
557 E naturalmente chiamiamo gtk_main(), la quale aspetta l'arrivo degli eventi
558 dal server X e chiama l'oggetto interessato per fargli emettere il segnale
563 E il return finale. Il controllo ritorna qui dopo che viene invocata gtk_quit().
569 Ora, quando premiamo il bottone del mouse su un bottone GTK, questo oggetto
570 emette il segnale ``clicked''. Per poter utilizzare queste informazioni, il
571 nostro programma predispone un gestore di segnale per catturare quel segnale,
572 il quale avvia la funzione da noi scelta. Nel nostro esempio, quando il
573 bottone creato viene cliccato, la funzione hello() viene invocata con argomento
574 NULL, dopoodiché viene invocato il successivo gestore di questo segnale.
575 Questo chiama la funziona gtk_widget_destroy(), passandole l'oggetto-finestra
576 (window) come argomento, che distruggerà la finestra. Questo fa sì
577 che la finestra emetta il segnale ``destroy'' che viene catturato e che fa
578 invocare la funzione di ritorno destroy(), che semplicemente esce dal programma GTK.
580 Un'altro modo in cui possono andare le cose è l'uso del window manager per
581 uccidere la finestra. Questo causera' l'emissione del segnale ``delete_event'' che
582 automaticamente chiamerà il gestore del segnale ``delete_event''. Se qui noi
583 restituiamo il valore TRUE, la finestra non verrà toccata e tutto
584 procederà come se nulla fosse successo. Dare invece il valore FALSE
585 causerà l'emissione da parte di GTK del segnale ``destroy'' il quale, a sua
586 volta, invocherà la callback ``destroy'', uscendo dall'applicazione.
588 Nota che questi segnali non sono gli stessi del sistema Unix e che non sono
589 implementati usando quei segnali, anche se la terminologia è praticamente
592 <!-- ***************************************************************** -->
594 <!-- ***************************************************************** -->
597 <!-- ----------------------------------------------------------------- -->
600 Ci sono alcune cose che avrete probabilmente notato nei precedenti esempi che
601 hanno bisogno di una spiegazione. I gint, gchar ecc. che vedete sono tipi di dato
602 (typedef) riferiti rispettivamente a int e char. Questo viene fatto per rimediare
603 alle scomode dipendenze dalle dimensioni di semplici tipi di dato quando si fanno
604 dei calcoli. Un buon esempio è ``gint32'' il quale sarà un tipo di
605 dato riferito ad un intero a 32 bit per tutte le piattaforme, sia per gli x86 che
606 per gli per gli alpha a 64 bit.
607 I tipi di dato sono ben spiegati più avanti e molto intuitivi. Sono definiti
608 in glib/glib.h (il quale viene incluso da gtk.h).
610 Noterete anche la possibilità di utilizzare un GtkWidget quando la funzione
611 richiede un GtkObject. GTK è una libreria orienta agli oggetti ed un widget
614 <!-- ----------------------------------------------------------------- -->
615 <sect1>Altri Dettagli sui Segnali
617 Diamo un'altra occhiata alla dichiarazione della funzione gtk_signal_connect.
620 gint gtk_signal_connect (GtkObject *object, gchar *name,
621 GtkSignalFunc func, gpointer func_data);
623 Notate il valore di ritorno definito come gint? Questo è un identificatore
624 per la vostra funzione di callback. Come detto sopra, si possono avere più
625 funzioni di ritorno per ogni segnale e per ogni ogetto a seconda delle
626 necessità, ed ognuna sarà eseguita in sequenza, nell'ordine in cui
627 è stata collegata.
629 Questo identificatore vi permette di rimuovere una funzione dalla lista delle
630 funzioni di ritorno tramite la seguente chiamata
633 void gtk_signal_disconnect (GtkObject *object,
636 Così, passando il widget da cui si vuole rimuovere il gestore di segnale e
637 l'identificativo restituito da una delle funzioni signal_connect, si può
638 rimuovere il gestore di segnale che si desidera dal widget.
640 Un'altra funzione, usata per rimuovere tutti i segnali di un widget in una volta
644 gtk_signal_handlers_destroy (GtkObject *object);
647 Questa chiamata è abbastanza auto esplicativa. Semplicemente rimuove tutti
648 i segnali collegati al widget che si passa alla funzione come argomento.
650 <!-- ----------------------------------------------------------------- -->
651 <sect1>Miglioriamo Hello World
654 Diamo un'occhiata ad una versione migliorata di Hello World con altri esempi
655 sulle callback. Questo ci introdurrà anche al nostro prossimo argomento,
656 l'impacchettamento dei widget.
662 /* La nostra funzione di callback migliorata. I dati passati a questa
663 * vengono stampati su stdout. */
664 void callback (GtkWidget *widget, gpointer data)
666 g_print ("Hello again - %s was pressed\n", (char *) data);
669 /* Un'altra callback */
670 void delete_event (GtkWidget *widget, gpointer data)
675 int main (int argc, char *argv[])
677 /* GtkWidget e' il tipo di dato per i widget */
682 /* Questa funzione e' invocata in tutte le applicazioni GTK, gli
683 argomenti sono analizzati e restituiti all'applicazione. */
684 gtk_init (&argc, &argv);
686 /* Crea una nuova finestra */
687 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
689 /* Questa e' una nuova chiamata. Assegna "Hello Buttons" come titolo
690 della nostra finestra */
691 gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
693 /* Qui settiamo il gestore per il segnale "delete_event" che
694 immediatamente esce dalla applicazione.
695 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
696 GTK_SIGNAL_FUNC (delete_event), NULL);
699 /* predispone il bordo della finestra */
700 gtk_container_border_width (GTK_CONTAINER (window), 10);
702 /* creiamo una scatola dove mettere tutti i widget. Questa è descritta
703 dettagliatamente nella sezione "packing". La scatola non è realmente
704 visibile, è solamente usata per sistemare i widget. */
705 box1 = gtk_hbox_new(FALSE, 0);
707 /* Inseriamo la scatola nella finestra */
708 gtk_container_add (GTK_CONTAINER (window), box1);
710 /* Creiamo un nuovo bottone con etichetta "Button 1" */
711 button = gtk_button_new_with_label ("Button 1");
713 /* Quando il bottone e' premuto, noi invocheremo la funzione di callback,
714 con un puntatore alla stringa "button 1" come proprio argomento) */
715 gtk_signal_connect (GTK_OBJECT (button), "clicked",
716 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
718 /* invece di aggiungerlo alla finestra, lo inseriamo nella scatola invisibile,
719 la quale e' stata inserita nella finstra. */
720 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
722 /* Ricordati sempre questo passo. Dice a GTK che la preparazione di questo
723 bottone e' finita e che quindi puo' essere mostrato. */
724 gtk_widget_show(button);
726 /* Facciamo la stessa cosa per il secondo bottone. */
727 button = gtk_button_new_with_label ("Button 2");
729 /* Chiamiamo la stessa funzione ma passandogli un argomento differente,
730 gli passiamo un puntatore alla stringa "button 2" */
731 gtk_signal_connect (GTK_OBJECT (button), "clicked",
732 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
734 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
736 /* L'ordine nel quale i bottoni sono visualizzati non e' realmente importante,
737 ma io ti raccomando di mostrare per ultima la finestra cosi' che tutto
738 sia visualizzato in una volta sola */
739 gtk_widget_show(button);
741 gtk_widget_show(box1);
743 gtk_widget_show (window);
745 /* e ora ci mettiamo in gtk_main e aspettiamo che il diverimento inizi.
752 Compilate questo programma usando gli stessi argomenti di link del nostro primo
753 esempio. Noterete che questa volta non c'è un modo semplice per uscire
754 dal programma, si deve usare il nostro window manager o la linea di comando per
755 uccidere l'applicazione.
756 Un buon esercizio per il lettore è quello di inserire un tezo bottone
757 ``quit'' che faccia uscire dal programma. Potete anche divertirvi con le opzioni
758 di gtk_box_pack_start() mentre leggete il prossimo capitolo. Provate a
759 ridimensionare la finestra ed a osservare cosa succede.
761 Solo una piccola nota: c'è un'altra definizione di gtk_window_new() -
762 GTK_WINDOW_DIALOG. Questa interagisce con il window manager in un modo un po'
763 diverso, e dovrebbe essere usata per finestre temporanee.
765 <!-- ***************************************************************** -->
766 <sect>Come ``Impacchettare'' i Widget
767 <!-- ***************************************************************** -->
769 Nel momento in cui si crea un'applicazione, normalmente si avrà la
770 necessità di mettere più di un unico bottone all'interno di
771 una finestra. Il nostro primo esempio ``Hello World'' usava un solo oggetto,
772 cosicché abbiamo potuto usare semplicemente una chiamata a
773 gtk_container_add per impacchettare il widget nella finestra. Quando invece
774 si vuole inserire più di un unico widget in una finestra, come si fa
775 a controllare dove vengono posizionati i propri oggetti? E' qui che entra in
776 gioco il meccanismo dell'``impacchettamento''.
777 <!-- ----------------------------------------------------------------- -->
778 <sect1>Teoria delle Scatole per Impacchettamento
780 La maggior parte dell'impacchettamento viene effettuata creando delle scatole
781 come nell'esempio più sopra. Le scatole sono dei contenitori invisibili
782 di widget che possiamo usare per imballarci i nostri oggetti e che esistono in
783 due varietà: in particolare si possono avere scatole orizzontali (hbox)
785 Quando si impacchentano degli oggetti in una scatola orizzontale, gli oggetti
786 vengono inseriti orizzontalmente da sinistra a destra oppure da destra a sinistra
787 a seconda della chiamata di funzione che si usa. In una scatola verticale, gli
788 oggetti vengono inseriti dall'alto in basso o viceversa. Si può usare
789 qualsiasi combinazione di scatole all'interno o a fianco di altre scatole, fino
790 ad ottenere l'effetto desiderato.
792 Per creare una nuova scatola orizzontale, si usa una chiamata a gtk_hbox_new(),
793 mentre per le scatole verticali si usa gtk_vbox_new(). Per inserire i widget
794 all'interno di questi contenitori si usano le funzioni gtk_box_pack_start() e
795 gtk_box_pack_end(). La funzione gtk_box_pack_start() comincerà dall'alto
796 verso il basso in una vbox e da sinistra a destra in una hbox. gtk_box_pack_end()
797 fa l'opposto, impacchettando dal basso verso l'alto in una vbox e da destra a
798 sinistra in una hbox. Queste funzioni ci permettono di giustificare a destra o
799 a sinistra i nostri widget, e possono essere mescolate in qualsiasi modo per
800 ottenere l'effetto desiderato. Useremo gtk_box_pack_start() nella maggior parte
801 dei nostri esempi. Un oggetto può essere costituito da un altro contenitore
802 o da un oggetto grafico. Infatti, molti oggetti grafici sono a loro volta dei
803 contenitori, compreso il bottone, anche se tipicamente all'interno del bottone
804 mettiamo solo una etichetta.
807 Usando queste chiamate, GTK riesce a capire dove si vogliono piazzare i propri
808 widget, in modo di essere poi in grado di effettuare il ridimensionamento
809 automatico e altre cose interessanti. Esiste poi un insieme di opzioni che riguardano
810 il modo in cui i propri oggetti grafici dovrebbero essere impacchettati. Come
811 si può immaginare, questo metodo dà una buona flessibilità nella creazione e
812 nella disposizione dei propri widget.
814 <!-- ----------------------------------------------------------------- -->
815 <sect1>Dettagli sulle Scatole
817 A causa di questa flessibilità, le scatole per impacchettamento del GTK
818 possono, di primo acchito, creare un po' di disorientamento. Sono infatti disponibili
819 molte opzioni, e non è immediato il modo in cui si combinano l'una con l'altra.
820 Alla fine però, si possono ottenere essenzialmente cinque diversi stili.
825 <IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528" HEIGHT="235"
826 ALT="Box Packing Example Image">
830 Ogni linea contiene una scatola orizzontale (hbox) con diversi bottoni.
831 La chiamata a gtk_box_pack è una scorciatoia per la chiamata di
832 impacchettamento di ognuno dei bottoni nella hbox. Ognuno dei bottoni viene
833 impacchettato nella hbox nello stesso modo (cioè, con gli stessi
834 argomenti per la funzione gtk_box_pack_start ()).
836 Questa è la dichiarazione della funzione gtk_box_pack_start.
839 void gtk_box_pack_start (GtkBox *box,
845 Il primo argomento è la scatola nella quale si stanno inscatolando i
846 widget, il secondo è il widget stesso. Gli oggetti per ora saranno
847 bottoni, quindi quello che faremo sarà impacchettare bottoni in scatole.
849 L'argomento ``expand'' in gtk_box_pack_start() o gtk_box_pack_end() controlla
850 se gli oggetti devono essere sistemati nella scatola in modo da riempire tutto
851 lo spazio in diponibile presente nella scatola, in modo che la scatola si espanda
852 fino ad occupare tutta l'area assegnatale (valore TRUE).
853 La scatola può anche essere rimpiciolita in modo da contenere esattamente i
854 widget (valore FALSE). Assegnare a expand il valore FALSE permette di giustificare
855 a destra o sinistra i propri oggetti. In caso contrario, tutti gli ogetti si
856 espandono fino ad adattarsi alla scatola, e il medesimo effetto si può
857 ottenere usando solo una delle funzioni gtk_box_pack_start o pack_end.
859 L'argomento ``fill'' delle funzioni gtk_box_pack stabilisce se lo spazio disponibile
860 nella scatola deve essere allocato agli oggetti (TRUE) o se deve essere mantenuto
861 come riempimento attorno a questi oggetti (FALSE). Questo argomento ha effetto
862 solo se a expand è assegnato il valore TRUE.
864 Quando si crea una nuova scatola, la funzione ha questo aspetto:
867 GtkWidget * gtk_hbox_new (gint homogeneous,
871 L'argomento homogeneous di gtk_hbox_new (la stesso per gtk_vbox_new)
872 determina se ogni oggetto nella scatola deve avere la stessa dimensione
873 (cioè la stessa ampiezza in una hbox o la stessa altezza in una vbox).
874 Se è settato, l'argomento expand delle routine gtk_box_pack è
877 Qual è la differenza fra la spaziatura (che è stabilita quando
878 la scatola viene creata) e il riempimento (che viene stabilito quando gli
879 elementi vengono impacchettati)? La spaziatura viene inserita fra gli oggetti,
880 mentre il riempimento viene aggiuno a ciascuno dei lati dell'oggetti. La seguente
881 figura dovrebbe chiarire meglio questo punto:
885 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509" HEIGHT="213"
886 VSPACE="15" HSPACE="10" ALT="Box Packing Example Image">
891 Di seguito è riportato il codice usato per creare le immagini precedenti.
892 L'ho commentato in modo piuttosto pesante, in modo che non dovreste avere
893 problemi nel seguirlo. Compilatelo voi stessi e provate a giocarci un po'.
895 <!-- ----------------------------------------------------------------- -->
896 <sect1>Programma Dimostrativo di Impacchettamento
904 delete_event (GtkWidget *widget, gpointer data)
909 /* Costruisco una nuova hbox riempita con bottoni-etichette. Gli
910 * argomenti per le varabili che ci interessano sono passati
911 * in questa funzione. Non mostriamo la scatola, ma mostriamo
912 * tutto quello che c'e' dentro. */
913 GtkWidget *make_box (gint homogeneous, gint spacing,
914 gint expand, gint fill, gint padding)
920 /* costruisco una nuova hbox con i valori appropriati di
921 * homogeneous e spacing */
922 box = gtk_hbox_new (homogeneous, spacing);
924 /* costruisco una serie di bottoni con i valori appropriati */
925 button = gtk_button_new_with_label ("gtk_box_pack");
926 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
927 gtk_widget_show (button);
929 button = gtk_button_new_with_label ("(box,");
930 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
931 gtk_widget_show (button);
933 button = gtk_button_new_with_label ("button,");
934 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
935 gtk_widget_show (button);
937 /* costruisco un bottone con l'etichetta che dipende dal valore di
940 button = gtk_button_new_with_label ("TRUE,");
942 button = gtk_button_new_with_label ("FALSE,");
944 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
945 gtk_widget_show (button);
947 /* Questo e' la stessa cosa della creazione del bottone per "expand"
948 * piu' sopra, ma usa la forma breve. */
949 button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
950 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
951 gtk_widget_show (button);
953 sprintf (padstr, "%d);", padding);
955 button = gtk_button_new_with_label (padstr);
956 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
957 gtk_widget_show (button);
963 main (int argc, char *argv[])
969 GtkWidget *separator;
974 /* La nostra inizializzazione, non dimenticatela! :) */
975 gtk_init (&argc, &argv);
978 fprintf (stderr, "uso: packbox num, dove num è 1, 2, o 3.\n");
979 /* questo fa solo un po' di pulizia in GTK, ed esce con un valore 1. */
983 which = atoi (argv[1]);
985 /* Creiamo la nostra finestra */
986 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
988 /* Ci si dovrebbe sempre ricordare di connettere il segnale di destroy
989 * alla finestra principale. Cio' e' molto importante per avere un funzionamento
990 * corretto dal punto di vista intuitivo */
991 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
992 GTK_SIGNAL_FUNC (delete_event), NULL);
993 gtk_container_border_width (GTK_CONTAINER (window), 10);
995 /* Creiamo una scatola verticale (vbox) in cui impacchettare quelle
996 * orizzontali. Questo ci permette di impilare le scatole orizzontali
997 * piene di bottoni una sull'altra in questa vbox. */
999 box1 = gtk_vbox_new (FALSE, 0);
1001 /* Decide quale esempio si deve mostrare. Corrispondono alle figure precedenti */
1004 /* creare una nuova etichetta. */
1005 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1007 /* allineare l'etichetta al lato sinistro. Discuteremo questa e altre
1008 * funzioni nella sezione dedicata agli attributi degli oggetti grafici. */
1009 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1011 /* Impacchettare l'etichetta nella scatola verticale (vbox box1).
1012 * Ricordare che gli oggetti che vengono aggiunti in una vbox vengono
1013 * impacchettati uno sopra all'altro in ordine. */
1014 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1016 /* mostrare l'etichetta */
1017 gtk_widget_show (label);
1019 /* chiamare la nostra funzione make_box - homogeneous = FALSE,
1020 * spacing = 0, expand = FALSE, fill = FALSE, padding = 0 */
1021 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1022 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1023 gtk_widget_show (box2);
1025 /* chiamare la nostra funzione make_box - homogeneous = FALSE, spacing = 0,
1026 * expand = FALSE, fill = FALSE, padding = 0 */
1027 box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1028 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1029 gtk_widget_show (box2);
1031 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1032 box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1033 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1034 gtk_widget_show (box2);
1036 /* Questo crea un separatore. Li conosceremo meglio in seguito,
1037 * comunque sono piuttosto semplici. */
1038 separator = gtk_hseparator_new ();
1040 /* Impacchetta il separatore nella vbox. Ricordare che stiamo impacchettando
1041 * ognuno di questi oggetti in una vbox, cosicché essi verranno
1042 * impacchettati verticalmente. */
1043 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1044 gtk_widget_show (separator);
1046 /* crea un'altra nuova etichetta e mostrala. */
1047 label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1048 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1049 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1050 gtk_widget_show (label);
1052 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1053 box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1054 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1055 gtk_widget_show (box2);
1057 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1058 box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1059 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1060 gtk_widget_show (box2);
1062 /* ancora un nuovo separatore. */
1063 separator = gtk_hseparator_new ();
1064 /* Gli ultimi 3 argumenti per gtk_box_pack_start sono: expand, fill, padding. */
1065 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1066 gtk_widget_show (separator);
1072 /* creare una nuova etichetta, ricordare che box1 e' la vbox creata
1073 * vicino all'inizio di main() */
1074 label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1075 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1076 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1077 gtk_widget_show (label);
1079 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1080 box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1081 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1082 gtk_widget_show (box2);
1084 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1085 box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1086 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1087 gtk_widget_show (box2);
1089 separator = gtk_hseparator_new ();
1090 /* Gli ultimi tre arcomenti di gtk_box_pack_start sono: expand, fill, padding. */
1091 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1092 gtk_widget_show (separator);
1094 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1095 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1096 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1097 gtk_widget_show (label);
1099 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1100 box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1101 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1102 gtk_widget_show (box2);
1104 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1105 box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1106 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1107 gtk_widget_show (box2);
1109 separator = gtk_hseparator_new ();
1110 /* Gli ultimi tre argomenti di gtk_box_pack_start sono: expand, fill, padding. */
1111 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1112 gtk_widget_show (separator);
1117 /* Questo dimostra la possibilita' di usare use gtk_box_pack_end() per
1118 * giustificare gli oggetti a destra. Per prima cosa creiamo una
1119 * nuova scatola come prima. */
1120 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1121 /* creiamo l'etichetta che sara' aggiunta alla fine. */
1122 label = gtk_label_new ("end");
1123 /* impacchettiamola usando gtk_box_pack_end(), cosa' che viene inserita
1124 * sul lato destro della hbox creata nella chiamata a the make_box(). */
1125 gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1126 /* mostriamo l'etichetta. */
1127 gtk_widget_show (label);
1129 /* impacchettiamo box2 in box1 (the vbox, ricordate? :) */
1130 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1131 gtk_widget_show (box2);
1133 /* un separatore per il fondo */
1134 separator = gtk_hseparator_new ();
1135 /* Questo assegna esplicitamente al separatore l'ampiezza di 400 pixel
1136 * e l'altezza di 5 pixel. Cio' fa si' che la hbox che abbiamo creato sia
1137 * anche essa larga 400 pixel, e che l'etichetta finale sia separata dalle
1138 * altre etichette nella hbox. In caso contrario, tutti gli oggetti nella
1139 * hbox sarebbero impacchettati il piu' vicino possibile. */
1140 gtk_widget_set_usize (separator, 400, 5);
1141 /* impacchetta il separatore nella vbox (box1) creata vicino all'inizio
1143 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1144 gtk_widget_show (separator);
1147 /* Creare un'altra nuova hbox.. ricordate che ne possiamo usare quante ne vogliamo! */
1148 quitbox = gtk_hbox_new (FALSE, 0);
1150 /* Il nostro bottone di uscita. */
1151 button = gtk_button_new_with_label ("Quit");
1154 /* Configuriamo il segnale per distruggere la finestra. Ricordate che
1155 * ciò manderà alla finestra il segnale "destroy", che verrà catturato
1156 * dal nostro gestore di segnali che abbiamo definito in precedenza. */
1157 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1158 GTK_SIGNAL_FUNC (gtk_main_quit),
1159 GTK_OBJECT (window));
1160 /* impacchetta il bottone in quitbox.
1161 * Gli ultimi tre argomenti di gtk_box_pack_start sono: expand, fill, padding. */
1162 gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1163 /* impacchetta quitbox nella vbox (box1) */
1164 gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1166 /* impacchetta la vbox (box1), che ora contiene tutti i nostri oggetti,
1167 * nella finestra principale. */
1168 gtk_container_add (GTK_CONTAINER (window), box1);
1170 /* e mostra tutto quel che rimane */
1171 gtk_widget_show (button);
1172 gtk_widget_show (quitbox);
1174 gtk_widget_show (box1);
1175 /* Mostriamo la finestra alla fine in modo che tutto spunti fuori assieme. */
1176 gtk_widget_show (window);
1178 /* E, naturalmente, la nostra funzione main. */
1181 /* Il controllo ritorna a questo punto quando viene chiamata gtk_main_quit(),
1182 * ma non quando si usa gtk_exit. */
1188 <!-- ----------------------------------------------------------------- -->
1189 <sect1>Impacchettamento con uso di Tabelle
1191 Diamo ora un'occhiata ad un altro modo di impacchettare - le Tabelle.
1192 In certe situazioni, possono risultare estremamente utili.
1194 Usando le tabelle, creiamo una griglia in cui possiamo piazzare gli oggetti.
1195 Gli oggetti possono occupare tanti spazi quanti ne specifichiamo.
1197 Naturalmente, la prima cosa da vedere è la funzione gtk_table_new:
1200 GtkWidget* gtk_table_new (gint rows,
1205 Il primo argomento rappresenta il numero di righe da mettere nella tabella,
1206 mentre il secondo è ovviamente il numero di colonne.
1208 L'argomento homogeneous ha a che fare con il modo in cui le caselle della tabella
1209 sono dimensionate. Se homogeneous ha il valore TRUE, le caselle sono ridimensionate
1210 fino alla dimensione del più grande oggetto contenuto nella tabelle. Se è FALSE, la
1211 dimensione delle caselleè decisa dal più alto oggetto in una certa riga e dal più
1212 largo oggetto in una stessa colonna.
1214 Le righe e le colonne sono disposte a partire da 0 fino a n, dove n è il numero
1215 che era stato specificato nella chiamata a gtk_table_new. Così, se specificate
1216 rows = 2 e columns = 2, lo schema avrà questo aspetto:
1220 0+----------+----------+
1222 1+----------+----------+
1224 2+----------+----------+
1227 Notate che il sistema di coordinate ha origine nel vertice in alto a sinistra. Per
1228 mettere un oggetto in una tabella, usate la seguente funzione:
1231 void gtk_table_attach (GtkTable *table,
1243 In cui il primo argomento (``table'') è la tabella che avete creato e il secondo
1244 (``child'') è l'oggetto che volete piazzare nella tabella.
1246 Gli argomenti ``attach'' (right, left, top, bottom) specificano dove mettere l'oggetto
1247 e quante caselle adoperare. Se volete mettere un bottone nella casella in basso a destra
1248 nella nostra tabella 2x2, e volete che esso riempia SOLO quella casella, dovete porre
1249 left_attach = 1, right_attach = 2, top_attach = 1, bottom_attach = 2.
1251 Se invece volete che un oggetto si prenda tutta la riga più in alto nella nostra tabella
1252 2x2, dovreste usare left_attach = 0, right_attach =2, top_attach = 0,
1255 Gli argomenti ``xoptions'' e ``yoptions'' sono usati per specificare le opzioni di impacchettamento;
1256 di essi si può fare l'OR in modo di ottenere opzioni multiple.
1260 <item>GTK_FILL - Se la parte di tabella in cui si vuole inserire il widget è più
1261 grande dell'oggetto, e se si specifica GTK_FILL, l'oggetto viene espanso fino ad
1262 occupare tutto lo spazio disponibile.
1264 <item>GTK_SHRINK - Se si alloca all'oggetto nella tabella meno spazio del necessario
1265 (di solito succede quando l'utente ridimensiona la finestra), allora normalmente
1266 l'oggetto verrebbe spinto fuori dal fondo della finestra fino a sparire.
1267 Se invece si specifica GTK_SHRINK is specified, gli oggetti si rimpiccioliscono
1268 assieme alla tabella.
1270 <item>GTK_EXPAND - Questo fa sì che la tabella si espanda fino ad occupare tutto lo
1271 spazio che rimane nella finestra.
1274 Il riempimento funziona come nelle scatole, con la creazione di un'area vuota
1275 attorno all'oggetto la cui dimensione viene specificata in pixel.
1277 La funzione gtk_table_attach() ha UN MUCCHIO di opzioni. Quindi, ecco una scorciatoia:
1280 void gtk_table_attach_defaults (GtkTable *table,
1285 gint bottom_attach);
1288 Le xoptions e yoptions vengono posti per difetto a GTK_FILL | GTK_EXPAND, e sia xpadding
1289 che ypadding vengono posti a 0. Il resto degli argomenti sono identici a quelli della funzione
1292 Ci sono poi le funzioni gtk_table_set_row_spacing() and gtk_table_set_col_spacing().
1293 Queste mettono dello spazio fra le righe (o colonne)in corrispondenza di una specifica
1297 void gtk_table_set_row_spacing (GtkTable *table,
1303 void gtk_table_set_col_spacing (GtkTable *table,
1308 Notate che per le colonne lo spazio viene posto alla destra della colonna, mentre
1309 per le righe lo spazio viene posto al di sotto della riga.
1311 Si può poi inserire una spaziatura identica fra tutte le righe e/o colonne usando:
1314 void gtk_table_set_row_spacings (GtkTable *table,
1320 void gtk_table_set_col_spacings (GtkTable *table,
1324 Notate che con queste chiamate, all'ultima riga e all'ultima colonna
1325 non viene assegnata alcuna spaziatura.
1327 <!-- ----------------------------------------------------------------- -->
1328 <sect1>Esempio di Impacchettamento con Tabelle
1330 In questo esempio creiamo una finestra avente tre bottoni disposti
1331 in una tabella 2x2. I primi due bottoni li mettiamo nella riga superiore.
1332 Un terzo bottone, quit, lo mettiamo nella riga inferioe, in modo da
1333 comprendere entrambe le colonne. Ciò significa che dovremmo
1334 avere qualcosa di questo tipo:
1338 <IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10"
1339 ALT="Table Packing Example Image" WIDTH="180" HEIGHT="120">
1343 Ecco il codice sorgente:
1347 #include <gtk/gtk.h>
1349 /* la nostra funzione di ritorno.
1350 * i dati passati a questa funzione vengono stampati su stdout */
1351 void callback (GtkWidget *widget, gpointer data)
1353 g_print ("Hello again - %s was pressed\n", (char *) data);
1356 /* questa funzione fa uscire dal programma */
1357 void delete_event (GtkWidget *widget, gpointer data)
1362 int main (int argc, char *argv[])
1368 gtk_init (&argc, &argv);
1370 /* creiamo una nova finestra */
1371 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1373 /* predisponiamo il titolo per la finestra */
1374 gtk_window_set_title (GTK_WINDOW (window), "Table");
1376 /* creiamo un gestore per delete_event che esca immediatamente
1378 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1379 GTK_SIGNAL_FUNC (delete_event), NULL);
1381 /* regoliamo la larghezza del bordo della finestra. */
1382 gtk_container_border_width (GTK_CONTAINER (window), 20);
1384 /* creiamo una tabella 2x2 */
1385 table = gtk_table_new (2, 2, TRUE);
1387 /* mettiamo la tabella nella finesta principale */
1388 gtk_container_add (GTK_CONTAINER (window), table);
1390 /*creiamo il primo bottone */
1391 button = gtk_button_new_with_label ("button 1");
1392 /* quando viene premuto il bottone, chiamiamo la funzione di ritorno
1393 * con un puntatore a "button 1"come argomento */
1394 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1395 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
1398 /* inseriamo il bottone 1 nel quadrante in alto a sinistra della tabella */
1399 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 1, 0, 1);
1401 gtk_widget_show (button);
1403 /* creiamo il secondo bottone */
1405 button = gtk_button_new_with_label ("button 2");
1407 /* quando si preme il bottone, chiamamo la funzione di ritorno
1408 * con un puntatore a "button 2"come argomento */
1409 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1410 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
1411 /* inseriamo il secondo bottone nel quadrate in alto a destra della tbella */
1412 gtk_table_attach_defaults (GTK_TABLE(table), button, 1, 2, 0, 1);
1414 gtk_widget_show (button);
1416 /* creiamo il botone "Quit" */
1417 button = gtk_button_new_with_label ("Quit");
1419 /* quando viene premuto questo bottone, chiamiamo la funzione "delete_event"
1420 * e si esce dal programma */
1421 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1422 GTK_SIGNAL_FUNC (delete_event), NULL);
1424 /* inseriamo il pulsante quit nelle due casele in basso della tabella */
1425 gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 1, 2);
1427 gtk_widget_show (button);
1429 gtk_widget_show (table);
1430 gtk_widget_show (window);
1438 <!-- ***************************************************************** -->
1439 <sect>Panoramica sui Widget
1440 <!-- ***************************************************************** -->
1443 La procedura generale di creazione di un widget in GTK prevede i seguenti passi:
1445 <item> gtk_*_new - una delle varie funzioni che servono per greare un nuovo widget.
1446 In questa sezione le vedremo tutte in dettaglio.
1448 <item> Connettere tutti i segnali che si vogliono usare alle funzione gestione appfropriate.
1450 <item> Assegnare gli attributi all'oggetto.
1452 <item> Impacchettare l'oggetto in un contenitore usando la chiamate appropriata,
1453 per esempio gtk_container_add() o gtk_box_pack_start().
1455 <item> Mostrare l'oggetto con gtk_widget_show().
1458 gtk_widget_show() fa sì che GTK sappia che abbiamo terminato di assegnare gli
1459 attributi dell'oggetto grafico, e che è pronto per essere visualizzato.
1460 Si può anche usare la funzione gtk_widget_hide per farlo sparire di nuovo.
1461 L'ordine in cui mostrate gli oggetti grafici non è importante, ma io suggerisco
1462 di mostrare per ultima la finestra, in modo che questa spunti fuori già completa,
1463 invece di vedere i singoli oggetti che arrivano sullo schermo a mano a mano che si
1464 formano. I figli di un oggetto grafico (anche una finestra è un oggetto grafico) non
1465 vengono infatti mostrati finché la finestra stessa non viene mostrata usando la
1466 funzione gtk_widget_show().
1468 <!-- ----------------------------------------------------------------- -->
1471 Noterete andando avanti che GTK usa un sistema di casting di tipo. Questa operazione
1472 viene sempre effettuata usando delle macro che allo stesso tempo controllano la
1473 possibilità di effettuare il cast sull'elemento dato e lo effettuano realmente.
1474 Alcune macro che avrete modo di incontrare sono:
1477 <item> GTK_WIDGET(widget)
1478 <item> GTK_OBJECT(object)
1479 <item> GTK_SIGNAL_FUNC(function)
1480 <item> GTK_CONTAINER(container)
1481 <item> GTK_WINDOW(window)
1485 Tutte queste funzioni sono usate per fare il cast di argomenti di funzione. Le vedrete
1486 negli esempi, e capirete se è il caso di usarle semplicemente guardando alle
1487 dichiarazioni delle funzioni.
1489 Come potrete vedere più sotto nella gerarchia delle classi, tutti i GtkWidgets
1490 sono derivati dalla classe base GtkObject. Ciò significa che potete usare un
1491 widget in ogni posto in cui una funzione richiede un oggetto - semplicemente
1492 usate la macro GTK_OBJECT().
1497 gtk_signal_connect(GTK_OBJECT(button), "clicked",
1498 GTK_SIGNAL_FUNC(callback_function), callback_data);
1501 Questo fa il cast del bottone in un oggetto e fornisce alla chiamata di ritorno
1502 un cast al puntatore a funzione.
1504 Molti oggetti grafici sono anche contenitori. Se guardate alla gerarchia delle
1505 classi più sotto, vedrete che molti oggetti grafici sono derivati dalla classe
1506 GtkContainer. Ognuna di queste classi può essere usata, con la macro GTK_CONTAINER,
1507 come argomento per funzioni che richiedono un contenitore.
1509 Sfortunatamente, in questo tutorial non si parlerà in modo estensivo di queste macro,
1510 ma raccomando di dare un'occhiata ai file header di GTK. Può essere una cosa molto
1511 educativa. Infatti, non è difficile imparare come funziona un oggetto solo guardando
1512 le dichiarazioni delle funzioni.
1514 <!-- ----------------------------------------------------------------- -->
1515 <sect1>Gerarchia degli Oggetti Grafici
1517 Ecco, per vostro riferimento, la gerarchia delle classi usata per implementare gli
1531 | | | `GtkAspectFrame
1536 | | | | `GtkCheckMenuItem
1537 | | | | `GtkRadioMenuItem
1541 | | +GtkColorSelectionDialog
1543 | | | `GtkInputDialog
1544 | | `GtkFileSelection
1547 | | | +GtkHButtonBox
1548 | | | `GtkVButtonBox
1553 | | +GtkColorSelection
1557 | | `GtkToggleButton
1570 | +GtkScrolledWindow
1603 <!-- ----------------------------------------------------------------- -->
1604 <sect1>Oggetti senza Finestre
1606 Gli oggetti seguenti non hanno una finestra associata. Se volete catturare
1607 degli eventi, dovrete usare l'oggetto GtkEventBox. Vedete anche la sezione su
1608 <ref id="sec_The_EventBox_Widget" name="Il Widget EventBox">
1630 Proseguiremo la nostra esplorazione di GTK esaminando uno alla volta tutti
1631 gli oggetti, creando qualche semplice funzione per mostrarli. Un'altra
1632 buona sorgente è il programma testgtk.c che viene fornito con GTK. Potete
1633 trovarlo in gtk/testgtk.c.
1635 <!-- ***************************************************************** -->
1636 <sect>Il Widget Bottone (Button)
1637 <!-- ***************************************************************** -->
1639 <!-- ----------------------------------------------------------------- -->
1640 <sect1>Bottoni Normali
1642 Ormai abbiamo visto tutto quello che c'è da vedere riguardo all'oggetto
1643 ``bottone''. E' piuttosto semplice, ma ci sono due modi per crare un bottone.
1644 Potete usare gtk_button_new_with_label() per creare un bottone con una
1645 etichetta, o usare gtk_button_new() per creare un bottone vuoto. In tal caso è poi
1646 vostro compito impacchettare un'etichetta o una pixmap sul bottone creato.
1647 Per fare ciò, create una nuova scatola, e poi impacchettateci i vostri
1648 oggetti usando la solita gtk_box_pack_start, e infine usate la funzione
1649 gtk_container_add per impacchettare la scatola nel bottone.
1651 Ecco un esempio di utilizzo di gtk_button_new per creare un bottone con
1652 un'immagine ed un'etichetta su di sè. Ho separato il codice usato per
1653 creare la scatola in modo che lo possiate usare nei vostri programmi.
1657 #include <gtk/gtk.h>
1660 /* crea una nuova hbox contenente un'immagine ed un'etichetta
1661 * e ritorna la scatola creata. */
1663 GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
1667 GtkWidget *pixmapwid;
1672 /* creare una scatola per una xpm ed una etichetta */
1673 box1 = gtk_hbox_new (FALSE, 0);
1674 gtk_container_border_width (GTK_CONTAINER (box1), 2);
1676 /* ottengo lo stile del bottone. Penso che sia per avere il colore
1677 * dello sfondo. Se qualcuno sa il vero motivo, è pregato di dirmelo. */
1678 style = gtk_widget_get_style(parent);
1680 /* e ora via con le faccende dell'xpm stuff. Carichiamo l'xpm*/
1681 pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
1682 &style->bg[GTK_STATE_NORMAL],
1684 pixmapwid = gtk_pixmap_new (pixmap, mask);
1686 /* creiamo l'etichetta per il bottone */
1687 label = gtk_label_new (label_text);
1689 /* impacchettiamo la pixmap e l'etichetta nella scatola */
1690 gtk_box_pack_start (GTK_BOX (box1),
1691 pixmapwid, FALSE, FALSE, 3);
1693 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
1695 gtk_widget_show(pixmapwid);
1696 gtk_widget_show(label);
1701 /* la nostra solita funzione di callback */
1702 void callback (GtkWidget *widget, gpointer data)
1704 g_print ("Hello again - %s was pressed\n", (char *) data);
1708 int main (int argc, char *argv[])
1710 /* GtkWidget è il tipo per contenere gli oggetti */
1715 gtk_init (&argc, &argv);
1717 /* creiamo una nuova finestra */
1718 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1720 gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
1722 /* E' una buona idea fare questo per tutte le finestre. */
1723 gtk_signal_connect (GTK_OBJECT (window), "destroy",
1724 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1726 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1727 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1729 /* assegnamo lo spessore del bordo della finestra */
1730 gtk_container_border_width (GTK_CONTAINER (window), 10);
1731 gtk_widget_realize(window);
1733 /* creiamo un nuovo bottone */
1734 button = gtk_button_new ();
1736 /* Ormai dovreste esservi abituati a vedere la maggior parte di
1737 * queste funzioni */
1738 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1739 GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
1741 /* questa chiama la nostra funzione di creazione di scatole */
1742 box1 = xpm_label_box(window, "info.xpm", "cool button");
1744 /* impacchetta e mostra tutti i nostri oggetti */
1745 gtk_widget_show(box1);
1747 gtk_container_add (GTK_CONTAINER (button), box1);
1749 gtk_widget_show(button);
1751 gtk_container_add (GTK_CONTAINER (window), button);
1753 gtk_widget_show (window);
1755 /* mettiti in gtk_main e aspetta che cominci il divertimento! */
1761 La funzione xpm_label_box può essere usata per impacchettare delle xpm
1762 e delle etichette su qualsiasi oggetto che può essere un contenitore.
1764 <!-- ----------------------------------------------------------------- -->
1765 <sect1> Bottoni a Commutazione (Toggle Buttons)
1767 I bottoni a commutazione sono molto simili ai bottoni normali, tranne che per il
1768 fatto che essi si trovano sempre in uno di due stati, che si alternano ad ogni
1769 click. Possono trovarsi nello stato ``premuto'', e quando li si ripreme, tornano
1770 ad essere sollevati. Ri-clickandoli, torneranno giù.
1772 I bottoni a commutazione sono la base per i bottoni di controllo (check button) e
1773 per i radio-bottoni, e quindi molte delle chiamate disponibili per i bottoni
1774 a commutazione vengono ereditati dai radio-bottoni e dai bottoni di controllo.
1775 Ma vedremo questi aspetti nel momento in cui li incontreremo.
1777 Creare un nuovo bottone a commutazione:
1780 GtkWidget* gtk_toggle_button_new (void);
1782 GtkWidget* gtk_toggle_button_new_with_label (gchar *label);
1785 Come potete immaginare, queste funzioni lavorano in modo identico che per
1786 i bottoni normali. La prima crea un bottone a commutazione vuoto e la seconda un
1787 bottone con un'etichetta.
1789 Per ottenere lo stato dei widget a commutazione, compresi i radio-bottoni e i
1790 bottoni di controllo, si può usare una macro come mostrato nell'esempio
1791 più sotto. In questo modo lo stato dell'oggetto commutabile viene valutato in
1792 una funzione di ritorno. Il segnale emesso dai bottoni a commutazione
1793 (toggle button, il radio button o il check button) che ci interessa è il segnale
1794 ``toggled''. Per controllare lo stato di questi bottoni, create un gestore di
1795 segnali che catturi il ``toggled'', e usate la macro per determinare
1796 il suo stato. La funzione di callback avrà un aspetto più o meno così:
1799 void toggle_button_callback (GtkWidget *widget, gpointer data)
1801 if (GTK_TOGGLE_BUTTON (widget)->active)
1803 /* Se il programma si è arrivato a questo punto, il bottone
1804 * a commutazione è premuto */
1808 /* il bottone è sollevato */
1818 guint gtk_toggle_button_get_type (void);
1821 No idea... they all have this, but I dunno what it is :)
1825 void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
1826 gint draw_indicator);
1833 void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
1837 La chiamata qui sopra può essere usata per fare l'assegnazione dello stato
1838 del bottone a commutazione e dei suoi figli, il radio-bottone e il bottone di
1839 controllo. Passando come primo argomento a questa funzione il vostro bottone e
1840 come secondo argomento il valore TRUE o FALSE, si può specificare se il
1841 bottone deve essere sollevato (rilasciato) o abbassato (premuto). Il valore
1842 di difetto è sollevato, cioè FALSE.
1844 Notate che quando usate la funzione gtk_toggle_button_set_state(), e lo
1845 stato viene cambiato, si ha il risultato che il bottone emette il segnale
1849 void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
1852 Questa funzione semplicemente commuta il bottone, ed emette il segnale ``toggled''.
1854 <!-- ----------------------------------------------------------------- -->
1855 <sect1> Bottoni di Controllo (Check Buttons)
1857 I bottoni di controllo ereditano molte proprietà e funzioni dal bottone a commutazione,
1858 ma hanno un aspetto un po' diverso. Invece di essere bottoni contenenti del testo,
1859 si tratta di quadratini con del testo alla propria destra. Questi bottoni sono
1860 spesso usati nelle applicazioni per commutare fra lo stato attivato e disattivato delle
1863 Le due funzioni di creazione sono analoghe a quelle del bottone normale..
1866 GtkWidget* gtk_check_button_new (void);
1868 GtkWidget* gtk_check_button_new_with_label (gchar *label);
1871 La funzione new_with_label crea un bottone di controllo con una etichetta
1874 Per controllare lo stato del check button si opera in modo identico al bottone
1877 <!-- ----------------------------------------------------------------- -->
1878 <sect1> Radio-Bottoni (Radio Buttons)
1880 I radio-bottoni sono simili ai bottoni di controllo, tranne che per il
1881 fatto che sono sempre raggruppati in modo che solo uno alla volta di essi
1882 può essere selezionato (premuto). Tornano utili quando nella propria applicazione
1883 si ha bisogno di selezionare una opzione da una breve lista.
1885 La creazione di un nuovo radio-bottone si fa con una di queste chiamate:
1888 GtkWidget* gtk_radio_button_new (GSList *group);
1890 GtkWidget* gtk_radio_button_new_with_label (GSList *group,
1894 Avrete notato l'argomento in più che c'è in queste chiamate. Queste hanno
1895 infatti bisogno dela specificazione di un ``gruppo'' per svolgere il loro compito.
1896 Per il primo bottone di un gruppo si deve passare come primo argomento il valore
1897 NULL. Dopodiché potete creare un gruppo usando la funzione:
1900 GSList* gtk_radio_button_group (GtkRadioButton *radio_button);
1904 La cosa importante da ricordare è che gtk_radio_button_group va chiamata ogni volta che si aggiunge un nuovo bottone al gruppo, con il preceente bottone passato come argomento. Il risultato viene poi passato nella chiamata a gtk_radio_button_new o a gtk_radio_button_new_with_label. Ciò permette di creare una catena di bottoni. L'esempio più sotto dovrebbe chiarire questo punto.
1906 E' poi una buona idea stabiire quale dev'essere il bottone premuto per difetto, usando:
1909 void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
1913 Questa funzione è descritta nella sezione sui bottoni a commutazione, e funziona
1914 nello stesso identico modo.
1917 Nel seguente esempio creiamo un gruppo di tre radio-bottoni.
1920 /* radiobuttons.c */
1922 #include <gtk/gtk.h>
1925 void close_application( GtkWidget *widget, gpointer data ) {
1929 main(int argc,char *argv[])
1931 static GtkWidget *window = NULL;
1935 GtkWidget *separator;
1938 gtk_init(&argc,&argv);
1939 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1941 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1942 GTK_SIGNAL_FUNC(close_application),
1945 gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
1946 gtk_container_border_width (GTK_CONTAINER (window), 0);
1948 box1 = gtk_vbox_new (FALSE, 0);
1949 gtk_container_add (GTK_CONTAINER (window), box1);
1950 gtk_widget_show (box1);
1952 box2 = gtk_vbox_new (FALSE, 10);
1953 gtk_container_border_width (GTK_CONTAINER (box2), 10);
1954 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
1955 gtk_widget_show (box2);
1957 button = gtk_radio_button_new_with_label (NULL, "button1");
1958 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1959 gtk_widget_show (button);
1961 group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
1962 button = gtk_radio_button_new_with_label(group, "button2");
1963 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
1964 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1965 gtk_widget_show (button);
1967 group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
1968 button = gtk_radio_button_new_with_label(group, "button3");
1969 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1970 gtk_widget_show (button);
1972 separator = gtk_hseparator_new ();
1973 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
1974 gtk_widget_show (separator);
1976 box2 = gtk_vbox_new (FALSE, 10);
1977 gtk_container_border_width (GTK_CONTAINER (box2), 10);
1978 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
1979 gtk_widget_show (box2);
1981 button = gtk_button_new_with_label ("close");
1982 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1983 GTK_SIGNAL_FUNC(close_application),
1984 GTK_OBJECT (window));
1985 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1986 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1987 gtk_widget_grab_default (button);
1988 gtk_widget_show (button);
1989 gtk_widget_show (window);
1996 La cosa può essere accorciata un po' usando la seguente sintassi,
1997 che elimina la necessità di una variabile per contenere la lista di bottoni:
2000 button2 = gtk_radio_button_new_with_label(
2001 gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
2006 <!-- ***************************************************************** -->
2007 <sect> Alcuni Widget
2008 <!-- ***************************************************************** -->
2010 <!-- ----------------------------------------------------------------- -->
2011 <sect1> L'Etichetta (Label)
2013 Le etichette sono molto usate in GTK, e sono relativamente semplici. Le
2014 etichette non emettono segnali, dal momento che non hanno una finestra
2015 X a loro assegnata. Se avete la necessità di avere dei segnali o di fare
2016 delle operazioni di clipping, potete usare il widget EventBox.
2018 Per creare una nuova etichetta, si usa:
2021 GtkWidget* gtk_label_new (char *str);
2024 In cui l'unico argomento è la stringa che si vuole sia mostrata.
2026 Per cambiare il testo dell'etichetta dopo che è stata creata, si usa
2030 void gtk_label_set (GtkLabel *label,
2034 in cui il primo argomento è l'etichetta creata in precedenza (di cui si
2035 fa il cast usando la macro GTK_LABEL()), mentre il secondo è la nuova
2038 Nel caso, lo spazio necessario per la nuova stringa verrà regolato automaticamente.
2040 Per ottenere la stringa corrente si usa:
2043 void gtk_label_get (GtkLabel *label,
2047 in cui il primo argomento è l'etichetta che avete creato, e il secondo
2048 è il valore di ritorno per la stringa.
2050 <!-- ----------------------------------------------------------------- -->
2051 <sect1>Il Widget Suggerimenti (Tooltips)
2053 I suggerimenti sono piccole stringhe di testo che spuntano quando lasciate il
2054 puntatore su un bottone o un altro widget per qualche secondo. Sono piuttosto
2055 semplici da usare, per cui ne darò la spiegazione senza corredarla di esempi.
2056 Se volede vedere un po' di codice, date un'occhiata al programma testgtk.c
2057 distribuito con GTK.
2059 Con alcuni widget (per esempio con l'etichetta) i suggerimenti non funzionano.
2061 La prima chiamata che si usa per creare un nuovo tooltip è la seguente.
2062 In una data funzione, è necessario chiamarla una sola volta: il <tt/GtkTooltip/
2063 che viene restituito da questa funzione può essere usato per creare suggerimenti
2067 GtkTooltips *gtk_tooltips_new (void);
2070 Una volta creato un nuovo suggerimento e il widget su cui lo volete usare,
2071 basta usare la seguente chiamata per fare l'assegnazione:
2074 void gtk_tooltips_set_tip (GtkTooltips *tooltips,
2076 const gchar *tip_text,
2077 const gchar *tip_private);
2080 Il primo argomento è il suggerimento che era già stato creato, che è seguito
2081 dal widget da cui volete che spunti il suggerimento e dal testo che volete
2082 venga mostrato. L'ultimo argomento può essere posto a NULL.
2084 Ecco un piccolo esempio:
2087 GtkTooltips *tooltips;
2090 tooltips = gtk_tooltips_new ();
2091 button = gtk_button_new_with_label ("button 1");
2093 gtk_tooltips_set_tips (tooltips, button, "This is button 1", NULL);
2095 Ci sono anche altre funzioni che si usano con i suggerimenti. Eccone una lista
2096 con una breve descrizione di quello che fanno.
2099 void gtk_tooltips_destroy (GtkTooltips *tooltips);
2102 Distrugge un suggerimento esistente.
2105 void gtk_tooltips_enable (GtkTooltips *tooltips);
2108 Abilita un gruppo di suggerimenti disbilitato.
2111 void gtk_tooltips_disable (GtkTooltips *tooltips);
2114 Disabilita un gruppo di suggerimenti abilitato.
2117 void gtk_tooltips_set_delay (GtkTooltips *tooltips,
2121 Stabilisce quanti millisecondi si deve mantenere il puntatore sopra al
2122 widget prima che venga mostrato il suggerimento. Il valore di difetto
2123 è di 1000 millisecondi.
2126 void gtk_tooltips_set_tips (GtkTooltips *tooltips,
2131 Cambia il testo di un suggerimento già esistente.
2134 void gtk_tooltips_set_colors (GtkTooltips *tooltips,
2135 GdkColor *background,
2136 GdkColor *foreground);
2139 Assegna i colori di primo piano e di sfondo dei suggerimenti. (Non ho idea
2140 di come si specifichino i colori).
2142 E questo è tutto riguardo alle funzioni relative ai suggerimenti. Più
2143 di quanto avreste mai voluto sapere :)
2146 <!-- ----------------------------------------------------------------- -->
2147 <sect1> La Barra di Avanzamento (Progress Bar)
2149 Le barre di avanzamento sono usate per mostrare lo stato di una operazione. Come potete
2150 vedere nel frammento di codice qui sotto, sono piuttosto semplici da usare.
2151 Ma prima vediamo come cominciare con la chiamata per creare una nuova progress
2155 GtkWidget *gtk_progress_bar_new (void);
2158 Ora che la barra di avanzamento è stata creata, possiamo usarla..
2161 void gtk_progress_bar_update (GtkProgressBar *pbar, gfloat percentage);
2164 Il primo argomento è la barra di avanzamento su cui volete lavorare, e il secondo
2165 è la quantità 'completato', cioè la quantità di riempimento della progress
2166 bar fra 0 e 100% (un numero reale fra 0 e 1).
2168 Le barre di avanzamento sono usate di solito con funzioni di timeout o altre di
2169 questo tipo (vedi alla sezione <ref id="sec_timeouts" name="Timeouts,
2170 I/O and Idle Functions">) per dare l'illusione del multitasking. Tutte
2171 usano la funzione gtk_progress_bar_update nello stesso modo.
2173 Ecco un esempio di barra di avanzamento, in cui l'aggiornamento avviene usando
2174 dei timeout. Questo codice vi mostra anche come riinizializzare le
2175 barre di avanzamento.
2180 #include <gtk/gtk.h>
2182 static int ptimer = 0;
2185 /* Questa funzione incrementa e aggiorna la barra di avanzamento, e la rimette
2186 a zero se pstat è FALSE */
2187 gint progress (gpointer data)
2191 /* ottiene il valore corrente della status bar */
2192 pvalue = GTK_PROGRESS_BAR (data)->percentage;
2194 if ((pvalue >= 1.0) || (pstat == FALSE)) {
2200 gtk_progress_bar_update (GTK_PROGRESS_BAR (data), pvalue);
2205 /* Questa funzione segnala la riinizializzazione della
2206 barra di avanzamento */
2207 void progress_r (void)
2212 void destroy (GtkWidget *widget, gpointer data)
2217 int main (int argc, char *argv[])
2225 gtk_init (&argc, &argv);
2227 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2229 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2230 GTK_SIGNAL_FUNC (destroy), NULL);
2232 gtk_container_border_width (GTK_CONTAINER (window), 10);
2234 table = gtk_table_new(3,2,TRUE);
2235 gtk_container_add (GTK_CONTAINER (window), table);
2237 label = gtk_label_new ("Progress Bar Example");
2238 gtk_table_attach_defaults(GTK_TABLE(table), label, 0,2,0,1);
2239 gtk_widget_show(label);
2240 /* Crea una nuova barra di avanzamento, impacchettala nella tabella
2242 pbar = gtk_progress_bar_new ();
2243 gtk_table_attach_defaults(GTK_TABLE(table), pbar, 0,2,1,2);
2244 gtk_widget_show (pbar);
2246 /* Attiva un timeout che gestisca l'aggiornamento automatico della barra */
2247 ptimer = gtk_timeout_add (100, progress, pbar);
2249 /* Questo bottone segnala alla barra che deve essere resettata */
2250 button = gtk_button_new_with_label ("Reset");
2251 gtk_signal_connect (GTK_OBJECT (button), "clicked",
2252 GTK_SIGNAL_FUNC (progress_r), NULL);
2253 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,2,3);
2254 gtk_widget_show(button);
2256 button = gtk_button_new_with_label ("Cancel");
2257 gtk_signal_connect (GTK_OBJECT (button), "clicked",
2258 GTK_SIGNAL_FUNC (destroy), NULL);
2260 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,2,3);
2261 gtk_widget_show (button);
2263 gtk_widget_show(table);
2264 gtk_widget_show(window);
2272 In questo programmino ci sono quattro aree che riguardano il modo di
2273 uso generale delle Barre di Avanzamento; le vediamo ora nell'ordine.
2276 pbar = gtk_progress_bar_new ();
2279 Questo codice crea una nuova barra ciamata pbar.
2282 ptimer = gtk_timeout_add (100, progress, pbar);
2285 Questo codice usa dei timeout per abilitare degli intervalli di tempo uguali.
2286 Per usare le barre di avanzamento non è però necessario servirsi di timeout.
2289 pvalue = GTK_PROGRESS_BAR (data)->percentage;
2292 Qui si assegna a pvalue il valore corrente della percentuale di avanzamento.
2295 gtk_progress_bar_update (GTK_PROGRESS_BAR (data), pvalue);
2298 Infine, questo codice aggiorna la barra di avanzamento con il valore di pvalue.
2300 Questo è tutto quanto c'è da sapere sulle barre di avanzamento, divertitevi.
2302 <!-- ----------------------------------------------------------------- -->
2306 Il widget ``Dialogo'' è molto semplice: si tratta in realtà di una finestra
2307 con alcuni elementi pre-impacchettati. La struttura di un dialogo è la
2316 GtkWidget *action_area;
2320 Come potete vedere, crea semplicemente una finestra vi inserisce una vbox
2321 in cima, poi un separatore e infine una hbox come ``area di azione''.
2323 Un Dialogo può essere utilizzato per messaggi per l'utente e
2324 altri scopi simili. E' un widget molto essenziale, che ha una sola funzione,
2328 GtkWidget* gtk_dialog_new (void);
2331 Per cui, per creare una nuova finestra di dialogo, uate:
2335 window = gtk_dialog_new ();
2338 Questa funzione crea una finestra di dialogo, dopodiché sta a voi
2339 utilizzarla. Potete mettere un bottone nella action_area facendo
2344 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
2346 gtk_widget_show (button);
2349 Potreste anche aggiungere, ad esempio, un'etichetta all'area della vbox,
2350 con qualcosa di questo genere:
2353 label = gtk_label_new ("Dialogs are groovy");
2354 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), label, TRUE,
2356 gtk_widget_show (label);
2359 Per provare a usare una finestra di dialogo, potreste provare a mettere
2360 due bottoni nella action_area, per esempio un bottone ``Cancella'' ed un
2361 bottone ``OK'' e un'etichetta nella vbox che chieda qualcosa all'utente o
2362 segnali un errore. Poi potreste collegare un diverso segnale a ciascun
2363 bottone ed eseguire l'operazione che l'utente che viene scelta dall'utente.
2365 <!-- ----------------------------------------------------------------- -->
2369 Le Pixmap sono strutture dati che contengono immagini. Queste immagini
2370 possono poi essere utilizzate in varie occasioni, per esempio come
2371 icone sul desktop X-Window o come cusori. Una bitmap è una pixmap a due
2374 Per usare una pixmap in GTK, dobbiamo in primo luogo creare una struttura
2375 GdkPixmap utilizzando le routine disponibili nello strato GDK. Una Pixmap
2376 può essere creata a partire da dati presenti in memoria o letti da un file.
2377 Vedremo ora una ad una le chiamate utilizzate per creare una pixmap.
2380 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
2386 Si usa questa routine per creare una pixmap ad un solo piano (2 colori) da
2387 dati disponibili in memoria. Ogni bit nei dati indica lo stato acceso o
2388 spento di un pixel. L'altezza (height) e la larghezza (width) sono espresse
2389 in pixel. GdkWindow è un puntatore alla finestra corrente, dal momento che
2390 le risorse di una pixmap hanno significato solo nel contesto dello schermo
2391 in cui deve essere mostrata.
2394 GdkPixmap* gdk_pixmap_create_from_data( GdkWindow *window,
2403 Questa è usata per creare una pixmap con la profondità data (depth, ossia
2404 numero di colori) usando i dati specificati. fg e bg indicano i colori da
2405 usare per il primo piano e per lo sfondo.
2408 GdkPixmap* gdk_pixmap_create_from_xpm( GdkWindow *window,
2410 GdkColor *transparent_color,
2411 const gchar *filename );
2414 Il formato XPM è una rappresentazione di pixmap leggibile per X Window. E' una
2415 rappresentazione molto diffusa, e sono disponibili parecchi programmi per creare
2416 immagini in questo formato. Il file specificato da ``filename'' deve contenere
2417 un'immagine in questo formato, che viene caricato nella struttura pixmap.
2418 La maschera (mask) specifica quali pixel della pixmap devono essere opachi.
2419 Tutti gli altri pixel sono colorati usando il colore specificato da
2420 transparent_color. Più sotto mostreremo un esempio di uso di questa funzione.
2423 GdkPixmap* gdk_pixmap_create_from_xpm_d (GdkWindow *window,
2425 GdkColor *transparent_color,
2429 Si possono incorporare piccole immagini all'interno di un programma sotto
2430 forma di dati in formato XPM. In questo modo, invece di leggerli da un file,
2431 si possono usare questi dati per creare una pixmap. Un esempio di questo tipo
2436 static const char * xpm_data[] = {
2439 ". c #000000000000",
2440 "X c #FFFFFFFFFFFF",
2460 void gdk_pixmap_destroy( GdkPixmap *pixmap );
2463 Quando abbiamo finito di usare una pixmap e pensiamo di non doverla riutilizzare
2464 presto, è una buona idea liberare queste risorse usando la funzione
2465 dk_pixmap_destroy. Le pixmap devono essere considerate una risorsa preziosa.
2467 Quando abbiamo creato una pixmap, possiamo mostrarla come un widget GTK.
2468 E' necessario creare un widget pixmap che contenga una pixmap GDK. Questa
2469 operazione viene compiuta usando
2472 GtkWidget* gtk_pixmap_new( GdkPixmap *pixmap,
2476 Le altre chiamate per i widget pixmap sono
2479 guint gtk_pixmap_get_type( void );
2480 void gtk_pixmap_set( GtkPixmap *pixmap,
2483 void gtk_pixmap_get( GtkPixmap *pixmap,
2488 La funzione gtk_pixmap_set viene usata per cambiare la pixmap che viene
2489 gestita correntemente dal widget.
2490 gtk_pixmap_set is used to change the pixmap that the widget is currently
2491 managing. ``val'' è la pixmap che è stata creata usando il GDK.
2492 Segue un esempio di uso di una pixmap in un bottone.
2496 #include <gtk/gtk.h>
2499 /* dat XPM dell'icona Apri File */
2500 static const char * xpm_data[] = {
2503 ". c #000000000000",
2504 "X c #FFFFFFFFFFFF",
2523 /* quando invocata (con il segnale delete_event), termina l'applicazione. */
2524 void close_application( GtkWidget *widget, gpointer data ) {
2528 /* invocata se il bottone è clickato. Stampa semplicemente un messaggio */
2529 void button_clicked( GtkWidget *widget, gpointer data ) {
2530 printf( "button clicked\n" );
2533 int main( int argc, char *argv[] )
2535 /* i widget sono memorizzati nel tipo GtkWidget */
2536 GtkWidget *window, *pixmapwid, *button;
2541 /* crea la finestra principale, e collega il segnale delete_event
2542 alla terminazione dell'applicazione */
2543 gtk_init( &argc, &argv );
2544 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
2545 gtk_signal_connect( GTK_OBJECT (window), "delete_event",
2546 GTK_SIGNAL_FUNC (close_application), NULL );
2547 gtk_container_border_width( GTK_CONTAINER (window), 10 );
2548 gtk_widget_show( window );
2550 /* la pixmap proviene da gdk */
2551 style = gtk_widget_get_style( window );
2552 pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
2553 &style->bg[GTK_STATE_NORMAL],
2554 (gchar **)xpm_data );
2556 /* un widget pixmap per contenere la pixmap */
2557 pixmapwid = gtk_pixmap_new( pixmap, mask );
2558 gtk_widget_show( pixmapwid );
2560 /* un bottone per contenere il widget pixmap */
2561 button = gtk_button_new();
2562 gtk_container_add( GTK_CONTAINER(button), pixmapwid );
2563 gtk_container_add( GTK_CONTAINER(window), button );
2564 gtk_widget_show( button );
2566 gtk_signal_connect( GTK_OBJECT(button), "clicked",
2567 GTK_SIGNAL_FUNC(button_clicked), NULL );
2569 /* mostra la finestra */
2577 Per caricare una pixmap da un file XPM chiamato icon0.xpm che si trova
2578 nella direttorio corrente, avremmo creato la pixmap in questo modo:
2581 /* carica una pixmap da un file */
2582 pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
2583 &style->bg[GTK_STATE_NORMAL],
2585 pixmapwid = gtk_pixmap_new( pixmap, mask );
2586 gtk_widget_show( pixmapwid );
2587 gtk_container_add( GTK_CONTAINER(window), pixmapwid );
2593 Uno degli svantaggi di usare le pixmap è costituito dal fatto che l'oggetto
2594 mostrato è sempre rettangolare, a prescindere dall'immagine. Ci piacerebbe
2595 invece poter crare dei desktop e delle immagini con forme più naturali. Per
2596 esempio, per l'interfaccia di un gioco, potremmo volere avere dei pulsanti
2597 circolari. Il modo per ottenere questo effetto è di usare delle finestre
2600 Una finestra sagomata è semplicemente una pixmap in cui i pixel dello
2601 sfondo sono trasparenti. In questo modo, se l'immagine di sfondo è
2602 multicolore, possiamo evitare di sovrascriverla con un bordo rettangolare
2603 attorno all'icona. Il prossimo esempio mostra una carriola sul desktop.
2607 #include <gtk/gtk.h>
2610 static char * WheelbarrowFull_xpm[] = {
2613 ". c #DF7DCF3CC71B",
2614 "X c #965875D669A6",
2615 "o c #71C671C671C6",
2616 "O c #A699A289A699",
2617 "+ c #965892489658",
2618 "@ c #8E38410330C2",
2619 "# c #D75C7DF769A6",
2620 "$ c #F7DECF3CC71B",
2621 "% c #96588A288E38",
2622 "& c #A69992489E79",
2623 "* c #8E3886178E38",
2624 "= c #104008200820",
2625 "- c #596510401040",
2626 "; c #C71B30C230C2",
2627 ": c #C71B9A699658",
2628 "> c #618561856185",
2629 ", c #20811C712081",
2630 "< c #104000000000",
2631 "1 c #861720812081",
2632 "2 c #DF7D4D344103",
2633 "3 c #79E769A671C6",
2634 "4 c #861782078617",
2635 "5 c #41033CF34103",
2636 "6 c #000000000000",
2637 "7 c #49241C711040",
2638 "8 c #492445144924",
2639 "9 c #082008200820",
2640 "0 c #69A618611861",
2641 "q c #B6DA71C65144",
2642 "w c #410330C238E3",
2643 "e c #CF3CBAEAB6DA",
2644 "r c #71C6451430C2",
2645 "t c #EFBEDB6CD75C",
2646 "y c #28A208200820",
2647 "u c #186110401040",
2648 "i c #596528A21861",
2649 "p c #71C661855965",
2650 "a c #A69996589658",
2651 "s c #30C228A230C2",
2652 "d c #BEFBA289AEBA",
2653 "f c #596545145144",
2654 "g c #30C230C230C2",
2655 "h c #8E3882078617",
2656 "j c #208118612081",
2657 "k c #38E30C300820",
2658 "l c #30C2208128A2",
2659 "z c #38E328A238E3",
2660 "x c #514438E34924",
2661 "c c #618555555965",
2662 "v c #30C2208130C2",
2663 "b c #38E328A230C2",
2664 "n c #28A228A228A2",
2665 "m c #41032CB228A2",
2666 "M c #104010401040",
2667 "N c #492438E34103",
2668 "B c #28A2208128A2",
2669 "V c #A699596538E3",
2670 "C c #30C21C711040",
2671 "Z c #30C218611040",
2672 "A c #965865955965",
2673 "S c #618534D32081",
2674 "D c #38E31C711040",
2675 "F c #082000000820",
2684 "ty> 459@>+&& ",
2686 "%$;=* *3:.Xa.dfg> ",
2687 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
2688 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
2689 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
2690 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
2691 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
2692 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
2693 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
2694 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
2695 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
2696 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
2697 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
2698 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
2699 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
2700 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
2701 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
2702 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
2703 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
2704 " p;<69BvwwsszslllbBlllllllu<5+ ",
2705 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
2706 " c1-699Blvlllllu7k96MMMg4 ",
2707 " *10y8n6FjvllllB<166668 ",
2708 " S-kg+>666<M<996-y6n<8* ",
2709 " p71=4 m69996kD8Z-66698&& ",
2710 " &i0ycm6n4 ogk17,0<6666g ",
2711 " N-k-<> >=01-kuu666> ",
2712 " ,6ky& &46-10ul,66, ",
2713 " Ou0<> o66y<ulw<66& ",
2714 " *kk5 >66By7=xu664 ",
2715 " <<M4 466lj<Mxu66o ",
2716 " *>> +66uv,zN666* ",
2726 /* quando invocata (con il segnale delete_event), termina l'applicazione. */
2727 void close_application( GtkWidget *widget, gpointer data ) {
2731 int main (int argc, char *argv[])
2733 /* il tipo di dato per i widget è GtkWidget */
2734 GtkWidget *window, *pixmap, *fixed;
2735 GdkPixmap *gdk_pixmap;
2740 /* crea la finestra principale e collega il segnale delete_event per
2741 terminare l'applicazione. Notare che non mettiamo un titolo
2743 gtk_init (&argc, &argv);
2744 window = gtk_window_new( GTK_WINDOW_POPUP );
2745 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2746 GTK_SIGNAL_FUNC (close_application), NULL);
2747 gtk_widget_show (window);
2749 /* ora occupiamoci della pixmap e del widget pixmap */
2750 style = gtk_widget_get_default_style();
2751 gc = style->black_gc;
2752 gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
2753 &style->bg[GTK_STATE_NORMAL],
2754 WheelbarrowFull_xpm );
2755 pixmap = gtk_pixmap_new( gdk_pixmap, mask );
2756 gtk_widget_show( pixmap );
2758 /* Per mostrare la pixmap, usiamo un widget "fixed" in cui metterla */
2759 fixed = gtk_fixed_new();
2760 gtk_widget_set_usize( fixed, 200, 200 );
2761 gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
2762 gtk_container_add( GTK_CONTAINER(window), fixed );
2763 gtk_widget_show( fixed );
2765 /* Questa maschera tutto tranne l'immagine stessa */
2766 gtk_widget_shape_combine_mask( window, mask, 0, 0 );
2768 /* mostra la finestra */
2769 gtk_widget_set_uposition( window, 20, 400 );
2770 gtk_widget_show( window );
2777 Per rendere sensibile l'immagine della carriola, potremmo collegare
2778 il segnale di pressione del bottone in modo che venga compiuta una certa
2779 azione. Le prossime linee renderebbero l'immagine sensibile alla pressione
2780 di un bottone del mouse che fa sì che l'applicazione termini.
2783 gtk_widget_set_events( window,
2784 gtk_widget_get_events( window ) |
2785 GDK_BUTTON_PRESS_MASK );
2787 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
2788 GTK_SIGNAL_FUNC(close_application), NULL );
2791 <!-- ----------------------------------------------------------------- -->
2794 I widget righello vengono usati per indicare la posizione del pontatore del
2795 mouse in una certa finestra. Una finestra può cioé avere un
2796 righello orizzontale che si estende per tutta la sua ampiezza e un righello verticale
2797 che ne comprende l'altezza. Un piccolo triangolo sui rghelli indica la posizione
2798 esatta del puntatore relativamente ai righelli.
2800 I righelli devono essere in primo luogo creati. I righlli orizzontali e verticali vengono
2804 GtkWidget *gtk_hruler_new(void); /* horizontal ruler */
2805 GtkWidget *gtk_vruler_new(void); /* vertical ruler */
2808 Una volta che che si è creato il righello, si può l'unità di
2809 misura. Le unità di misura possono essere GTK_PIXELS,
2810 GTK_INCHES oppure GTK_CENTIMETERS. Ciò viene stabilito usando
2813 void gtk_ruler_set_metric( GtkRuler *ruler,
2814 GtkMetricType metric );
2817 La misura predefinita è GTK_PIXELS.
2820 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
2823 Altre caratteritiche importanti di un righello sono il modo in cui vengono segnate
2824 le tacche delle unità di misura e dove viene posto inizialmente l'indicatore
2825 di posizione. Questi vengono stabiliti usando
2828 void gtk_ruler_set_range (GtkRuler *ruler,
2835 Gli argomenti lower e upper definiscono l'estensione del righello, e
2836 max_size rappresenta il numero massimo che verrà mostrato.
2837 Position definisce l posizione iniziale dell'indicatore del puntatore
2838 all'interno del righello.
2840 Quindi, un righello che può stare su una finestra di 800 pixel sarà:
2843 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
2846 Sul righello saranno presenti dei segni da 0 a 800, con un numero ogni 100 pixel.
2847 Se avessimo invece voluto che il righello fosse andato da 7 a 16, avremmo scritto:
2850 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
2853 L'indicatore sul righello è un piccolo segno triangolare che indica
2854 la posizione del puntatore rispetto al righello. Se il righello viene usato
2855 per seguire il movimento del mouse, il segnale di motion_notify_event
2856 dovrebbe venir connesso al metodo motion_notify_event del righello.
2857 Per seguire tutti i movimenti del mouse all'interno dell'area di una finestra,
2861 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
2863 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
2864 (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
2865 GTK_OBJECT(ruler) );
2868 L'esempio seguente crea un'area di disegno con un reghello orizzontale nella
2869 parte superiore e un righello verticale nella parte sinistra. Le dimensioni
2870 di questa area di disegno sono di 600 e 400 pixel risettivamente per la larghezza
2871 e per l'altezza. Il righello orizzontale va da 7 a 13 con una tacca ogni 100 pixel,
2872 mentre quello verticale va da 0 a 400, ancora con una tacca ogni 100 pixel.
2873 La sistemazione dell'area di disegno e dei righelli viene fatta usando una tabella.
2878 #include <gtk/gtk.h>
2880 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
2885 /* il controllo raggiunge questa routine quando si preme il bottone close
2887 void close_application( GtkWidget *widget, gpointer data ) {
2891 /* la routine principale
2893 int main( int argc, char *argv[] ) {
2894 GtkWidget *window, *table, *area, *hrule, *vrule;
2896 /* inizializziamo gtk e creiamo la finestra principale */
2897 gtk_init( &argc, &argv );
2899 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
2900 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2901 GTK_SIGNAL_FUNC( close_application ), NULL);
2902 gtk_container_border_width (GTK_CONTAINER (window), 10);
2904 /* creiamo una tabella in cui mettere righelli e area di disegno */
2905 table = gtk_table_new( 3, 2, FALSE );
2906 gtk_container_add( GTK_CONTAINER(window), table );
2908 area = gtk_drawing_area_new();
2909 gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
2910 gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
2911 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
2912 gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
2914 /* Il righello orizzontale va nella parte superiore. Quando il mouse si muove
2915 * nell'area di disegno, si passa un motion_notify_event al gestore appropriato
2916 * per il righello. */
2918 hrule = gtk_hruler_new();
2919 gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
2920 gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
2921 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
2922 (GtkSignalFunc)EVENT_METHOD(hrule, motion_notify_event),
2923 GTK_OBJECT(hrule) );
2924 /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
2925 gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
2926 GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
2928 /* Il righello verticale va nella parte sinistra. Quando il mouse si muove
2929 * nell'area di disegno, si passa un motion_notify_event al gestore appropriato
2930 * per il righello. */
2932 vrule = gtk_vruler_new();
2933 gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
2934 gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
2935 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
2937 GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)-motion_notify_event,
2938 GTK_OBJECT(vrule) );
2939 gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
2940 GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
2942 /* ora mostriamo tutto quanto */
2943 gtk_widget_show( area );
2944 gtk_widget_show( hrule );
2945 gtk_widget_show( vrule );
2946 gtk_widget_show( table );
2947 gtk_widget_show( window );
2954 <!-- ----------------------------------------------------------------- -->
2955 <sect1>Barre di Stato (Statusbar)
2957 Le barre di stato sono dei semplici widget usati per mostrare messaggi di test.
2958 Hanno la caratteristica di mantenere uno stack dei messggi che vi vengono
2959 mostrati, cosiccheé rimuovendo il messaggio corrente fa sì che
2960 torni ad essere mostrato il messaggio precedente..
2962 Per permettere a parti diverse di una stessa applicazione di usare la stessa barra di
2963 stato per mostrare messaggi, questo widget emette degli 'Identificatori di Contesto'
2964 che vengono usati per identificare i diversi 'utenti'. Quello che viene mostrato
2965 è sempre il messaggio che si trova in cima allo stack, a prescindere in
2966 quale contesto si trovi. I messaggi vengono immagazzinati secondo l'ordine
2967 LIFO, e non secondo l'ordine stabilito dal contesto.
2969 Una barra di stato viene creata con una chiamata a:
2971 GtkWidget* gtk_statusbar_new (void);
2974 Per richiedere un nuovo identificatore di contesto, si usa una chiamata alla seguente
2975 funzione con una breve descrizione testuale:
2977 guint gtk_statusbar_get_context_id (GtkStatusbar *statusbar,
2978 const gchar *context_description);
2981 Le seguenti sono tre funzioni che possono operare sulle barre di stato:
2983 guint gtk_statusbar_push (GtkStatusbar *statusbar,
2987 void gtk_statusbar_pop (GtkStatusbar *statusbar)
2989 void gtk_statusbar_remove (GtkStatusbar *statusbar,
2994 La prima, gtk_statusbar_push, viene usata per aggiungere un nuovo messaggio
2995 alla barra di stato. Questa restituisce un identificatore di messaggio, che può
2996 essere passato successivamente alla funzione gtk_statusbar_remove per rimuovere
2997 dallo stack il messggio con identificatore di messaggio e di contesto dati.
2999 La funzione gtk_statusbar_pop rimuove il messaggio che si trova in cima allo stack
3000 avente un dato identificatore di contesto.
3002 Nel seguente esempio si crea una barra di stato e due bottoni, uno per mettere
3003 elementi sulla barra di stato e l'altro per riuovere l'ultimo elemento..
3008 #include <gtk/gtk.h>
3011 GtkWidget *status_bar;
3013 void push_item (GtkWidget *widget, gpointer data)
3015 static int count = 1;
3018 g_snprintf(buff, 20, "Item %d", count++);
3019 gtk_statusbar_push( GTK_STATUSBAR(status_bar), (guint) &data, buff);
3024 void pop_item (GtkWidget *widget, gpointer data)
3026 gtk_statusbar_pop( GTK_STATUSBAR(status_bar), (guint) &data );
3030 int main (int argc, char *argv[])
3039 gtk_init (&argc, &argv);
3041 /* creazione di una nuova finestra */
3042 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3043 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
3044 gtk_window_set_title(GTK_WINDOW (window), "GTK Statusbar Example");
3045 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
3046 (GtkSignalFunc) gtk_exit, NULL);
3048 vbox = gtk_vbox_new(FALSE, 1);
3049 gtk_container_add(GTK_CONTAINER(window), vbox);
3050 gtk_widget_show(vbox);
3052 status_bar = gtk_statusbar_new();
3053 gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
3054 gtk_widget_show (status_bar);
3056 context_id = gtk_statusbar_get_context_id( GTK_STATUSBAR(status_bar), "Statusbar example");
3058 button = gtk_button_new_with_label("push item");
3059 gtk_signal_connect(GTK_OBJECT(button), "clicked",
3060 GTK_SIGNAL_FUNC (push_item), &context_id);
3061 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
3062 gtk_widget_show(button);
3064 button = gtk_button_new_with_label("pop last item");
3065 gtk_signal_connect(GTK_OBJECT(button), "clicked",
3066 GTK_SIGNAL_FUNC (pop_item), &context_id);
3067 gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
3068 gtk_widget_show(button);
3070 /* la finestra va sempre mostrata come ultimo passo, in modo che venga
3071 * sullo schermo tutta in una volta. */
3072 gtk_widget_show(window);
3080 <!-- ----------------------------------------------------------------- -->
3081 <sect1>Inserimento di testo
3083 Questo widget permette diinserire e mostrare del testo in una casella contenente una
3084 sola linea. Il testo può essere assegnato con chiamate di funzione che
3085 permettono a nuovo testo di sostituire, seguire o precedere il contenuto corrente
3086 del widget di inserimento testo.
3088 Per la creazione di un inserimento di testo, sono disponibili due funzioni:
3090 GtkWidget* gtk_entry_new (void);
3092 GtkWidget* gtk_entry_new_with_max_length (guint16 max);
3095 La prima crea solamente un inserimento di testo, mentre la seconda lo crea
3096 imponendo un limite alla lunghezza del testo inseribile..
3098 Per cambiaere il testo che si trova correntemente nel widget, sono disponibili diverse
3101 void gtk_entry_set_text (GtkEntry *entry,
3103 void gtk_entry_append_text (GtkEntry *entry,
3105 void gtk_entry_prepend_text (GtkEntry *entry,
3109 La funzione gtk_entry_set_text assegna il contenuto del widget di inserimento,
3110 sostituendo il contenuto corrente. Le funzioni gtk_entry_append_text e gtk_entry_prepend_text
3111 permettono di antemporre o posporre un testo al testo corrente..
3113 La prossima funzione permette di stabilire il punto di inserimento.
3115 void gtk_entry_set_position (GtkEntry *entry,
3119 Usando la seguente funzione, è possibile estrarre il contenuto di un widget di inserimento.
3120 Ciò può essere utile nelle funzioni di ritorno come descritto più sotto.
3122 gchar* gtk_entry_get_text (GtkEntry *entry);
3125 Se non si vuole che qualcuno possa cambiare il contenuto di una entry sovrascrivendola,
3126 ne possiamo cambiare lo stato di "editabilità"..
3128 void gtk_entry_set_editable (GtkEntry *entry,
3132 Questa funzine ci permette di far passare un widget di inserimento dallo sato di editabile a
3133 quello di non editabile passando con l'argomento editable i valori TRUE o FALSE.
3135 Se stiamo usando l'entry in un punto in cui non vogliamo che il testo sia visibile, per
3136 esempio quando si digita una password, possiamo usare la seguente funzione, che
3137 accetta un parametro booleano..
3139 void gtk_entry_set_visibility (GtkEntry *entry,
3143 Si può stabilire che una parte del testo risulti selezionata usado la seguente funzione.
3144 Si userà di solito questa possibilità dopo aver inserito nel widget un
3145 qualche valore predefinito, in modo che per l'utente sia semplice sostituirlo.
3148 void gtk_entry_select_region (GtkEntry *entry,
3153 Se vogliamo accorgerci del momento in cui l'utente ha inserito del testo, possiamo connettere
3154 il segnale <tt/activate/ o <tt/changed/. <tt/activate/ viene reso attivo quando
3155 l'utente preme il tasto Enter mentre si trova nel widget. <tt/changed/ viene invece emesso ogni volta che
3156 il testo cambia, per esempio ogni volta che viene inserito o rimosso un carattere.
3158 Il seguente codice mostra un esempio di utilizzo del widget di inserimento.
3163 #include <gtk/gtk.h>
3165 void enter_callback(GtkWidget *widget, GtkWidget *entry)
3168 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
3169 printf("Entry contents: %s\n", entry_text);
3172 void entry_toggle_editable (GtkWidget *checkbutton,
3175 gtk_entry_set_editable(GTK_ENTRY(entry),
3176 GTK_TOGGLE_BUTTON(checkbutton)->active);
3179 void entry_toggle_visibility (GtkWidget *checkbutton,
3182 gtk_entry_set_visibility(GTK_ENTRY(entry),
3183 GTK_TOGGLE_BUTTON(checkbutton)->active);
3186 int main (int argc, char *argv[])
3190 GtkWidget *vbox, *hbox;
3195 gtk_init (&argc, &argv);
3197 /* creiamo una nuova finestra */
3198 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3199 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
3200 gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
3201 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
3202 (GtkSignalFunc) gtk_exit, NULL);
3204 vbox = gtk_vbox_new (FALSE, 0);
3205 gtk_container_add (GTK_CONTAINER (window), vbox);
3206 gtk_widget_show (vbox);
3208 entry = gtk_entry_new_with_max_length (50);
3209 gtk_signal_connect(GTK_OBJECT(entry), "activate",
3210 GTK_SIGNAL_FUNC(enter_callback),
3212 gtk_entry_set_text (GTK_ENTRY (entry), "hello");
3213 gtk_entry_append_text (GTK_ENTRY (entry), " world");
3214 gtk_entry_select_region (GTK_ENTRY (entry),
3215 0, GTK_ENTRY(entry)->text_length);
3216 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
3217 gtk_widget_show (entry);
3219 hbox = gtk_hbox_new (FALSE, 0);
3220 gtk_container_add (GTK_CONTAINER (vbox), hbox);
3221 gtk_widget_show (hbox);
3223 check = gtk_check_button_new_with_label("Editable");
3224 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
3225 gtk_signal_connect (GTK_OBJECT(check), "toggled",
3226 GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
3227 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
3228 gtk_widget_show (check);
3230 check = gtk_check_button_new_with_label("Visible");
3231 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
3232 gtk_signal_connect (GTK_OBJECT(check), "toggled",
3233 GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
3234 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
3235 gtk_widget_show (check);
3237 button = gtk_button_new_with_label ("Close");
3238 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3239 GTK_SIGNAL_FUNC(gtk_exit),
3240 GTK_OBJECT (window));
3241 gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
3242 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3243 gtk_widget_grab_default (button);
3244 gtk_widget_show (button);
3246 gtk_widget_show(window);
3253 <!-- ----------------------------------------------------------------- -->
3254 <sect1> Selettori di Colore
3256 Il widget selettore di colore è chiaramente un widget che permtte di
3257 scegliere interattivamente dei colori. Questo widget composto permette all'utente
3258 di selezionare un colore agendo su terne RGB (Red, Green, Blue) e HSV
3259 (Hue, Saturation, Value). Questo lo si può fare o agendo sui singoli valori
3260 tramite degli slider o inserendoli da tastiera, oppure selezionando direttamente il
3261 colore da un cerchio (valori H e S) e da una barra (valore V).
3262 Opzionalmente, è possibile anche stabilire il grado di trasparenza del
3264 Il widget di selezione di colore emette per ora un solo segnale, "color_changed", che
3265 viene generato ogni volta che il colore corrente nel widget cambia, sia quando
3266 è l'utente a cambiarlo, sia quando viene modificato esplicitamente tramite
3267 una chiamata a gtk_color_selection_set_color().
3269 Diamo ora un'occhiata a cosa ha da offrirci il widget di selezione di colore.
3270 Il widget è disponibile in due versioni, gtk_color_selection e
3271 gtk_color_selection_dialog:
3274 GtkWidget *gtk_color_selection_new(void);
3277 E' probabile che non userete questo costruttore direttamente. Infatti esso crea un
3278 widget GtkColorSelection orfano a cui dovrete assegnare un genitore voi stessi.
3279 Il widget GtkColorSelection eredita dal widget GtkVBox.
3282 GtkWidget *gtk_color_selection_dialog_new(const gchar *title);
3285 Questo è il più comune fra i costruttori di selettori di colore. Esso
3286 crea un GtkColorSelectionDialog, che eredita da GtkDialog. Esso consiste di un
3287 GtkFrame che contiene un widget GtkColorSelection, un GtkHSeparator e un
3288 GtkHBox con tre bottoni, "Ok", "Cancel" e "Help". Si arriva a questi bottoni
3289 accedendo ai widget "ok_button", "cancel_button" e "help_button" nella
3290 struttura GtkColorSelectionDialog (cioè (GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button).
3293 void gtk_color_selection_set_update_policy(GtkColorSelection *colorsel,
3294 GtkUpdateType policy);
3297 Questa funzione stabilisce la politica di aggiornamento. Quella predefinita è
3298 GTK_UPDATE_CONTINOUS, che significa che il colore viene aggiornato
3299 continuamente mano a mano che l'utente trascina gli slider o preme e trascina il
3300 mouse nel cerchio della hue-saturation o nella relativa barra. Se si hanno problemi
3301 di prestazioni, si può decidere di usare la politica
3302 GTK_UPDATE_DISCONTINOUS
3303 o GTK_UPDATE_DELAYED.
3306 void gtk_color_selection_set_opacity(GtkColorSelection *colorsel,
3310 Il widget di selezione di colore permette anche di variare l'opacità di un
3311 colore (conosciuta anche come canale alfa). Questa caratteristica è
3312 normalmente disabilitata. Chiamare la precedente funzione, con use_opacity uguale
3313 a TRUE abilita la manipolazione dell'opacità. Analogamente, mettendo
3314 use_opacity uguale a FALSE la disabiliterà.
3317 void gtk_color_selection_set_color(GtkColorSelection *colorsel,
3321 Si può assegnare esplicitamente un colore chiamando questa funzione
3322 con un puntatore ad un vettore di colori (gdouble). La lunghezza del vettore
3323 dipende dall'attivazione o meno del controllo dell'opacità. La posizione 0
3324 contiene la componente rossa, la 1 ` il verde, la 2 il blu e la 3 contiene
3325 l'opacità (se questa ` attivata, come si è detto per
3326 gtk_color_selection_set_opacity()). Tutti i valori sono compresi fra 0.0 e 1.0.
3329 void gtk_color_selection_get_color(GtkColorSelection *colorsel,
3333 Questa funzione viene usata per ottenere il colore corrente, tipicamente quando
3334 si è ricevuto il segnale "color_changed". Color è un puntatore al
3335 vettore di colori da riempire. Vedi la descrizione di questo vettore nella funzione
3336 gtk_color_selection_set_color().
3338 <!-- C'e' bisogno di una sezione sul DnD - TRG
3343 Le aree con l'esempio del colore (sotto il cerchio H-S) supportano il drag and drop.
3344 Il tipo del drag and drop è "application/x-color". I dati del messaggio sono
3345 costituiti da un vettore di 4 valori gdouble (o 5 nel caso di attivazione
3346 dell'opacità), in cui il valore alla posizione 0 ` può
3347 essere 0.0 (opacità attivata) o 1.0 (disattivata) seguito dal rosso,
3348 dal verde e dal blu alle posizioni 1,2 e 3. Nel caso di opacità attiva,
3349 il suo valore è passato alla posizione 4.
3352 Ecco un semplice esempio che mostra l'uso di GtkColorSelectionDialog.
3353 Il programma mostra una finestra che contiene un'area di disegno. Cliccandoci
3354 sopra, si apre un dialogo di selezione di colore, e se si modifica il colore
3355 nella finestra di dialogo verrà cambiato anche il colore dello sfondo.
3359 #include <gdk/gdk.h>
3360 #include <gtk/gtk.h>
3362 GtkWidget *colorseldlg = NULL;
3363 GtkWidget *drawingarea = NULL;
3365 /* gestore del cambiamento del colore */
3367 void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel)
3371 GdkColormap *colormap;
3373 /* recupera la colormap dell'area di disegno */
3375 colormap = gdk_window_get_colormap (drawingarea->window);
3377 /* recupera il colore corrente */
3379 gtk_color_selection_get_color (colorsel,color);
3381 /* adattamento ad un intero unsigned di 16 bit (0..65535)
3382 * e inseriscili nella struttura GdkColor */
3384 gdk_color.red = (guint16)(color[0]*65535.0);
3385 gdk_color.green = (guint16)(color[1]*65535.0);
3386 gdk_color.blue = (guint16)(color[2]*65535.0);
3388 /* Alloca il colore */
3390 gdk_color_alloc (colormap, &gdk_color);
3392 /* assegna il colore di sfondo della finestra */
3394 gdk_window_set_background (drawingarea->window, &gdk_color);
3396 /* pulisce la finestra */
3398 gdk_window_clear (drawingarea->window);
3401 /* gestore per l'area di disegno */
3403 gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data)
3405 gint handled = FALSE;
3406 GtkWidget *colorsel;
3408 /* controlliamo se abbiamo ricevuto un evento di pressione di pulsante */
3410 if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
3412 /* Si , c'e' l'evento e ancora non c'e' alcun colorseldlg! */
3416 /* Creiamo una finestra di dialogo per la selezione del colore */
3418 colorseldlg = gtk_color_selection_dialog_new("Select background color");
3420 /* Otteniamo il widget GtkColorSelection */
3422 colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
3424 /* Facciamo la connessione al segnale "color_changed",
3425 * ed assegnamo i dati-utente al widget di selezione di colore */
3427 gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
3428 (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
3430 /* Mostriamo il dialogo */
3432 gtk_widget_show(colorseldlg);
3438 /* Chiusura ed uscita dal getore */
3440 void destroy_window (GtkWidget *widget, gpointer client_data)
3447 gint main (gint argc, gchar *argv[])
3451 /* Inizialliziamo il toolkit, remuoviamo gli argomenti sulla linea di
3452 * comando legati a gtk */
3454 gtk_init (&argc,&argv);
3456 /* creiamo la finestra base, con titolo e politiche */
3458 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3459 gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
3460 gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);
3462 /* colleghiamo gli eventi "delete" e "destroy" per poter uscire */
3464 gtk_signal_connect (GTK_OBJECT(window), "delete_event",
3465 (GtkSignalFunc)destroy_window, (gpointer)window);
3467 gtk_signal_connect (GTK_OBJECT(window), "destroy",
3468 (GtkSignalFunc)destroy_window, (gpointer)window);
3470 /* crea un'area di disegna, stabilisce le dimensioni e raccogli
3473 drawingarea = gtk_drawing_area_new ();
3475 gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
3477 gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
3479 gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
3480 (GtkSignalFunc)area_event, (gpointer)drawingarea);
3482 /* aggiungi l'area di disegno alla finestra e mostrale entrambe */
3484 gtk_container_add (GTK_CONTAINER(window), drawingarea);
3486 gtk_widget_show (drawingarea);
3487 gtk_widget_show (window);
3489 /* entra nel ciclo principale di gtk (che non cede mai il controllo */
3493 /* soddisfa i compilatori brontoloni */
3499 <!-- ----------------------------------------------------------------- -->
3500 <sect1> Selezione di File (File Selections)
3503 Il widget Selezione di File è un modo rapido e semplice per mostrare una
3504 finestra di dialogo `File'. Questa si presenta completa di bottoni Ok,
3505 Cancel e Help, un buon modo per tagliare i tempi di programmazione.
3507 Per creare una nuova finestra di selezione file usate:
3510 GtkWidget* gtk_file_selection_new (gchar *title);
3513 Per assegnare il nome del file, ad esempio per predisporre una certa
3514 directory o per dare un certo nome di file per difetto, usate la seguente
3518 void gtk_file_selection_set_filename (GtkFileSelection *filesel, gchar *filename);
3521 Per recuperare il testo che l'utente ha inserito o che ha selezionato con
3522 il mouse, si usa la funzione:
3525 gchar* gtk_file_selection_get_filename (GtkFileSelection *filesel);
3528 Ci sono anche dei puntatori ai widget che sono contenuti all'interno
3529 del widget di selezione file. Si tratta di:
3534 <item>selection_entry
3535 <item>selection_text
3542 Molto probabilmente potreste voler usare i puntatori a ok_button,
3543 cancel_button e help_button per segnalarne l'uso.
3545 Ecco un esempio rubato da testgtk.c, nodificato per essere eseguito da
3546 solo. Come potrete vedere, non c'è molto più che la creazione di un
3547 widget di selezione file. In questo esempio, il bottone Help non fa nulla
3548 mentre è mostrato allo schermo, dal momento che non c'è alcun segnale
3554 #include <gtk/gtk.h>
3556 /* Recupera il nome di file selezionato e stampalo a console */
3557 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
3559 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
3562 void destroy (GtkWidget *widget, gpointer data)
3567 int main (int argc, char *argv[])
3571 gtk_init (&argc, &argv);
3573 /* Crea un nuovo widget di selezione file */
3574 filew = gtk_file_selection_new ("File selection");
3576 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
3577 (GtkSignalFunc) destroy, &filew);
3578 /* Connette ok_button alla funzione file_ok_sel */
3579 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
3580 "clicked", (GtkSignalFunc) file_ok_sel, filew );
3582 /* Connette cancel_button alla funzione di distruzione del widget */
3583 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
3584 "clicked", (GtkSignalFunc) gtk_widget_destroy,
3585 GTK_OBJECT (filew));
3587 /* Preassegnamo un nome di file, come se stessimo dando un valore per difetto in
3588 dialogo di tipo `` salva con nome '' */
3589 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
3592 gtk_widget_show(filew);
3598 <!-- ***************************************************************** -->
3599 <sect> Widget Contenitore
3600 <!-- ***************************************************************** -->
3602 <!-- ----------------------------------------------------------------- -->
3603 <sect1> Il widget Blocco Note (Notebook)
3605 Il widget Blocco note è un insieme di pagine sovrapposte l'una con l'altra,
3606 ognuna contente cose diverse. Questo widget è diventato molto comune nella
3607 programmazione delle interfacce utente ed è un buon metodo per mostrare informazioni
3608 tra loro correlate ma che debbano essere mostrate separatamente.
3611 La prima funzione da invocare che si deve conoscere, come si può intuire, è usata
3612 per creare un nuovo Blocco Note.
3615 GtkWidget* gtk_notebook_new (void);
3618 Una volta che il notebook è sato creato, ci sono 12 funzioni che possono
3619 operare sul widget notebook. Guardiamole individualmente.
3621 La prima che vediamo riguarda come posizionare l'indicatore di pagina.
3622 Questi inidicatori di pagina o ``linguette'' (come possono anche essere chiamati)
3623 possono essere posizionati in quattro posti: alto, basso, sinistra.destra.
3626 void gtk_notebook_set_tab_pos (GtkNotebook *notebook, GtkPositionType pos);
3629 GtkPositionType sarà uno dei seguenti valori (molto autoesplicativi)
3632 <item> GTK_POS_RIGHT
3634 <item> GTK_POS_BOTTOM
3637 GTK_POS_TOP e' il valore predefinito.
3639 Ora vediamo come aggiugere le pagine al Blocco Note. Ci sono 3 modi per farlo. Diamo
3640 un'occhiata ai primi due insieme, viste che sono molto simili.
3643 void gtk_notebook_append_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
3645 void gtk_notebook_prepend_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
3648 Queste funzioni aggiungono pagine al notebook inserendole rispettivamente alla fine
3649 (append) o all'inizio (prepend). *child è il widget che è posto nella pagina del
3650 notebook e *tab_label e la intestazione della pagina stessa.
3652 L'ultima funzione per aggiungere una pagina al notebook contiene tutte le proprietà
3653 delle precedenti due, ma permette di specificare dove posizionare la pagina che
3657 void gtk_notebook_insert_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, gint position);
3660 I parametri sono gli stessi di _append_ e _prepend_ tranne che per il parametro in
3661 più: ``position''.
3662 Questo parametro viene usato per specificare in che posizione ineserire la pagina.
3664 Ora che conosciamo come aggiungere le pagine, vediamo come poter toglierne una.
3667 void gtk_notebook_remove_page (GtkNotebook *notebook, gint page_num);
3670 Questa funzione prende il numero della pagina specificata dal campo page_num e
3671 rimuove la pagina corrispondente dal Blocco Note.
3673 Per trovare qual'è la pagina corrente nel notebook bisogna usare la funzione:
3676 gint gtk_notebook_current_page (GtkNotebook *notebook);
3679 Le prossime due funzioni sono semplicemente delle chiamate che muovono la pagina del
3680 notebook avanti o indietro. Semplicemente forniscono le chiamate alle rispettive
3681 funzioni del widget notebook su si può operare. NB: quando un notebook è
3682 correntemente sull'ultima pagina e viene invocata la funzione gtk_notebook_next_page,
3683 il notebook ritornerà automaticamente alla prima pagina. Logicamente succede anche
3684 il contrario quando invochi gtk_notebook_prev_page e ti trovi sulla prima pagina.
3687 void gtk_notebook_next_page (GtkNoteBook *notebook);
3688 void gtk_notebook_prev_page (GtkNoteBook *notebook);
3691 La prossima funzione stabilisce la pagina ``attiva''. Se si vuole che la pagina
3692 principale del notebook sia per esempio la 5 (ad esempio) si può usare questa
3694 Se non si usa questa funzione la pagina principale sarà la 1.
3697 void gtk_notebook_set_page (GtkNotebook *notebook, gint page_num);
3700 Le prossime due funzioni aggiungono o rimuovono, rispettivamente, le intestazioni e
3701 i bordi delle pagine.
3704 void gtk_notebook_set_show_tabs (GtkNotebook *notebook, gint show_tabs);
3705 void gtk_notebook_set_show_border (GtkNotebook *notebook, gint show_border);
3708 show_tabs e show_border posso avere come valore TRUE o FALSE (0 or 1).
3710 Diamo ora una occhiata ad un esempio. Si tratta di una espansione del codice preso
3711 dal file testgtk.c che è compreso in tutte le distribuzioni, e mostra
3712 tutte le 13 funzioni. Questo piccolo programma crea una finestra con un notebook
3713 e 6 bottoni. Il notebook contiene 11 pagine, aggiunte nei 3 modi differenti (alla
3714 fine, all'inizio o in qualsiasi posizione). I bottoni permettono di girare le
3715 intestazioni, aggiungere/rimuovere le intestazioni e i bordi, rimuovere una
3716 pagina, cambiare la pagina avanti e indietro e uscire dal programma.
3721 #include <gtk/gtk.h>
3723 /* Queta funzione ruota le posizione delle linguette delle pagine */
3724 void rotate_book (GtkButton *button, GtkNotebook *notebook)
3726 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
3729 /* Aggiunge e rimuove le linguette e i bordi */
3730 void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
3734 if (notebook->show_tabs == 0)
3736 if (notebook->show_border == 0)
3739 gtk_notebook_set_show_tabs (notebook, tval);
3740 gtk_notebook_set_show_border (notebook, bval);
3743 /* Rimuove una pagina */
3744 void remove_book (GtkButton *button, GtkNotebook *notebook)
3748 page = gtk_notebook_current_page(notebook);
3749 gtk_notebook_remove_page (notebook, page);
3750 /* E' necessario fare un refresh del widget --
3751 Questo forza il widget a ridisegnarsi. */
3752 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
3755 void delete (GtkWidget *widget, gpointer data)
3760 int main (int argc, char *argv[])
3765 GtkWidget *notebook;
3768 GtkWidget *checkbutton;
3773 gtk_init (&argc, &argv);
3775 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3777 gtk_signal_connect (GTK_OBJECT (window), "destroy",
3778 GTK_SIGNAL_FUNC (destroy), NULL);
3780 gtk_container_border_width (GTK_CONTAINER (window), 10);
3782 table = gtk_table_new(2,6,TRUE);
3783 gtk_container_add (GTK_CONTAINER (window), table);
3785 /* Crea un nuovo notebook, e tabilisce la posizione delle linguette */
3786 notebook = gtk_notebook_new ();
3787 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
3788 gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
3789 gtk_widget_show(notebook);
3791 /* appende una parte delle pagine */
3792 for (i=0; i < 5; i++) {
3793 sprintf(bufferf, "Append Frame %d", i+1);
3794 sprintf(bufferl, "Page %d", i+1);
3796 frame = gtk_frame_new (bufferf);
3797 gtk_container_border_width (GTK_CONTAINER (frame), 10);
3798 gtk_widget_set_usize (frame, 100, 75);
3799 gtk_widget_show (frame);
3801 label = gtk_label_new (bufferf);
3802 gtk_container_add (GTK_CONTAINER (frame), label);
3803 gtk_widget_show (label);
3805 label = gtk_label_new (bufferl);
3806 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
3810 /* Ora aggiungiamo una pagina in una certa posizione */
3811 checkbutton = gtk_check_button_new_with_label ("Check me please!");
3812 gtk_widget_set_usize(checkbutton, 100, 75);
3813 gtk_widget_show (checkbutton);
3815 label = gtk_label_new ("Add spot");
3816 gtk_container_add (GTK_CONTAINER (checkbutton), label);
3817 gtk_widget_show (label);
3818 label = gtk_label_new ("Add page");
3819 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
3821 /* Ora finalmente aggiungiamo le pagine all'inizio */
3822 for (i=0; i < 5; i++) {
3823 sprintf(bufferf, "Prepend Frame %d", i+1);
3824 sprintf(bufferl, "PPage %d", i+1);
3826 frame = gtk_frame_new (bufferf);
3827 gtk_container_border_width (GTK_CONTAINER (frame), 10);
3828 gtk_widget_set_usize (frame, 100, 75);
3829 gtk_widget_show (frame);
3831 label = gtk_label_new (bufferf);
3832 gtk_container_add (GTK_CONTAINER (frame), label);
3833 gtk_widget_show (label);
3835 label = gtk_label_new (bufferl);
3836 gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
3839 /* Stabilisce quale sarà la prima pagina che sarà visualizzata. */
3840 gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
3843 /* Crea un set di bottoni */
3844 button = gtk_button_new_with_label ("close");
3845 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3846 GTK_SIGNAL_FUNC (delete), NULL);
3847 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
3848 gtk_widget_show(button);
3850 button = gtk_button_new_with_label ("next page");
3851 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3852 (GtkSignalFunc) gtk_notebook_next_page,
3853 GTK_OBJECT (notebook));
3854 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
3855 gtk_widget_show(button);
3857 button = gtk_button_new_with_label ("prev page");
3858 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3859 (GtkSignalFunc) gtk_notebook_prev_page,
3860 GTK_OBJECT (notebook));
3861 gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
3862 gtk_widget_show(button);
3864 button = gtk_button_new_with_label ("tab position");
3865 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3866 (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
3867 gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
3868 gtk_widget_show(button);
3870 button = gtk_button_new_with_label ("tabs/border on/off");
3871 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3872 (GtkSignalFunc) tabsborder_book,
3873 GTK_OBJECT (notebook));
3874 gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
3875 gtk_widget_show(button);
3877 button = gtk_button_new_with_label ("remove page");
3878 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
3879 (GtkSignalFunc) remove_book,
3880 GTK_OBJECT(notebook));
3881 gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
3882 gtk_widget_show(button);
3884 gtk_widget_show(table);
3885 gtk_widget_show(window);
3893 E speriamo che questo vi aiuti a creare i Blocco Note per le vostre applicazioni GTK!
3895 <!-- ----------------------------------------------------------------- -->
3896 <sect1> Finestre Scorribili (Scrolled Windows)
3898 Le Finestre Scorribili sono usate per creare areee scorribili in una vera finestra.
3899 Si può inserire qualsiasi tipo di widget in questo tipo di finestra, e possono poi
3900 essere accessibili a prescindere dalle dimensioni usando le barre di scorrimento.
3902 La funzione seguente è usata per creare una nuova scrolled window.
3905 GtkWidget* gtk_scrolled_window_new (GtkAdjustment *hadjustment,
3906 GtkAdjustment *vadjustment);
3909 Il primo argomento è l'aggiustamento (di quanto scendere ogni
3910 volta) orizzontale e il secondo è quello verticale. A questi si assegna
3911 quasi sempre il valore NULL.
3915 void gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
3916 GtkPolicyType hscrollbar_policy,
3917 GtkPolicyType vscrollbar_policy);
3920 Questa funzione stabilisce la politica da usare nella barra di scorrimento. Il primo
3921 argomento è la finestra scorribile interessata. Il secondo stabilisce la politica
3922 per la barra di scorrimento orizzontale e il terzo è quello per la politca verticale.
3924 La politica può essere GTK_POLICY AUTOMATIC o GTK_POLICY_ALWAYS.
3925 GTK_POLICY_AUTOMATIC decide automaticamente se la barra di scorrimento deve essere
3926 visualizzata, mentre con GTK_POLICY_ALWAYS la barra verrà sempre mostrata.
3931 #include <gtk/gtk.h>
3933 void destroy(GtkWidget *widget, gpointer data)
3938 int main (int argc, char *argv[])
3940 static GtkWidget *window;
3941 GtkWidget *scrolled_window;
3947 gtk_init (&argc, &argv);
3949 /* Crea una nuove finestra di dialogo in cui la scrolled window sarà
3950 inserita. Una finestra di dialogo è semplicemente come una
3951 finestra normale, ma ha anche un vbox e un separatore orizzontale
3952 già inseriti per difetto. E'un modo semplice per
3953 creare finestre di dialogo. */
3954 window = gtk_dialog_new ();
3955 gtk_signal_connect (GTK_OBJECT (window), "destroy",
3956 (GtkSignalFunc) destroy, NULL);
3957 gtk_window_set_title (GTK_WINDOW (window), "dialog");
3958 gtk_container_border_width (GTK_CONTAINER (window), 0);
3959 gtk_widget_set_usize(window, 300, 300);
3961 /* crea una nuova finestra scorribile. */
3962 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
3964 gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
3966 /* la politica è GTK_POLICY AUTOMATIC per lo scorrimento orizzontale e
3967 GTK_POLICY_ALWAYS per quello verticale. */
3968 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
3969 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
3971 /* La finestra di dialogo è creata con un vbox già inserito.*/
3972 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
3974 gtk_widget_show (scrolled_window);
3976 /* crea una tablella di10 x 10. */
3977 table = gtk_table_new (10, 10, FALSE);
3979 /* setta lo spazio tra ogni cella di 10 pixel sia verticale sia orizzontale*/
3980 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
3981 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
3983 /* inserisce la tabella nella finestra scorribile*/
3984 gtk_container_add (GTK_CONTAINER (scrolled_window), table);
3985 gtk_widget_show (table);
3987 /* questo semplicemente crea una griglia di bottoni nella tabelle per
3988 dimostrare il comportamento della finestra scorribile */
3989 for (i = 0; i < 10; i++)
3990 for (j = 0; j < 10; j++) {
3991 sprintf (buffer, "button (%d,%d)\n", i, j);
3992 button = gtk_toggle_button_new_with_label (buffer);
3993 gtk_table_attach_defaults (GTK_TABLE (table), button,
3995 gtk_widget_show (button);
3998 /* Aggiunge un bottone "close" alla fine della finestra */
3999 button = gtk_button_new_with_label ("close");
4000 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
4001 (GtkSignalFunc) gtk_widget_destroy,
4002 GTK_OBJECT (window));
4004 /* questo fa sì che questo bottone sia quello predefinito */
4006 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4007 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
4009 /* Questo ottiene il bottone predefinito. Premendo semplicemente l'"enter" il
4010 bottone si avvierà */
4011 gtk_widget_grab_default (button);
4012 gtk_widget_show (button);
4014 gtk_widget_show (window);
4022 Prova a giocare con il ridemensionamento della finestra. Noterete la reazione della
4023 barra di scorrimento. Potete anche usare la funzione gtk_widget_set_usize() per
4024 assegnare la dimensione predefinita della finestra o di un widget.
4025 <!-- (ndMichel: questa chiamata non funziona per i bottoni!) -->
4027 <!-- ----------------------------------------------------------------- -->
4028 <sect1> Il widget "Finestra Frazionata" (Paned Window)
4030 Le finestre frazionate tornano utili quando si vuole dividere un'area in due parti,
4032 le cui dimensioni relative siano sotto il controllo dell'utente. Fra le due zone
4034 viene disgnato un separatore dotato di una maniglia che l'utente può
4036 trascinare per cambiare la proporzione fra le aree. La divisione può
4038 essere sia di tipo orizzontale (HPaned) che verticale (VPaned).
4041 Per creare una finestra frazionata, si chiama una delle seguenti:
4044 GtkWidget* gtk_hpaned_new (void)
4045 GtkWidget* gtk_vpaned_new (void)
4049 Dopo aver creato il widget della finestra frazionata, si devono aggiungere dei
4051 widget figli alle due parti. Per farlo, si usano le funzioni:
4054 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child)
4055 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child)
4058 <tt/gtk_paned_add1()/ inserisce il widget figlo alla parte di sinistra o superiore
4060 della finestra. <tt/gtk_paned_add2()/ lo inserisce invece nella parte destra o
4065 Per fare un esempio, creeremo una parte dell'interfaccia utente di un immaginario
4067 programma di email. Si divide una finestra in due verticalmente, <!-- sicuro ? -->
4069 con la parte superiore in cui si mette la lista dei messaggi, e quella inferiore con
4071 il testo. La maggior parte del programma è piuttosto banale. Un paio
4073 di punti da notare sono: Non si può scrivere su un widget di testo prima
4075 che esso venga "realizato". Questa operazione può essere fatta con una
4077 chiamata alla funzione <tt/gtk_widget_realize()/, ma per far vedere un metodo
4079 alternativo, connetteremo una funzione al segnale "realize" per aggiungere il testo.
4081 Inoltre, dobbiamo aggiungere l'opzione <tt/GTK_SHRINK/ ad alcuni degli
4083 elementi della tabella che contiene la finestra del testo e le barre di scorrimento, in
4085 modo che quando si riducono le dimensioni della parte inferiore, le parti coinvolte
4087 risultino proporzionalmente rimpicciolite invece di venir spinte fuori dal fondo
4095 #include <gtk/gtk.h>
4097 /*Creiamo la lista dei "messaggi" */
4102 GtkWidget *scrolled_window;
4104 GtkWidget *list_item;
4109 /* Creiamo una nuova finestra scorribile con barre di scorrimento solo
4112 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
4113 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
4114 GTK_POLICY_AUTOMATIC,
4115 GTK_POLICY_AUTOMATIC);
4117 /* Creiamo una nuova lista e la mettiamo nella finestra scorribile */
4118 list = gtk_list_new ();
4119 gtk_container_add (GTK_CONTAINER(scrolled_window), list);
4120 gtk_widget_show (list);
4122 /* Aggiungiamo un po' di messaggi alla fiestra */
4123 for (i=0; i<10; i++) {
4125 sprintf(buffer,"Message #%d",i);
4126 list_item = gtk_list_item_new_with_label (buffer);
4127 gtk_container_add (GTK_CONTAINER(list), list_item);
4128 gtk_widget_show (list_item);
4132 return scrolled_window;
4135 /* Aggiungiamo un po' di testo al nostro widget di testo - questa e' una
4137 funzione di callback che viene invocata quando la finestra viene "realizzata".
4139 Potremmo anche forzare la finestra ad essere realizzata con la funzione
4141 gtk_widget_realize, ma dovrebbe prima essere parte di una certa cerarchia */
4145 realize_text (GtkWidget *text, gpointer data)
4147 gtk_text_freeze (GTK_TEXT (text));
4148 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
4149 "From: pathfinder@nasa.gov\n"
4150 "To: mom@nasa.gov\n"
4151 "Subject: Made it!\n"
4153 "We just got in this morning. The weather has been\n"
4154 "great - clear but cold, and there are lots of fun sights.\n"
4155 "Sojourner says hi. See you soon.\n"
4158 gtk_text_thaw (GTK_TEXT (text));
4161 /* Creiamo un'area di testo scorribile che mostra un "messaggio" */
4167 GtkWidget *hscrollbar;
4168 GtkWidget *vscrollbar;
4170 /*Creiamo una tabella in cui mettere il widget di testo e le barre di scorrimento */
4171 table = gtk_table_new (2, 2, FALSE);
4173 /* Mettiamo un widget di testo nella parte superiore destra. Notate l'uso di
4174 * GTK_SHRINK nella direzione y */
4175 text = gtk_text_new (NULL, NULL);
4176 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
4177 GTK_FILL | GTK_EXPAND,
4178 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
4179 gtk_widget_show (text);
4181 /* Mettiamo una HScrollbar nella parte in basso a sinistra */
4182 hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
4183 gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
4184 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
4185 gtk_widget_show (hscrollbar);
4187 /* Aggiungiamo una VScrollbar in alto a sinistra */
4188 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
4189 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
4190 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
4191 gtk_widget_show (vscrollbar);
4193 /* Aggiungiamo un gestore per mettere un messaggio nel wiget di testo
4195 * viene reaizzato */
4196 gtk_signal_connect (GTK_OBJECT (text), "realize",
4197 GTK_SIGNAL_FUNC (realize_text), NULL);
4203 main (int argc, char *argv[])
4210 gtk_init (&argc, &argv);
4212 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4213 gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
4214 gtk_signal_connect (GTK_OBJECT (window), "destroy",
4215 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
4216 gtk_container_border_width (GTK_CONTAINER (window), 10);
4218 /* Creiamo un widget frazionato verticalmente e aggiungiamolo alla
4220 * finestra di piu' alto livello */
4222 vpaned = gtk_vpaned_new ();
4223 gtk_container_add (GTK_CONTAINER(window), vpaned);
4224 gtk_widget_show (vpaned);
4226 /* Creiamo il contenuto delle de parti della finestra */
4228 list = create_list ();
4229 gtk_paned_add1 (GTK_PANED(vpaned), list);
4230 gtk_widget_show (list);
4232 text = create_text ();
4233 gtk_paned_add2 (GTK_PANED(vpaned), text);
4234 gtk_widget_show (text);
4235 gtk_widget_show (window);
4242 <!-- ----------------------------------------------------------------- -->
4243 <sect1> Cornici ad aspetto fisso (Aspect Frames)
4245 Il widget aspect frame ` analogo al widget "cornice", tranne che per il
4247 fatto che è in grado di forzare le finestre figlie ad avere un certo aspetto,
4249 cioè un certo rapporto fra altezza e larghezza, aggiungendo se necessario
4251 dello spazio in più. Ciò può tornare utile se per esempio
4253 si vuole fare l'anteprima di un'immagine: le dimensioni dell'anteprima devono
4255 variare se l'utente ridimensiona la finestra, ma le proporzioni devono essere
4257 sempre quelle dell'immagine originale.
4259 Per creare una nuova cornice ad aspetto fisso, si usa:
4262 GtkWidget* gtk_aspect_frame_new (const gchar *label,
4269 <tt/xalign/ e <tt/yalign/ specificano l'allineamento come si fa con il widget di
4271 allineamento. Se <tt/obey_child/ è TRUE, le proporzioni di una finestra
4273 figlia saranno le stesse delle misure ideali richieste. In caso contrario, vengono
4275 stabilite da <tt/ratio/.
4278 Per cambiare le opzioni di una finestra esistente, si può usare:
4279 To change the options of an existing aspect frame, you can use:
4282 void gtk_aspect_frame_set (GtkAspectFrame *aspect_frame,
4290 Per fare un esempio, il seguente programma usa un Aspect Frame per rendere
4292 disponibile un'area disegnabile che sia sempre di proporzioni 2:1, in quasiasi
4294 modo l'utente ridimensioni la finestra di base.
4300 #include <gtk/gtk.h>
4303 main (int argc, char *argv[])
4306 GtkWidget *aspect_frame;
4307 GtkWidget *drawing_area;
4308 gtk_init (&argc, &argv);
4310 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4311 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
4312 gtk_signal_connect (GTK_OBJECT (window), "destroy",
4313 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
4314 gtk_container_border_width (GTK_CONTAINER (window), 10);
4316 /* Creiamo aspect_frame e lo mettiamo nella finestra di base */
4318 aspect_frame = gtk_aspect_frame_new ("2x1", /* etichetta */
4319 0.5, /* x del centro */
4320 0.5, /* y del centro */
4321 2, /* xsize/ysize = 2 */
4322 FALSE /* ignora le proporzioni del figlio */);
4324 gtk_container_add (GTK_CONTAINER(window), aspect_frame);
4325 gtk_widget_show (aspect_frame);
4327 /* Aggiungamo un widget figlio alla nostra cornice */
4329 drawing_area = gtk_drawing_area_new ();
4331 /* Chiediamo una finestra 200x200, anche se l'AspectFrame ce ne dara' una
4332 * di 200x100 perche' forziamo l'aspetto 2:1 */
4333 gtk_widget_set_usize (drawing_area, 200, 200);
4334 gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
4335 gtk_widget_show (drawing_area);
4337 gtk_widget_show (window);
4346 <!-- ***************************************************************** -->
4347 <sect> Il Widgets Lista
4348 <!-- ***************************************************************** -->
4350 Il widget GtkList serve come contenitore verticale per altri widget che
4351 devono essere di tipo GtkListItem.
4353 Un widget GtkList possiede una sua propria finestra per ricevere eventi
4354 e un suo proprio colore di sfondo che di solito è bianco. Dal momento
4355 che è direttamente derivato dal widget GtkContainer, può essere trattato
4356 come tale usando la macro GTK_CONTAINER(List); si veda il widget GtkContainer
4357 per ulteriori dettagli.
4358 Per usare il widget GtkList in tutte le sue potenzialità, si dovrebbe essere
4359 già familiari con l'uso della GList e delle relative funzioni g_list_*().
4361 All'interno della definizione della struttura del widget GtkList c'è un
4362 campo che sarà per noi di grande interesse, cioè:
4369 guint selection_mode;
4374 Il campo ``selection'' in un GtkList punta a una lista collegata di tutti
4375 gli elementi che sono selezionati correntemente, oppure a NULL se la
4376 selezione è vuota. Quindi, per avere informazioni sulla selezione corrente,
4377 leggiamo il campo GTK_LIST()->selection, senza però modificarlo dal momento
4378 che i campi interni debbono essere gestiti dalle funzioni gtk_list_*().
4380 Le modalità di selezione in una GtkList, e quindi il contenuto di
4381 GTK_LIST()->selection, sono determinate dal campo selection_mode:
4383 selection_mode può assumere uno dei seguenti valori:
4385 <item> GTK_SELECTION_SINGLE - La selezione può essere o NULL oppure
4386 un puntatore GList* per un singolo elemento
4389 <item> GTK_SELECTION_BROWSE - La selezione è null se la lista non contiene
4390 alcun widget o se ha solo widget non sensibili,
4391 oppure può contenere un puntatore a una struttura
4392 GList, e quindi esattamente un elemento di lista.
4394 <item> GTK_SELECTION_MULTIPLE - La selezione è ``NULL'' se non è selezionato
4395 alcun elemento di lista, oppure un puntatore GList al
4396 primo elemento selezionato. Quello, a sua volta, punta
4397 a una struttura GList per il secondo elemento selezionato
4400 <item> GTK_SELECTION_EXTENDED - La selezione è sempre NULL.
4403 Il valore per difetto è GTK_SELECTION_MULTIPLE.
4405 <!-- ----------------------------------------------------------------- -->
4409 void selection_changed (GtkList *LIST)
4412 Questo segnale verrà invocato ogni volta che il campo di
4413 selezione di una GtkList è cambiato. Questo accade quando
4414 un figlio della GtkList viene selezionato o deselezionato.
4417 void select_child (GtkList *LIST, GtkWidget *CHILD)
4420 Questo segnale viene invocato quando un fuglio di una GtkList
4421 sta per essere selezionato. Questo accade principalmente in
4422 occasione di chiamate a gtk_list_select_item() e gtk_list_select_child(),
4423 di pressioni di bottoni e a volte può venir fatto scattare indirettamente
4424 in altre occasioni, in cui vengono aggiunti o rimossi dei figli
4428 void unselect_child (GtkList *LIST, GtkWidget *CHILD)
4431 Questo segnale viene invocato quando un figlio della GtkList sta
4432 per essere deselezionato. Ciò accade principalmente in occasione
4433 di chiamate a gtk_list_unselect_item() e gtk_list_unselect_child(),
4434 di pressioni di bottoni, e a volte può venir fatto scattare indirettamente
4435 in altre occasioni, in cui vengono aggiunti o rimossi dei figli
4438 <!-- ----------------------------------------------------------------- -->
4442 guint gtk_list_get_type (void)
4445 Restituisce l'identificatore di tipo `GtkList'.
4448 GtkWidget* gtk_list_new (void)
4451 Crea un nuovo oggetto `GtkList'. Il nuovo widget viene
4452 restituito sotto forma di un puntoatore ad un oggetto
4453 `GtkWidgetì'. In caso di fallimento, viene ritornato NULL.
4456 void gtk_list_insert_items (GtkList *LIST, GList *ITEMS, gint POSITION)
4459 Inserisce degli elementi di lista nella LIST, a partire da
4460 POSITION. ITEMS ITEMS è una lista doppiamente collegata, in
4461 cui ci si aspetta che i puntatori di ogni nodo puntino a
4462 un GtkListItem appena creato. I nodi GList di ITEMS vengono
4466 void gtk_list_append_items (GtkList *LIST, GList *ITEMS)
4469 Inserisce elementi di lista proprio come gtk_list_insert_items(),
4470 ma alla fine della LIST. I nodi GList di ITEMS vengono
4474 void gtk_list_prepend_items (GtkList *LIST, GList *ITEMS)
4477 Inserisce elementi di lista proprio come gtk_list_insert_items(),
4478 ma al principio della LIST. I nodi GList di ITEMS vengono
4482 void gtk_list_remove_items (GtkList *LIST, GList *ITEMS)
4485 Rimuove degli elementi di lista dalla LIST. ITEMS è una lista
4486 doppiamente collegata in cui ci si aspetta che i puntatori di
4487 ogni nodo puntino a un figlio diretto di LIST. E' poi responsabilità
4488 del chiamante di fare una chiamata a g_list_free(ITEMS). E' anche
4489 necessario che il chiamante distrugga lui stesso gli elementi della
4493 void gtk_list_clear_items (GtkList *LIST, gint START, gint END)
4496 Rimuove e distrugge elementi di lista da LIST. Un widget ne è
4497 interessato se la sua posizione corrente all'interno di LIST è compreso
4501 void gtk_list_select_item (GtkList *LIST, gint ITEM)
4504 Invoca il segnale select_child per un elemento di lista
4505 specificato dalla sua posizione corrente all'interno di LIST.
4508 void gtk_list_unselect_item (GtkList *LIST, gint ITEM)
4511 Invoca il segnale unselect_child per un elemento di lista
4512 specificato dalla sua posizione corrente all'interno di LIST.
4515 void gtk_list_select_child (GtkList *LIST, GtkWidget *CHILD)
4518 Invoca il segnale select_child per uno specifico CHILD.
4521 void gtk_list_unselect_child (GtkList *LIST, GtkWidget *CHILD)
4524 Invoca il segnale unselect_child per uno specifico CHILD.
4527 gint gtk_list_child_position (GtkList *LIST, GtkWidget *CHILD)
4530 Restituisce la posizione di CHILD all'interno di LIST. In caso di fallimento,
4531 viene restituito `-1'.
4534 void gtk_list_set_selection_mode (GtkList *LIST, GtkSelectionMode MODE)
4537 Assegna a LIST il modo di selezione MODE, che può essere uno fra
4538 GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE o
4539 GTK_SELECTION_EXTENDED.
4542 GtkList* GTK_LIST (gpointer OBJ)
4545 Fa il cast di un generico puntatore a `GtkList*'. Per maggiori
4546 informazioni vedere Standard Macros::.
4549 GtkListClass* GTK_LIST_CLASS (gpointer CLASS)
4552 Fa il cast di un generico puntatore a `GtkListClass*'. Per maggiori
4553 informazioni vedere Standard Macros::.
4556 gint GTK_IS_LIST (gpointer OBJ)
4559 Determina se un generico puntatore si riferisce ad un oggetto `GtkList'.
4560 Per maggiori informazioni vedere Standard Macros::.
4562 <!-- ----------------------------------------------------------------- -->
4565 Diamo di seguito un programma di esempio che stamperà i campbiamenti
4566 della selezione di una GtkList, e vi lascia ``imprigionare'' gli elementi
4567 di una lista selezionandoli con il pulsante destro del mouse:
4572 /* includiamo i file header di gtk+
4573 * includiamo stdio.h, ne abbiamo bisogno per printf()
4575 #include <gtk/gtk.h>
4578 /* Questa e' la nostra stringa di identificazione dei dati per assegnarli
4579 * ad elementi di lista
4581 const gchar *list_item_data_key="list_item_data";
4584 /* prototipi per i gestori di segnale che connetteremo
4587 static void sigh_print_selection (GtkWidget *gtklist,
4588 gpointer func_data);
4589 static void sigh_button_event (GtkWidget *gtklist,
4590 GdkEventButton *event,
4594 /* funzione main per predisporre l'interfaccia utente */
4596 gint main (int argc, gchar *argv[])
4598 GtkWidget *separator;
4601 GtkWidget *scrolled_window;
4605 GtkWidget *list_item;
4611 /* inizializza gtk+ (e di conseguenza gdk) */
4613 gtk_init(&argc, &argv);
4616 /* crea una finestra in cui mettere tutti i widget
4617 * connette gtk_main_quit() al segnale "destroy" della finestra
4618 * per gestire le richieste di chiusura finestra del window manager
4620 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
4621 gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
4622 gtk_signal_connect(GTK_OBJECT(window),
4624 GTK_SIGNAL_FUNC(gtk_main_quit),
4628 /* all'interno della finestra abbiamo bisogno di una scatola
4629 * in cui mettere i widget verticalmente */
4630 vbox=gtk_vbox_new(FALSE, 5);
4631 gtk_container_border_width(GTK_CONTAINER(vbox), 5);
4632 gtk_container_add(GTK_CONTAINER(window), vbox);
4633 gtk_widget_show(vbox);
4635 /* questa è la finestra scorribile in cui mettere il widget GtkList */
4636 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
4637 gtk_widget_set_usize(scrolled_window, 250, 150);
4638 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
4639 gtk_widget_show(scrolled_window);
4641 /* crea il widget GtkList
4642 * connette il gestore di segnale sigh_print_selection()
4643 * al segnale "selection_changed" della GtkList, per stampare
4644 * gli elementi selezionati ogni volta che la selezione cambia
4646 gtklist=gtk_list_new();
4647 gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
4648 gtk_widget_show(gtklist);
4649 gtk_signal_connect(GTK_OBJECT(gtklist),
4650 "selection_changed",
4651 GTK_SIGNAL_FUNC(sigh_print_selection),
4654 /* creiamo una "Prigione" (Prison) in cui mettere gli elementi di lista ;)
4656 frame=gtk_frame_new("Prison");
4657 gtk_widget_set_usize(frame, 200, 50);
4658 gtk_container_border_width(GTK_CONTAINER(frame), 5);
4659 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
4660 gtk_container_add(GTK_CONTAINER(vbox), frame);
4661 gtk_widget_show(frame);
4663 /* connette il gestore di segnale sigh_button_event() alla GtkList
4664 * il quale gestira' l'"imprigionamento" degli elementi di lista
4666 gtk_signal_connect(GTK_OBJECT(gtklist),
4667 "button_release_event",
4668 GTK_SIGNAL_FUNC(sigh_button_event),
4671 /* crea un separatore
4673 separator=gtk_hseparator_new();
4674 gtk_container_add(GTK_CONTAINER(vbox), separator);
4675 gtk_widget_show(separator);
4677 /* infine creiamo un bottone e connettiamone il segnale "clicked"
4678 * alla distruzione della finestra
4680 button=gtk_button_new_with_label("Close");
4681 gtk_container_add(GTK_CONTAINER(vbox), button);
4682 gtk_widget_show(button);
4683 gtk_signal_connect_object(GTK_OBJECT(button),
4685 GTK_SIGNAL_FUNC(gtk_widget_destroy),
4686 GTK_OBJECT(window));
4689 /* a questo punto creiamo 5 elementi di lista, ognuno con la
4690 * propria etichetta, e li aggiungiamo alla GtkList usando
4691 * gtk_container_add(). Inoltre, recuperiamo la stringa di testo
4692 * dall'etichetta e la associamo, per ogni elemento, a
4693 * list_item_data_key
4695 for (i=0; i<5; i++) {
4699 sprintf(buffer, "ListItemContainer with Label #%d", i);
4700 label=gtk_label_new(buffer);
4701 list_item=gtk_list_item_new();
4702 gtk_container_add(GTK_CONTAINER(list_item), label);
4703 gtk_widget_show(label);
4704 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
4705 gtk_widget_show(list_item);
4706 gtk_label_get(GTK_LABEL(label), &string);
4707 gtk_object_set_data(GTK_OBJECT(list_item),
4712 /* qui creiamo altre 5 etichette, questa volta usando
4713 * per la creazione gtk_list_item_new_with_label().
4714 * Non possiamo recuperare la stringa di testo dall'etichetta
4715 * dal momento che non disponiamo di puntatori alle etichette,
4716 * quindi associamo semplicemente il list_item_data_key di ogni
4717 * elemento di lista con la medesima stringa di testo.
4718 * Per aggiungere elementi di lista, li mettiamo tutti in una lista
4719 * doppiamente collegata (GList), e quindi li aggiungiamo con una
4720 * unica chiamata a gtk_list_append_items().
4721 * Dal momento che usiamo g_list_prepend() per mettere gli elementi
4722 * nella lista doppiamente collegata, il loro ordine sara' discendente
4723 * (invece che ascendente come sarebbe se usassimo g_list_append())
4727 sprintf(buffer, "List Item with Label %d", i);
4728 list_item=gtk_list_item_new_with_label(buffer);
4729 dlist=g_list_prepend(dlist, list_item);
4730 gtk_widget_show(list_item);
4731 gtk_object_set_data(GTK_OBJECT(list_item),
4733 "ListItem with integrated Label");
4735 gtk_list_append_items(GTK_LIST(gtklist), dlist);
4737 /* e finalmente vogliamo vedere la finestra, non e' vero? ;)
4739 gtk_widget_show(window);
4741 /* lancia il ciclo principale di gtk
4745 /* si arriva a questo punto dopo la chiamata di gtk_main_quit(),
4746 * il che accade quando viene distrutta la finestra principale
4751 /* questo e' il gestore di segnale che e' stato connesso all'evento di
4752 * pressione/rilascio del bottone della GtkList
4755 sigh_button_event (GtkWidget *gtklist,
4756 GdkEventButton *event,
4759 /* facciamo qualcosa solo nel caso di rilascio del terzo bottone
4760 * (quello piu' a destra)
4762 if (event->type==GDK_BUTTON_RELEASE &&
4764 GList *dlist, *free_list;
4765 GtkWidget *new_prisoner;
4767 /* recuperiamo l'elemento di lista selezionato correntemente,
4768 * che sara' il nostro prossimo prigioniero ;)
4770 dlist=GTK_LIST(gtklist)->selection;
4772 new_prisoner=GTK_WIDGET(dlist->data);
4776 /* cerchiamo elementi di lista gia' imprigionati,
4777 * li rimetteremo nella lista.
4778 * Ricordare di liberare la lista doppiamente collegata
4779 * che viene restituita da gtk_container_children()
4781 dlist=gtk_container_children(GTK_CONTAINER(frame));
4784 GtkWidget *list_item;
4786 list_item=dlist->data;
4788 gtk_widget_reparent(list_item, gtklist);
4792 g_list_free(free_list);
4794 /* se abbiamo un nuovo prigioniero, lo rimuoviamo
4795 * dalla GtkList e lo mettiamo nella cornice della
4796 * "Prigione". Dobbiamo prima deselezionare l'elemento
4801 static_dlist.data=new_prisoner;
4802 static_dlist.next=NULL;
4803 static_dlist.prev=NULL;
4805 gtk_list_unselect_child(GTK_LIST(gtklist),
4807 gtk_widget_reparent(new_prisoner, frame);
4812 /* questo e' il gestore di segnaleche viene chiamato de la
4813 * GtkList emette il segnale "selection_changed"
4816 sigh_print_selection (GtkWidget *gtklist,
4821 /* recuperiamo la lista doppiamente collegata degli
4822 * elementi selezionati della GtkList, ricordate di
4823 * trattarla come sola lettura
4825 dlist=GTK_LIST(gtklist)->selection;
4827 /* se non ci sono elementi selezionati non c'e' altro da
4828 * fare che dirlo all'utente
4831 g_print("Selection cleared\n");
4834 /* ok, abbiamo una selezione e quindi lo scriviamo
4836 g_print("The selection is a ");
4838 /* ottieniamo l'elemento di lista dalla lista doppiamente
4839 * collegata e poi richiediamo i dati associati con
4840 * list_item_data_key. Poi semplicemente li stampiamo
4843 GtkObject *list_item;
4844 gchar *item_data_string;
4846 list_item=GTK_OBJECT(dlist->data);
4847 item_data_string=gtk_object_get_data(list_item,
4848 list_item_data_key);
4849 g_print("%s ", item_data_string);
4857 <!-- ----------------------------------------------------------------- -->
4858 <sect1> Il Widget Elemento di Lista (List Item)
4860 Il widget GtkListItem è progettato allo scopo di essere un contenitore
4861 collegato ad un figlio, per fornire le funzioni per la selezione e deselezione
4862 allo stesso modo in cui il widget GtkList ne ha bisogno per i propri figli.
4864 Un GtkListItem ha la sua propria finestra per ricevere eventi, e ha il suo
4865 proprio colore di sfondo, che di solito è bianco.
4867 Dal momento che questo widget deriva direttamente da GtkItem, può essere
4868 trattato come tale usando la macro GTK_ITEM(ListItem), vedere il widget
4869 GtkItem per ulteriori informazioni.
4870 Di solito un GtkListItem ha solo un'etichetta per identificare per esempio
4871 un nome di file all'interno di una GtkList -- per cui viene fornita la
4872 funzione appropriata gtk_list_item_new_with_label(). Si può ottenere lo
4873 stesso effetto creando una GtkLabel da sola, assegnando al suo allineamento
4874 i valori xalign=0 e yalign=0.5, aggiungendo successivamente un contenitore
4877 Dal momento che non si è obbligati a mettere una GtkLabel, si può anche
4878 aggiungere una GtkVBox una GtkArrow ecc. alla GtkListItem.
4881 <!-- ----------------------------------------------------------------- -->
4884 Un GtkListItem non crea alcun nuovo segnale di per se, ma eredita
4885 i segnali di GtkItem. Per ulteriori informazioni, vedere GtkItem::.
4887 <!-- ----------------------------------------------------------------- -->
4892 guint gtk_list_item_get_type (void)
4895 Restituisce l'identificatore di tipo `GtkListItem'.
4898 GtkWidget* gtk_list_item_new (void)
4901 Crea un nuovo oggetto `GtkListItem'. Il nuovo widget viene restituito
4902 sottoforma di un puntatore ad un oggetto `GtkWidget'. In caso di
4903 fallimento, viene restituito `NULL'.
4906 GtkWidget* gtk_list_item_new_with_label (gchar *LABEL)
4909 Cre un nuovo oggetto `GtkListItem', avente come unico figlio
4910 un GtkLabel. Il nuovo widget viene restituito
4911 sottoforma di un puntatore ad un oggetto `GtkWidget'. In caso di
4912 fallimento, viene restituito `NULL'.
4915 void gtk_list_item_select (GtkListItem *LIST_ITEM)
4918 Questa funzione è essenzialmente un wrapper per una chiamata a
4919 gtk_item_select (GTK_ITEM (list_item)) che emetterà il segnale
4921 Vedere GtkItem:: per maggiori informazioni.
4924 void gtk_list_item_deselect (GtkListItem *LIST_ITEM)
4927 Questa funzione è essenzialmente un wrapper per una chiamata a
4928 gtk_item_deselect (GTK_ITEM (list_item)) che emetterà il segnale
4930 Vedere GtkItem:: per maggiori informazioni.
4933 GtkListItem* GTK_LIST_ITEM (gpointer OBJ)
4936 Effettua il cast di un puntatore generico a `GtkListItem*'. Vedere
4937 Standard Macros:: per maggiorni informazioni.
4940 GtkListItemClass* GTK_LIST_ITEM_CLASS (gpointer CLASS)
4943 Effettua il cast di un puntatore generico a `GtkListItemClass*'. Vedere
4944 Standard Macros:: per maggiorni informazioni.
4947 gint GTK_IS_LIST_ITEM (gpointer OBJ)
4950 Determina se un puntatore generico si riferisce ad un oggetto
4951 `GtkListItem'. Vedere Standard Macros:: per maggiorni informazioni.
4953 <!-- ----------------------------------------------------------------- -->
4956 Come esempio su questo argomento, si veda quello relativo alla GtkList,
4957 che riguarda anche l'uso del GtkListItem.
4959 <!-- ***************************************************************** -->
4960 <sect>Il Widget Menù (Menu Widgets)
4961 <!-- ***************************************************************** -->
4963 Ci sono due modi per creare dei menù, quello facile e quello difficile.
4964 Ognuno è più adatto per certe circostanze, ma di solito si può usare il
4965 modo semplice, cioé menu_factory (la ``fabbrica dei menù''). Il modo
4966 ``difficile'' è di crearsi tutti i menù usando direttamente le chiamate.
4967 Quello semplice è di usare le chiamate di tipo gtk_menu_factory. Anche se
4968 è un modo molto più semplice, ci sono svantaggi e vantaggi per ciascuno
4971 La menu_factory è molto più semplice da usare e per aggiungere dei nuovi
4972 menù, anche se scriversi un po' di funzioni per creare dei menù con il
4973 metodo manuale può dare risultati molto migliori dal punto di vista
4974 dell'usabilità. Con la menufactory, non è possibile mettere immagini o
4975 caratteri '/' nei menù.
4977 <!-- ----------------------------------------------------------------- -->
4978 <sect1>Creazione Manuale di Menù
4980 Seguendo la tradizionale arte dell'insegnamento, partiamo dal modo
4981 difficile. <tt>:)</>
4983 I widget che hanno a che fare con la creazione di una barra di menù e di sottomenù sono tre:
4985 <item>un elemento di menù, che ` quello che l'utente poi selezionerà, per esempio 'Salva'
4986 <item>un menù, che fa la parte di contenitore per gli elementi di menù, e
4987 <item>una barra dei menù, che è un contenitore per ciascuno dei menù
4991 La cosa viene un po' complicata dal fatto che i widget elemento di menù vngono usati per
4993 due scopi diversi. Essi sono sia i widget che vengono impacchettati nei menù, che
4995 quelli che vengono impacchettati nella barra dei menù che, quando selezonati, attivano i menù.
4997 Diamo un'occhiata alle funzioni usate per creare i menù e le barre di menù.
4998 Con questa prima funzione si crea un nuova barra di menù:
5002 GtkWidget *gtk_menu_bar_new(void);
5005 Questa funzione crea una nuova barra di menù. Per impacchettarla in una
5006 finestra o si usa la funzione gtk_container_add, oppure, per impacchettarla
5007 in una scatola, le funzioni box_pack - come con i bottoni.
5010 GtkWidget *gtk_menu_new();
5013 Questa funzione restituisce un puntatore ad un nuovo menù, non viene mai
5014 realmente mostrato (con gtk_widget_show), serve solo per contenere gli
5015 elementi del menù. Spero che il tutto risulti più chiaro quando daremo
5016 un'occhiata all'esempio più sotto.
5018 Le prossime due chiamate sono usate per creare degli elementi che poi
5019 vengono impacchettati nei menù e nelle barre dei menù..
5022 GtkWidget *gtk_menu_item_new();
5028 GtkWidget *gtk_menu_item_new_with_label(const char *label);
5031 Queste chiamate sono usate per creare gli elementi di menù che devono poi essere mostrati.
5032 Ricordate la differenza che esiste fra un ``menù'' come quelli creati con
5033 gtk_menu_new e un ``elemento di menù'' (menu item) come quelli creati con
5034 la funzione gtk_menu_item_new. L'elemento di menù sarà un bottone
5035 vero e proprio con una azione associata, mentre un menù è solo un contenitore che li raccoglie.
5036 Le funzioni gtk_menu_new_with_label e gtk_menu_new sono esattamente come vi aspettereste che siano dopo
5038 aver conosciuto i bottoni. Una crea un nuovo elemento di menù con un'etichetta già impacchettata,
5040 mentre l'altra crea un elemento di menù vuoto.
5043 Una volta che si ` creato un elemento di menù, è necessario piazzarlo su di un menù.
5045 Per fare ciò si usa la funzione gtk_menu_append. Per determinare quando l'utente ha selezionato un elemento, abbiamo bisogno di connettere il segnale <tt/activate/ nel solito modo.
5047 Quindi, se volessimo creare un normale menù <tt/File/, con le opzioni <tt/Open/, <tt/Save/ e <tt/Quit/, il codice avrebbe più o meno il seguente aspetto:
5050 file_menu = gtk_menu_new(); /* Non e' necessario mostrare i menu' */
5052 /* Creiamo gli elementi del menu' */
5053 open_item = gtk_menu_item_new_with_label("Open");
5054 save_item = gtk_menu_item_new_with_label("Save");
5055 quit_item = gtk_menu_item_new_with_label("Quit");
5057 /* Aggiungiamoli al menu' */
5058 gtk_menu_append( GTK_MENU(file_menu), open_item);
5059 gtk_menu_append( GTK_MENU(file_menu), save_item);
5060 gtk_menu_append( GTK_MENU(file_menu), quit_item);
5063 /* Colleghiamo le funzioni di callback al segnale activate */
5064 gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
5065 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
5066 gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
5067 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
5069 /* Possiamo collegare l'elemento Quit alla nostra funzione di uscita */
5070 gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
5071 GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
5073 /* Abbiamo bisogno di mostrare gli elementi di menu' */
5074 gtk_widget_show( open_item );
5075 gtk_widget_show( save_item );
5076 gtk_widget_show( quit_item );
5080 A questo punto abbiamo il nostro menù Adesso abbiamo bisogno di creare una barra dei menù
5082 e un elemento di menù per <tt/File/, a cui aggiungeremo il nostro menù. Il codice è questo:
5086 menu_bar = gtk_menu_bar_new();
5087 gtk_container_add( GTK_CONTAINER(window), menu_bar);
5088 gtk_widget_show( menu_bar );
5090 file_item = gtk_menu_item_new_with_label("File");
5091 gtk_widget_show(file_item);
5095 Ora dobbiamo associare il menù con <tt/file_item/. Lo si può fare con la funzione
5098 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
5099 GtkWidget *submenu);
5103 Quindi, il nostro esempio continuerebbe con
5106 gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu);
5110 Ciò che manca a questo punto è di collegare il menù alla barra, cosa che si può ottenere tramite la funzione
5113 void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
5116 che nel nostro caso è:
5119 gtk_menu_bar_append( GTK_MENU_BAR(menu_bar), file_item );
5123 Se volessimo il menù giustificato a dstra, come sono spesso i menù di aiuto, potremm
5125 usare la seguente funzioe (di nuovo su <tt/file_item/ in questo esempio) prima di fare il collegamento alla barra.
5129 void gtk_menu_item_right_justify (GtkMenuItem *menu_item);
5131 Ecco un riassunto dei passi necessari per creare una barra con i relativi menù collegati:
5134 <item> Create un nuovo menù con gtk_menu_new()
5135 <item> Usate delle chiamate multiple a gtk_menu_item_new() per ognuno degli
5136 elementi che volete mettere nel vostro menù. Usate inoltre gtk_menu_item_append()
5137 per mettere ciascuno di questi nuovi elementi sul menù..
5138 <item> Create un elemento di menù usando gtk_menu_item_new(). Questo rappresenta l'elemento di base
5140 delmenù, e il testo relativo sarà il testo mostrato sulla barra dei menù stessa.
5142 <item> Usate gtk_menu_item_set_submenu() per collegare i menù all'elemento base del menù (cioè quello creato al passaggio precedente).
5144 <item> Create una nuova barra di menù usando gtk_menu_bar_new. Questo passo
5145 necessita di essere effettuato una sola volta quando si crea una serie di
5146 menù su una sola barra.
5147 <item> Usate gtk_menu_bar_append per mettere il menù base sulla barra dei menù.
5150 Creare un menù a comparsa è più o meno la stessa cosa. La differenza è che il
5151 il menù non viene attivato ``automaticamente'' da una barra, bensì per esempio
5152 con la chiamata espicita alla funzione gtk_menu_popup() da parte di un evento di pressione di un pulsante.
5153 Seguite questi passaggi:
5155 <item>Create una funzione di gestione di un evento. Essa deve seguire il prototipo
5157 static gint handler(GtkWidget *widget, GdkEvent *event);
5159 e usare l'evento per scoprire dove il menu deve essere fatto comparire.
5160 <item>Nel gestore di evento, se questo è la pressione di un bottone, trattate
5161 <tt>event</tt> come l'evento relativo ad un bottone (cosa che in effetti è)
5162 e usatelo come mostrato nel codice di esempio per passare informazioni a
5164 <item>Collegate il gestore di evento a un widget con
5166 gtk_signal_connect_object(GTK_OBJECT(widget), "event",
5167 GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
5169 in cui <tt>widget</tt> è il widget a cui state effettuando il collegamento, e
5170 <tt>handler</tt> è la funzione di gestione, mentre <tt>menu</tt> è un menù
5171 creato con gtk_menu_new(). Quest'ultimo può essere un menù che viene anche
5172 attivato da una barra di menù, come mostrato nel codice di esempio.
5176 <!-- ----------------------------------------------------------------- -->
5177 <sect1>Esempio di Menù Manuale
5179 Per la teoria dovrebbe essere abbastanza. Diamo un'occhiata ad un esempio che
5180 ci aiuti a chiarire le cose.
5184 #include <gtk/gtk.h>
5186 static gint button_press (GtkWidget *, GdkEvent *);
5187 static void menuitem_response (gchar *);
5189 int main (int argc, char *argv[])
5194 GtkWidget *menu_bar;
5195 GtkWidget *root_menu;
5196 GtkWidget *menu_items;
5202 gtk_init (&argc, &argv);
5204 /* crea una nuova finestra */
5205 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
5206 gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
5208 gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
5209 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
5210 (GtkSignalFunc) gtk_main_quit, NULL);
5212 /* Inizializziamo il menù, e ricordate: mai applicare
5213 * gtk_show_widget() al widget menù!!
5214 * Questo è il menù che contiene gli elementi, quello che
5215 * spunta quando si fa click sul "Menù radice" nell'applicazione */
5216 menu = gtk_menu_new();
5218 /* Ora creiamo un ciclo che crea tre elementi di menu per "test-menu".
5219 * Notete la chiamata a gtk_menu_append. In questo punto aggiungiamo una
5220 * lista di elementi al nostro menù. Normalmente, dovremmo poi catturare
5221 * il segnale di attivazione per ognuno degli elementi del menu, e creare
5222 * una funzione di ritorno per ciascuno di essi, ma qui non li mettiamo per
5223 * brevità. */
5225 for(i = 0; i < 3; i++)
5227 /* Copia i nomi in buf. */
5228 sprintf(buf, "Test-undermenu - %d", i);
5230 /* Crea un nuovo elemento di menù con un nome... */
5231 menu_items = gtk_menu_item_new_with_label(buf);
5233 /* ...e aggiungilo al menù. */
5234 gtk_menu_append(GTK_MENU (menu), menu_items);
5236 /* Fa qualcosa di interessante quando si seleziona l'elemento */
5237 gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
5238 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
5240 /* Mostra il widget */
5241 gtk_widget_show(menu_items);
5244 /* Questo è il menù radice, e l'etichetta sarà il nome del menù che
5245 * verrà mostrato sulla barra dei menù. Non ci sarà alcun gestore di
5246 * segnale collegato, dal momento che non fa altro che mostrare il resto
5247 * del menù quando viene premuto. */
5248 root_menu = gtk_menu_item_new_with_label("Root Menu");
5250 gtk_widget_show(root_menu);
5255 /* Ora specifichiamo che vogliamo che il menù che abbiamo appena creato
5256 * sia il menù radice *//
5257 gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
5259 /* Una vbox in cui mettere un menù ed un bottone: */
5260 vbox = gtk_vbox_new(FALSE, 0);
5261 gtk_container_add(GTK_CONTAINER(window), vbox);
5262 gtk_widget_show(vbox);
5264 /* Crea una barra dei menù per metterci i menù e l'aggiunge alla finestra principale */
5265 menu_bar = gtk_menu_bar_new();
5266 gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
5267 gtk_widget_show(menu_bar);
5269 /* Crea un bottone a cui collegare un menù */
5270 button = gtk_button_new_with_label("press me");
5271 gtk_signal_connect_object(GTK_OBJECT(button), "event",
5272 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
5273 gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
5274 gtk_widget_show(button);
5276 /* E finalmente attacchiamo l'elemento di menù alla barra dei menù -- questo
5277 * è l'elemento di menù "radice" di cui parlavo */
5278 gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
5280 /* La finestra va mostrata sempre come ultimo passo in modo che sia già
5281 * completa di tutti i suoi elementi. */
5282 gtk_widget_show(window);
5291 /* Risponde alla pressione di un bottone impostando un menù che
5292 * viene passato come widget.
5293 * Notate che l'argomento "widget" si riferisce al menù impostato
5294 * e NON al bottone premuto.
5297 static gint button_press (GtkWidget *widget, GdkEvent *event)
5300 if (event->type == GDK_BUTTON_PRESS) {
5301 GdkEventButton *bevent = (GdkEventButton *) event;
5302 gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
5303 bevent->button, bevent->time);
5304 /* Riferisce al codice chiamante che abbiamo trattato l'evento;
5305 * la faccenda finisce qui. */
5309 /* Riferisce al codice chiamante che abbiamo trattato l'evento; passa avanti. */
5314 /* Stampa una stringa quando viene selezionato un elemento di menù */
5316 static void menuitem_response (gchar *string)
5318 printf("%s\n", string);
5322 Si può anche fare in modo che un elemento di menù sia insensibile e, usando
5323 una tabella di acelleratori, collegare dei tasti a delle funzioni di menù.
5326 <!-- ----------------------------------------------------------------- -->
5327 <sect1>Usare GtkMenuFactory
5329 Ora che vi abbiamo mostrato il modo difficile, ecco invece come si fa usando
5330 le chiamate di gtk_menu_factory.
5333 <!-- ----------------------------------------------------------------- -->
5334 <sect1>Esempio di Menu Factory
5336 Ecco un esempio di utilizzo della ``Fabbrica'' di Menù di GTK (Menu Factory).
5337 Questo è il primo file, menufactoy.h. Teniemo dei file menufactory.c e main.c separati
5338 a causa delle variabili globali usate nel file menufactory.c.
5344 #ifndef __MENUFACTORY_H__
5345 #define __MENUFACTORY_H__
5349 #endif /* __cplusplus */
5351 void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
5352 void menus_create(GtkMenuEntry *entries, int nmenu_entries);
5356 #endif /* __cplusplus */
5358 #endif /* __MENUFACTORY_H__ */
5362 Ed ecco il file menufactory.c.
5366 #include <gtk/gtk.h>
5367 #include <strings.h>
5371 static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
5372 static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
5373 void menus_init(void);
5374 void menus_create(GtkMenuEntry * entries, int nmenu_entries);
5376 /* Questa è la struttuta GtkMenuEntry, che viene usata per creare dei nuovi
5377 * menù. Il primo membro à la stringa di definizione del menù. Il secondo
5378 * è il tasto acceleratore predefinito, usato per accedere a questa funzione
5379 * con la tastiera. Il terzo è la funzione di ritorno che viene chiamata
5380 * quando si seleziona con la tastiera o il mouse questo elemento di menù.
5381 * L'ultimo membro costituisce il dato che viene passato alla funzione di
5384 static GtkMenuEntry menu_items[] =
5386 {"<Main>/File/New", "<control>N", NULL, NULL},
5387 {"<Main>/File/Open", "<control>O", NULL, NULL},
5388 {"<Main>/File/Save", "<control>S", NULL, NULL},
5389 {"<Main>/File/Save as", NULL, NULL, NULL},
5390 {"<Main>/File/<separator>", NULL, NULL, NULL},
5391 {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
5392 {"<Main>/Options/Test", NULL, NULL, NULL}
5395 /* calcola il numero di menu_item */
5396 static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
5398 static int initialize = TRUE;
5399 static GtkMenuFactory *factory = NULL;
5400 static GtkMenuFactory *subfactory[1];
5401 static GHashTable *entry_ht = NULL;
5403 void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
5409 *menubar = subfactory[0]->widget;
5411 *table = subfactory[0]->table;
5414 void menus_init(void)
5419 factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
5420 subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
5422 gtk_menu_factory_add_subfactory(factory, subfactory[0], "<Main>");
5423 menus_create(menu_items, nmenu_items);
5427 void menus_create(GtkMenuEntry * entries, int nmenu_entries)
5436 for (i = 0; i < nmenu_entries; i++) {
5437 accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
5439 if (accelerator[0] == '\0')
5440 entries[i].accelerator = NULL;
5442 entries[i].accelerator = accelerator;
5445 gtk_menu_factory_add_entries(factory, entries, nmenu_entries);
5447 for (i = 0; i < nmenu_entries; i++)
5448 if (entries[i].widget) {
5449 gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator",
5450 (GtkSignalFunc) menus_install_accel,
5452 gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator",
5453 (GtkSignalFunc) menus_remove_accel,
5458 static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
5464 if (modifiers & GDK_CONTROL_MASK)
5465 strcat(accel, "<control>");
5466 if (modifiers & GDK_SHIFT_MASK)
5467 strcat(accel, "<shift>");
5468 if (modifiers & GDK_MOD1_MASK)
5469 strcat(accel, "<alt>");
5476 t1 = g_hash_table_lookup(entry_ht, path);
5479 entry_ht = g_hash_table_new(g_str_hash, g_str_equal);
5481 g_hash_table_insert(entry_ht, path, g_strdup(accel));
5486 static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
5491 t = g_hash_table_lookup(entry_ht, path);
5494 g_hash_table_insert(entry_ht, path, g_strdup(""));
5498 void menus_set_sensitive(char *path, int sensitive)
5500 GtkMenuPath *menu_path;
5505 menu_path = gtk_menu_factory_find(factory, path);
5507 gtk_widget_set_sensitive(menu_path->widget, sensitive);
5509 g_warning("Impossibile assegnare sensibilità a menù inesistente: %s", path);
5521 #ifndef __MFMAIN_H__
5522 #define __MFMAIN_H__
5526 #endif /* __cplusplus */
5528 void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
5532 #endif /* __cplusplus */
5534 #endif /* __MFMAIN_H__ */
5545 #include <gtk/gtk.h>
5548 #include "menufactory.h"
5551 int main(int argc, char *argv[])
5554 GtkWidget *main_vbox;
5557 GtkAcceleratorTable *accel;
5559 gtk_init(&argc, &argv);
5561 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
5562 gtk_signal_connect(GTK_OBJECT(window), "destroy",
5563 GTK_SIGNAL_FUNC(file_quit_cmd_callback),
5565 gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
5566 gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
5568 main_vbox = gtk_vbox_new(FALSE, 1);
5569 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
5570 gtk_container_add(GTK_CONTAINER(window), main_vbox);
5571 gtk_widget_show(main_vbox);
5573 get_main_menu(&menubar, &accel);
5574 gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
5575 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
5576 gtk_widget_show(menubar);
5578 gtk_widget_show(window);
5584 /* Questo è per mostrare come si usano le funzioni di ritorno quando
5585 * si utilizza la MenuFactory. Spesso, si mettono tutte le funzioni di
5586 * callback in un file separato, e le si fanno chiamare le funzioni
5587 * appropriate da lì. Così le cose sono più organizzate. */
5588 void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
5590 g_print ("%s\n", (char *) data);
5595 Ed infine un bel makefile per semplificare la compilazione.
5604 C_FLAGS = -Wall $(PROF) -L/usr/local/include -DDEBUG
5605 L_FLAGS = $(PROF) -L/usr/X11R6/lib -L/usr/local/lib
5606 L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
5607 PROGNAME = menufactory
5609 O_FILES = menufactory.o mfmain.o
5611 $(PROGNAME): $(O_FILES)
5613 $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
5616 $(CC) -c $(C_FLAGS) $<
5619 rm -f core *.o $(PROGNAME) nohup.out
5624 Per il momento, accontentatevi di questo esempio. Più avanti aggiungeremo
5625 una spiegazione ed un bel po' di commenti.
5628 <!-- ***************************************************************** -->
5629 <sect> Widget "Testo" (Text Widget)
5630 <!-- ***************************************************************** -->
5632 Il widget di testo permette di mostrare e modificare del testo disposto su più
5633 linee. Questo widget supporta sia la presenza di diversi colori che di diversi font
5634 contemporaneamente, permettendo di mischiarli nel modo in cui si desidera. Mette poi a
5635 disposizione un ampio gruppo di comandi basati sulla tastiera, che sono compatibili con
5638 Il widget di testo dà la possibilità di fare taglia e incolla in modo
5639 completo, compreso l'uso del doppio e triplo click per selezionare un'intera parola o
5642 <!-- ----------------------------------------------------------------- -->
5643 <sect1>Creazione e configurazione di una casella di testo
5645 Esiste un'unica funzione per la creazione di un nuovo widget di testo:
5647 GtkWidget* gtk_text_new (GtkAdjustment *hadj,
5648 GtkAdjustment *vadj);
5651 Gli argomenti di questa chiamata ci permettono di assegnare dei puntatori a dei
5652 valori che stabiliscono il punto di vista del widget. Passare dei valori NULL all'uno
5653 o all'altro o ad entrambi questi argomenti, fà sì che gtk_text_new li
5654 crei automaticamente.
5657 void gtk_text_set_adjustments (GtkText *text,
5658 GtkAdjustment *hadj,
5659 GtkAdjustment *vadj);
5662 La funzione precedente permette di cambiare gli aggiustamenti orizzontale e verticale
5663 di un widget di testo i ogni momento.
5665 Il widget di testo non ` di creare delle barre di scorrimento quando la
5666 quantità è troppo grande per la finestra. Dobbiamo quindi crearle e
5667 aggiungerle alla finestra noi stessi.
5670 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
5671 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
5672 gtk_widget_show (vscrollbar);
5675 Il pezzetto di codice precedente crea una nuova barra di scorrimento verticale e la
5676 collega all'aggiustamento verticale del widget di testo, <tt/text/, dopodiché la
5677 impacchetta nella hbox al solito modo.
5679 Ci sono due modi principali di utilizzo di un widget di testo: per permettere all'utente
5680 di editare del testo, oppure per permettere a noi di mostrare all'utente del testo
5681 disposto su più righe. Per passare dall'una all'altra di queste modalità,
5682 il widget di testo ci mette a disposizione la seguente funzione:
5685 void gtk_text_set_editable (GtkText *text,
5689 L'argomento <tt/editable/ è un valore TRUE o FALSE che specifica se l'utente
5690 può modificare o meno il contenuto del widgte. Quando il widget è
5691 modificabile, mostrerà un cursore nel punto di inserimento corrente.
5693 Niente però vi obbliga ad usare il widget di testo in questi due soli modi. Si
5694 può passare dall'una all'altra delle due modalità in qualsiasi momento,
5695 e si può inserire del testo in ogni momento.
5697 Il widget di testo è in grado di andare a capo automaticamente quando delle linee
5698 di testo sono troppo lunghe per stare su una sola linea della finestra. Il comportamento
5699 predefinito è di andare a capo automaticamente al termine della linea. Questo
5700 può essere cambiato con la seguente funzione:
5703 void gtk_text_set_word_wrap (GtkText *text,
5707 L'uso di questa funzione ci permette di specificare se il widget di testo deve spezzare
5708 o no le linee lunghe ai bordi della finestra. L'argomento <tt/word_wrap/ è un
5709 valore di tipo TRUE o FALSE.
5711 <!-- ----------------------------------------------------------------- -->
5712 <sect1>Manipolazione del testo
5714 Il punto di inserimento corrente del widget può essere stabilito usando
5716 void gtk_text_set_point (GtkText *text,
5719 in cui <tt/index/ è la posizione in cui mettere il punto di inserimento.
5721 La funzione per ottenere la posizione di inserimento corrente è analoga:
5723 guint gtk_text_get_point (GtkText *text);
5726 Una funzione che è utile in combinazione con le precedenti due è
5728 guint gtk_text_get_length (GtkText *text);
5730 la quale restituisce la lunghezza corrente del widget di testo. La lunghezza è
5731 definita come il numero di caratteri che si trovano nel blocco di testo della finestra,
5732 compresi i caratteri tipo CR, che marcano la fine delle linee.
5734 Per inserire del testo alla posizione corrente del widget di testo, si usa la funzione
5735 gtk_text_insert, che permette anche di specificare i colori di primo piano e di sfondo
5736 per il testo, oltre al font da usare.
5739 void gtk_text_insert (GtkText *text,
5747 Passare un valore di NULL come valore per il colore di primo piano (fore), di sfondo (back)
5748 o per il font, farà sì che vengano usati i valori che sono specifici dello
5749 stile del widget. Usare un valore di <tt/-1/ per il parametro lunghezza (length) avrà
5750 come risultato l'inserzione dell'intera stringa di testo.
5752 Il widget di testo è uno dei pochi in GTK che vengono disegnati dinamicamente, fuori
5753 dalla funzione gtk_main. Ciò significa che tutti i cambiamenti al suo contenuto
5754 avranno effetto immediato. Questo può essere un comportamento indesiderabile quando
5755 si stanno facendo delle modifiche multiple al contenuto del widget. Per permettere di
5756 operare cambiamenti multipli sul widget senza che esso si ridisegni continuamente,
5757 si può congelare il contenuto della finestra, in modo che esso interrompa
5758 temporaneamente di ridisegnarsi. Potremo poi sbloccare il widget una volta che tutte
5759 le modifiche sono state completate.
5761 Le due seguenti funzioni fanno il congelamento e lo sbloccaggio (thaw) del widget:
5764 void gtk_text_freeze (GtkText *text);
5765 void gtk_text_thaw (GtkText *text);
5768 Il testo può essere cancellato nel widget di testo a partire dal punto di
5769 inserimento corrente usando le seguenti due funzioni, andando all'indietro (backward)
5770 o all'avanti (forward):
5773 gint gtk_text_backward_delete (GtkText *text,
5775 gint gtk_text_forward_delete (GtkText *text,
5779 Quando si vuole recuperare il contenuto del widget di testo, è
5780 disponibile la macro <tt/GTK_TEXT_INDEX(t, index)/, che permette di
5781 ottenere il crattere alla posizione <tt/index/ all'interno del widget
5784 Per ecuperare un blocco di testo più ampio, si usa la funzione:
5787 gchar *gtk_editable_get_chars (GtkEditable *editable,
5792 Questa è una funzione della classe madre del widget di testo. Un valore
5793 di -1 per <tt/end_pos/, sta ad indicare la fine del testo. L'indice per il
5796 Questa funzione alloca una nuova porzione di memoria per il blocco di testo,
5797 per cui non dimenticate di liberarla con una chiamata a g_free quando non
5798 ne avete più bisogno.
5800 <!-- ----------------------------------------------------------------- -->
5801 <sect1>Keyboard Shortcuts
5803 Il widget di testo mette a disposizione un certo numero di scorciatoie da tastiera
5804 per le più comuni operazioni di modifica, movimento e selezione. Si possono
5805 utilizzare con delle combinazioni che comprendono i tasti Control e Alt.
5807 Oltre a queste, mantenendo premuto il pulsante Control mentre si usano i tasti di
5808 movimento del cursore, causerà lo spostamento parola per parola invece che
5809 carattere per carattere. Mantenere invece premuto il tasto Shift mentre si sposta il
5810 cursore, causerà l'estensione della selezione.
5812 <sect2>Scorciatoie per il movimento
5815 <item> Ctrl-A Inizio della linea
5816 <item> Ctrl-E Fine della linea
5817 <item> Ctrl-N Prossima linea
5818 <item> Ctrl-P Linea precedente
5819 <item> Ctrl-B Indietro di un carattere
5820 <item> Ctrl-F Avanti di un carattere
5821 <item> Alt-B Indietro di una parola
5822 <item> Alt-F Avanti di una parola
5825 <sect2>Scorciatoie per la modifica
5828 <item> Ctrl-H Cancella il carattere precedente (Backspace)
5829 <item> Ctrl-D Cancella il carattere successivo (Delete)
5830 <item> Ctrl-W Cancella la parola precedente
5831 <item> Alt-D Cancella la parola successiva
5832 <item> Ctrl-K Cancella fino alla fine della linea
5833 <item> Ctrl-U Cancella la linea
5836 <sect2>Scorciatoie per la selezione
5839 <item> Ctrl-X Taglia
5841 <item> Ctrl-V Incolla
5845 <!-- ***************************************************************** -->
5846 <sect> Widget non documentati
5847 <!-- ***************************************************************** -->
5850 Per questi sarebbe utile il contributo degli autori! :) Prendete in
5851 considerazione la possibilità di contribuire al nostro tutorial.
5853 Se dovete usare uno di questi widget non documentati, vi suggeriamo
5854 caldamente di dare un'occhiata ai loro rispettivi file header nella
5855 distribuzione di GTK. I nomi delle funzioni di GTK sono molto descrittivi.
5856 Non appena si capisce come funzionano le cose, non è
5857 difficile dedurre il modo d'uso di un widget semplicemente guardando la
5858 dichiarazione di funzione associata ad esso. Aggiungendo a questo qualche
5859 spunto tratto dal codice di altri non dovrebbero esserci problemi.
5861 Quando avrete raggiunto una comprensione globale di tutte le funzioni
5862 di un widget non documentato, considerate la possibilità di scrivere
5863 un tutorial su di esso, in modo che altri possano beneficiare del
5866 <!-- ----------------------------------------------------------------- -->
5867 <sect1> Controlli di intervallo (Range Controls)
5869 <!-- ----------------------------------------------------------------- -->
5872 (Potrebbe essere necessario riscrivere questa parte per conformarsi allo stile
5873 del resto del tutorial)
5876 Le anteprime servono a un certo numero di cose in GIMP/GTK. La più
5877 importante è questa: a risoluzioni molto alte le immagini possono
5878 facilmente occupare diverse decine di megabyte di memoria; ogni operazione
5879 su immagini così grosse può richiedere molto tempo. Se per la
5880 scelta di una data modifica vi occorrono 5-10 tentativi (cioè 10-20
5881 passi, poiché è necessario ripristinare l'originale se si
5882 è commesso un errore), possono volerci letteralmente delle ore per
5883 fare quella giusta - se non si rimane a corto di memoria prima! Coloro che
5884 hanno passato ore in camera oscura conoscono la sensazione. In questi casi
5885 le anteprime sono utilissime!
5887 Ma la seccatura dell'attesa non è l'unico caso. Spesso è utile
5888 confrontare la versione precedente con la successiva affiancandole, o almeno
5889 alternandole. Se si sta lavorando con grandi immagini e ritardi di una decina
5890 di secondi un confronto efficace è quantomeno difficile da fare.
5891 Per immagini di 30 mega (4 pollici per 6 pollici, 600 punti per pollice, 24 bit)
5892 tale confronto risulta impraticabile per la maggior parte degli utenti. In
5893 questo caso le anteprime sono di grande aiuto!
5895 Ma c'è di più. Con le anteprime è possibile scrivere
5896 plug-in per ottenere addirittura anteprime di anteprime (per esempio, la
5897 simulazione del pacchetto di filtri). Questi plug-in possono così
5898 fornire un certo numero di anticipazioni di quel che si otterrebbe applicando
5899 certe opzioni. Un simile approccio funziona come una tavolozza di anteprime,
5900 ed è molto efficace per piccoli cambiamenti!
5902 Non è finita. Per alcuni plug-in può essere necessario un
5903 intervento umano in tempo reale specifico per ogni immagine. Nel plug-in
5904 SuperNova, ad esempio, vengono chieste le coordinate del centro della
5905 futura supernova. Il modo più semplice per fare questo è
5906 senza dubbio quello di mostrare un'anteprima all'utente chiedendogli di
5907 selezionare interattivamente il centro.
5909 Infine, un paio di applicazioni tipiche. Le anteprime possono essere usate
5910 anche quando non si sta lavorando con grandi immagini. Per esempio, sono
5911 utili quando si stanno calcolando dei pattern complicati (date un'occhiata
5912 al venerabile plug in ``Diffraction'' e a molti altri!). Altro esempio:
5913 date un'occhiata al plug-in di rotazione della mappa dei colori (in allestimento).
5914 Le anteprime possono anche essere usate per visualizzare in un plug-in
5915 piccoli logo o, addirittura, l'immagine dell'Autore!
5917 Quando non usare le anteprime
5919 Le anteprime non vanno usate per grafici, disegni ecc., poiché per
5920 queste cose GDK è molto più veloce. Le anteprime vanno usate
5921 solo per immagini derivate da un'elaborazione!
5923 Le anteprime possono essere inserite dappertutto. In un vbox, in un hbox,
5924 in una tabella, in un bottone, ecc. Sicuramente però hanno il loro
5925 look migliore se bordate con delle cornici (frame). Le anteprime non hanno
5926 bordi propri e appaiono piatte senza (naturalmente, se quel che si vuole
5927 è proprio un aspetto piatto...). I bordi possono essere creati con
5932 Le anteprime sono per molti aspetti simili agli altri widget in GTK (con
5933 tutto ciò che questo implica), con l'eccezione di avere una
5934 caratteristica in più: è necessario che siano riempite con
5935 qualche tipo di immagine! Inizialmente parleremo solo dell'aspetto GTK
5936 delle anteprime e successivamente discuteremo di come riempirle.
5941 /* Crea un widget di anteprima,
5942 inizializzane le dimensioni
5945 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
5946 /* Alternativamente:
5947 GTK_PREVIEW_GRAYSCALE);*/
5948 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
5949 gtk_widget_show(preview);
5950 my_preview_rendering_function(preview);
5953 Come già detto, le anteprime hanno un buon aspetto dentro le cornici,
5957 GtkWidget *create_a_preview(int Width,
5964 frame = gtk_frame_new(NULL);
5965 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
5966 gtk_container_border_width (GTK_CONTAINER(frame),0);
5967 gtk_widget_show(frame);
5969 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
5970 :GTK_PREVIEW_GRAYSCALE);
5971 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
5972 gtk_container_add(GTK_CONTAINER(frame),preview);
5973 gtk_widget_show(preview);
5975 my_preview_rendering_function(preview);
5981 Questa è una semplice anteprima. Questa funzione restituisce la cornice
5982 ``madre'', in modo che sia possibile metterla in qualche altro posto nella vostra
5983 interfaccia. Naturalmente è possibile passare alla routine la cornice
5984 madre come parametro. In molte situazioni, comunque, il contenuto di un'anteprima
5985 viene aggiornato continuamente dall'applicazione; in questi casi potreste
5986 preferire passare alla funzione ``create_a_preview()'' un puntatore
5987 all'anteprima, ottenendone così il controllo dopo.
5989 Un'avvertimento più importante che potrebbe un giorno risparmiarvi
5990 tanto tempo perso: a volte è preferibile etichettare le anteprime;
5991 ad esempio, è possibile etichettare l'anteprima contenente l'immagine
5992 originale come ``Originale'' e quella contenente l'immagine modificata come
5993 ``Modificata''. Potrebbe capitarvi di impacchettare in un vbox l'anteprima
5994 insieme con l'etichetta associata. L'insidia inattesa sta nel fatto che se
5995 l'etichetta è più ampia dell'anteprima (cosa che può
5996 accadere per una varietà di motivi da voi non prevedibili, come il
5997 fatto che la dimensione dell'anteprima viene decisa dinamicamente, o la
5998 dimensione del font), la cornice si espande e non risulta più
5999 perfettamente aderente all'anteprima. Questo stesso problema probabilmente
6000 può verificarsi anche in altre situazioni.
6004 La soluzione è quella di mettere l'anteprima e l'etichetta in una
6005 tabella 2x1 e di legarle insieme chiamando la funzione gtk_table_attach con
6006 i seguenti parametri (questa è una delle varianti possibili,
6007 naturalmente; l'importante è che non ci sia GTK_FILL nella seconda
6011 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
6013 GTK_EXPAND|GTK_FILL,
6015 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
6021 Ed ecco il risultato:
6027 La maniera più semplice per rendere cliccabile un'anteprima è
6028 quella di metterla dentro un bottone. Questo ha anche l'effetto di aggiungere
6029 un bel bordo attorno all'anteprima, il che rende superfluo metterla in una
6032 Questo è tutto per quel che riguarda GTK.
6035 Completare un'anteprima
6037 Per impratichirci con le basi del completamento delle anteprime, creiamo
6038 il seguente disegno (trovato per tentativi):
6044 my_preview_rendering_function(GtkWidget *preview)
6047 #define HALF (SIZE/2)
6049 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
6050 gint i, j; /* Coordinates */
6051 double r, alpha, x, y;
6053 if (preview==NULL) return; /* Di solito aggiungo questo per */
6054 /* evitare piantamenti stupidi. */
6055 /* Probabilmente bisognerebbe */
6056 /* assicurarsi che tutto sia stato*/
6057 /* inizializzato con successo */
6058 for (j=0; j < ABS(cos(2*alpha)) ) { /* Siamo dentro la sagoma? */
6059 /* glib.h contiene ABS(x). */
6060 row[i*3+0] = sqrt(1-r)*255; /* Definisce il Rosso */
6061 row[i*3+1] = 128; /* Definisce il Verde */
6062 row[i*3+2] = 224; /* Definisce il Blu */
6063 } /* "+0" è per allineamento */
6066 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
6067 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
6070 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
6071 /* Inserisce "row" in "preview" a partire del punto avente */
6072 /* coordinate (0,j) prima colonna, j-esima riga, per SIZE */
6073 /* pixel verso destra */
6076 free(row); /* libera un po' di memoria */
6077 gtk_widget_draw(preview,NULL); /* indovina cosa fa questo? */
6078 gdk_flush(); /* e questo? */
6081 Coloro che non usano GIMP probabilmente hanno già visto abbastanza
6082 per fare molte cose. Per gli utenti GIMP c'è ancora qualcosa da
6085 Anteprima dell'immagine
6087 Probabilmente è opportuno tenere pronta una versione ridotta dell'immagine,
6088 grande quanto basta per riempire l'anteprima. Questo può essere fatto
6089 selezionando un pixel ogni n, dove n è il rapporto tra la dimensione
6090 dell'immagine e la dimensione dell'anteprima. Tutte le operazioni successive
6091 (compreso il riempimento dell'anteprima) sono fatte solo sul ridotto numero
6092 di pixel selezionati. Di seguito è riportata un'implementazione della
6093 riduzione dell'immagine (si tenga presente che ho preso solo lezioni basilari
6097 (ATTENZIONE: CODICE NON VERIFICATO!!!)
6111 SELCTION_IN_CONTEXT,
6115 ReducedImage *Reduce_The_Image(GDrawable *drawable,
6120 /* Questa funzione riduce l'immagine alla dimens. scelta per l'anteprima */
6121 /* La dimensione dell'anteprima è determinata da LongerSize, cioè la più */
6122 /* grande delle dimensioni. Funziona solo per immagini RGB! */
6123 gint RH, RW; /* Altezza ridotta e larghezza ridotta */
6124 gint width, height; /* Larghezza e altezza dell'area da ridurre */
6125 gint bytes=drawable->bpp;
6126 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
6128 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
6129 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
6130 GPixelRgn srcPR, srcMask;
6131 gint NoSelectionMade=TRUE; /* Assumiamo di trattare l'intera immagine */
6133 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
6136 /* Se c'è una SELEZIONE, ne abbiamo avuto gli estremi! */
6138 if (width != drawable->width && height != drawable->height)
6139 NoSelectionMade=FALSE;
6140 /* Controlliamo se l'utente ha una selezione attiva. Questo */
6141 /* diventerà importante dopo, alla creazione di una maschera ridotta */
6143 /* Se si vuole l'anteprima dell'immagine intera, annulla quanto sopra */
6144 /* Naturalmente, in assenza di una selezione, questo non cambia nulla */
6145 if (Selection==ENTIRE_IMAGE) {
6149 y2=drawable->height;
6152 /* Se si vuole l'anteprima di una selezione con parte dell'area */
6153 /* circostante bisogna espanderla un po'. */
6154 if (Selection==SELECTION_IN_CONTEXT) {
6155 x1=MAX(0, x1-width/2.0);
6156 x2=MIN(drawable->width, x2+width/2.0);
6157 y1=MAX(0, y1-height/2.0);
6158 y2=MIN(drawable->height, y2+height/2.0);
6161 /* Così si determinano larghezza e altezza dell'area da ridurre. */
6165 /* Le linee seguenti determinano quale dimensione deve essere il */
6166 /* lato più lungo. L'idea è presa dal plug-in supernova. Ritengo */
6167 /* che avrei potuto pensarci da solo, ma la verità va detta. */
6168 /* Brutta cosa il plagio! */
6171 RH=(float) height * (float) LongerSize/ (float) width;
6175 RW=(float)width * (float) LongerSize/ (float) height;
6178 /* L'intera immagine viene "stirata" in una stringa! */
6179 tempRGB = (guchar *) malloc(RW*RH*bytes);
6180 tempmask = (guchar *) malloc(RW*RH);
6182 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
6183 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, FALSE, FALSE);
6185 /* Prendine abbastanza da contenere una riga di immagine e una di maschera */
6186 src_row = (guchar *) malloc (width*bytes);
6187 src_mask_row = (guchar *) malloc (width);
6189 for (i=0; i < RH; i++) {
6190 whichrow=(float)i*(float)height/(float)RH;
6191 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
6192 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
6194 for (j=0; j < RW; j++) {
6195 whichcol=(float)j*(float)width/(float)RW;
6197 /* Nessuna selezione = tutti i punti sono completamente selezionati */
6198 if (NoSelectionMade)
6199 tempmask[i*RW+j]=255;
6201 tempmask[i*RW+j]=src_mask_row[whichcol];
6203 /* Aggiungi la riga alla lunga stringa che ora contiene l'immagine */
6204 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
6205 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
6206 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
6208 /* Mantieni anche la trasparenza (alpha) */
6210 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
6217 temp->mask=tempmask;
6223 La seguente è una funzione di anteprima che usa lo stesso tipo
6224 ReducedImage! Si noti che usa una finta trasparenza - se ne è presente
6225 una, tramite fake_transparency che è definita come segue:
6228 gint fake_transparency(gint i, gint j)
6230 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
6237 E adesso la funzione per l'anteprima:
6240 my_preview_render_function(GtkWidget *preview,
6244 gint Inten, bytes=drawable->bpp;
6247 gint RW=reduced->width;
6248 gint RH=reduced->height;
6249 guchar *row=malloc(bytes*RW);;
6252 for (i=0; i < RH; i++) {
6253 for (j=0; j < RW; j++) {
6255 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
6256 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
6257 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
6260 for (k=0; k<3; k++) {
6261 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
6262 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
6265 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
6269 gtk_widget_draw(preview,NULL);
6273 Funzioni Applicabili
6275 guint gtk_preview_get_type (void);
6277 void gtk_preview_uninit (void);
6279 GtkWidget* gtk_preview_new (GtkPreviewType type);
6280 /* Descritta precedentemente */
6281 void gtk_preview_size (GtkPreview *preview,
6284 /* Permette di ridimensionare un'anteprima esistente */
6285 /* Pare che un bug in GTK renda disordinato questo */
6286 /* processo. Un modo di rimettere le cose a posto */
6287 /* è quello di ridimensionare manualmente */
6288 /* la finestra contenente l'anteprima dopo aver */
6289 /* ridimensionato l'anteprima. */
6291 void gtk_preview_put (GtkPreview *preview,
6302 void gtk_preview_put_row (GtkPreview *preview,
6310 void gtk_preview_draw_row (GtkPreview *preview,
6315 /* Descritta nel testo */
6317 void gtk_preview_set_expand (GtkPreview *preview,
6321 /* Nessun indizio per le seguenti, ma dovrebbero */
6322 /* essere standard per la maggior parte dei widget */
6323 void gtk_preview_set_gamma (double gamma);
6324 void gtk_preview_set_color_cube (guint nred_shades,
6325 guint ngreen_shades,
6327 guint ngray_shades);
6328 void gtk_preview_set_install_cmap (gint install_cmap);
6329 void gtk_preview_set_reserved (gint nreserved);
6330 GdkVisual* gtk_preview_get_visual (void);
6331 GdkColormap* gtk_preview_get_cmap (void);
6332 GtkPreviewInfo* gtk_preview_get_info (void);
6338 <!-- ----------------------------------------------------------------- -->
6342 <!-- ***************************************************************** -->
6343 <sect>Il Widget EventBox<label id="sec_The_EventBox_Widget">
6344 <!-- ***************************************************************** -->
6346 Alcuni widget gtk non sono associati a finestre X, sicché
6347 semplicemente disegnano sui loro genitori. Per questo motivo essi non possono
6348 ricevere eventi e se sono sovradimensionati non vengono troncati, ma rischiano
6349 di sovrapporsi, generando confusione. Se si vuole di più da questi
6350 widget si può ricorrere agli EventBox.
6352 A prima vista il widget EventBox potrebbe sembrare completamente inutile. Non
6353 disegna nulla sullo schermo e non risponde a nessun evento. Tuttavia ha
6354 una funzione: fornire una finestra X al suo widget figlio. Ciò
6355 è importante in quanto molti widget GTK non hanno una finestra X
6356 associata. Se questo da una parte risparmia memoria e migliora le prestazioni,
6357 dall'altra introduce degli svantaggi: un widget senza una finestra X non
6358 può ricevere eventi, e non taglia in alcun modo il suo contenuto.
6359 Sebbene il nome ``EventBox'' (casella di eventi) enfasizzi la funzione di
6360 gestione degli eventi, il widget può essere usato anche per
6361 limitare la dimensione dei widget figli (ma anche per altro: si veda
6362 l'esempio seguente).
6365 Per creare un widget di tipo EventBox:
6368 GtkWidget* gtk_event_box_new (void);
6372 All'EventBox si può aggiungere un widget figlio:
6375 gtk_container_add (GTK_CONTAINER(event_box), widget);
6379 The following example demonstrates both uses of an EventBox - a label
6380 is created that clipped to a small box, and set up so that a
6381 mouse-click on the label causes the program to exit.
6382 Il seguente esempio mostra entrambi gli usi di un EventBox - si crea
6383 un'etichetta limitata da un rettangolo piccolo, fatta in modo che
6384 cliccando con il mouse su di essa il programma termina.
6389 #include <gtk/gtk.h>
6392 main (int argc, char *argv[])
6395 GtkWidget *event_box;
6398 gtk_init (&argc, &argv);
6400 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6402 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
6404 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6405 GTK_SIGNAL_FUNC (gtk_exit), NULL);
6407 gtk_container_border_width (GTK_CONTAINER (window), 10);
6409 /* Crea un EventBox e lo aggiunge alla finestra principale */
6411 event_box = gtk_event_box_new ();
6412 gtk_container_add (GTK_CONTAINER(window), event_box);
6413 gtk_widget_show (event_box);
6415 /* Crea una etichetta lunga */
6417 label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
6418 gtk_container_add (GTK_CONTAINER (event_box), label);
6419 gtk_widget_show (label);
6421 /* Limitane le dimensioni */
6422 gtk_widget_set_usize (label, 110, 20);
6424 /* E collega ad essa una azione */
6425 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
6426 gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
6427 GTK_SIGNAL_FUNC (gtk_exit), NULL);
6429 /* Un'altra cosa per cui si ha bisogno di una finestra X ... */
6431 gtk_widget_realize (event_box);
6432 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
6434 gtk_widget_show (window);
6442 <!-- ***************************************************************** -->
6443 <sect>Selezionare gli Attributi dei Widget<label id="sec_setting_widget_attributes">
6444 <!-- ***************************************************************** -->
6446 Qui si descrivono le funzioni per la gestione dei widget. Esse possono essere
6447 usate per impostarne lo stile, il padding, le dimensioni, ...
6449 (Forse andrebbe fatta un'intera sezione sugli acceleratori).
6452 void gtk_widget_install_accelerator (GtkWidget *widget,
6453 GtkAcceleratorTable *table,
6458 void gtk_widget_remove_accelerator (GtkWidget *widget,
6459 GtkAcceleratorTable *table,
6460 gchar *signal_name);
6462 void gtk_widget_activate (GtkWidget *widget);
6464 void gtk_widget_set_name (GtkWidget *widget,
6466 gchar* gtk_widget_get_name (GtkWidget *widget);
6468 void gtk_widget_set_sensitive (GtkWidget *widget,
6471 void gtk_widget_set_style (GtkWidget *widget,
6474 GtkStyle* gtk_widget_get_style (GtkWidget *widget);
6476 GtkStyle* gtk_widget_get_default_style (void);
6478 void gtk_widget_set_uposition (GtkWidget *widget,
6481 void gtk_widget_set_usize (GtkWidget *widget,
6485 void gtk_widget_grab_focus (GtkWidget *widget);
6487 void gtk_widget_show (GtkWidget *widget);
6489 void gtk_widget_hide (GtkWidget *widget);
6493 <!-- ***************************************************************** -->
6494 <sect>Funzioni periodiche, di I/O e di attesa<label id="sec_timeouts">
6495 <!-- ***************************************************************** -->
6497 <!-- ----------------------------------------------------------------- -->
6498 <sect1>Funzioni periodiche
6500 Probabilmente vi sarete chiesti come far fare qualcosa di utile a GTK
6501 durante la chiamata alla gtk_main(). Ci sono diverse possibilità.
6502 Usando le seguenti funzioni si possono creare funzioni che vengono chiamate
6506 gint gtk_timeout_add (guint32 interval,
6507 GtkFunction function,
6511 Il primo argomento è il numero di millisecondi tra le chiamate alla
6512 funzione. Il secondo è la funzione periodica, mentre il terzo
6513 rappresenta i dati che vengono passati alla funzione. Il valore restituito
6514 è un'etichetta che può essere utilizzata per fermare la chiamata
6515 periodica, passandolo alla funzione:
6518 void gtk_timeout_remove (gint tag);
6521 La chiamata periodica si ferma anche se la funzione periodica ritorna zero
6522 o FALSE. Naturalmente questo vuol dire che se si vuole che la funzione periodica
6523 continui ad essere richiamata, essa deve restituire un valore non nullo,
6526 La dichiarazione della funzione periodica dovrebbe essere come questa:
6529 gint timeout_callback (gpointer data);
6532 <!-- ----------------------------------------------------------------- -->
6533 <sect1>Controllo dell'I/O
6535 Un'altra utile caratteristica di GTK è la possibilità di fargli
6536 controllare che siano verificate certe condizioni su un descrittore di file
6537 (come quelli restituiti da open(2) o socket(2)). Questo è utile in
6538 particolar modo per le applicazioni di rete. La funzione è la seguente:
6541 gint gdk_input_add (gint source,
6542 GdkInputCondition condition,
6543 GdkInputFunction function,
6547 Il primo argomento è il descrittore che si desidera venga controllato,
6548 mentre il secondo specifica quale condizione si vuole che GDK controlli.
6549 Questa può essere una tra:
6551 GDK_INPUT_READ - Chiama la funzione quando ci sono dati pronti per la lettura
6552 nel descrittore di file.
6554 GDK_INPUT_WRITE - Chiama la funzione quando il descrittore di file è
6555 pronto per la scrittura.
6557 Come sicuramente avrete già intuito, il terzo parametro è la
6558 funzione da chiamare quando la condizione specificata è soddisfatta,
6559 mentre il quarto rappresenta i dati da passare a questa funzione.
6561 Il valore di ritorno è un etichetta che può essere usata per
6562 fermare il controllo di GDK sul descrittore di file, usando la seguente
6566 void gdk_input_remove (gint tag);
6569 La funzione da richiamare va dichiarata così:
6572 void input_callback (gpointer data, gint source,
6573 GdkInputCondition condition);
6577 <!-- ----------------------------------------------------------------- -->
6578 <sect1>Funzioni di attesa (``Idle'')
6580 Cosa fare se si ha una funzione che si vuole venga chiamata quando non
6581 sta accadendo nient'altro?
6584 gint gtk_idle_add (GtkFunction function,
6588 Questa fa si che GDK chiami la funzione specificata quando non c'è
6589 nessuna altra operazione in corso.
6592 void gtk_idle_remove (gint tag);
6595 Non ci soffermeremo sul significato dei parametri in quanto del tutto analoghi
6596 ai precedenti. La funzione puntata dal primo argomento della gtk_idle_add
6597 viene chiamata non appena se ne presenta l'opportunità; come
6598 negli altri casi, se essa restituisce FALSE non viene più chiamata.
6600 <!-- ***************************************************************** -->
6601 <sect>La gestione delle selezioni
6602 <!-- ***************************************************************** -->
6604 <!-- ----------------------------------------------------------------- -->
6609 Le <em>selezioni</em> sono un tipo di comunicazione tra processi
6610 supportato da GTK. Una selezione identifica un frammento di dati; per
6611 esempio, una porzione di testo selezionata dall'utente in qualche modo,
6612 magari con il mouse. Su un display solo un'applicazione alla volta
6613 (il <em>proprietario</em>) puó essere proprietaria di una
6614 particolare selezione, sicché quando un'applicazione richiede
6615 una selezione il precedente proprietario deve comunicare all'utente che
6616 la selezione è stata ceduta. Altre applicazioni possono richiedere
6617 il contenuto di una selezione in diverse forme, chiamate <em>obiettivi</em>.
6618 Ci può essere un numero qualsiasi di selezioni, ma la maggior parte
6619 delle applicazioni X può gestirne solo una, la <em>selezione
6623 Nella maggior parte dei casi per una applicazione GTK non è
6624 necessario gestire esplicitamente le selezioni. I widget standard,
6625 come quello di Ingresso, hanno già la capacità di
6626 chiedere la selezione se necessario (p. e., quando l'utente
6627 seleziona sul testo), e di recuperare il contenuto di una selezione
6628 di un altro widget o di un'altra applicazione (p. e., quando l'utente
6629 clicca il tasto centrale del mouse). Ci possono comunque essere dei
6630 casi nei quali si vuole dare ad altri widget la capacità di
6631 fornire la selezione, o si vogliono recuperare degli obiettivi non
6632 supportati direttamente.
6635 Un concetto fondamentale necessario per comprendere la gestione delle
6636 selezioni è quello di <em>atomo</em>. Un atomo è un intero
6637 che identifica univocamente una stringa (su un certo display).
6638 Certi atomi sono predefiniti dal server X, e in alcuni casi in <tt>gtk.h</tt>
6639 ci sono costanti corrispondenti a questi atomi. Per esempio, la costante
6640 <tt>GDK_PRIMARY_SELECTION</tt> corrisponde alla stringa ``PRIMARY''.
6641 Negli altri casi bisogna usare le funzioni <tt>gdk_atom_intern()</tt>
6642 per ottenere l'atomo corrispondente ad una stringa, e <tt>gdk_atom_name()</tt>
6643 per ottenere il nome di un atomo. Sia le selezioni sia gli obiettivi sono
6644 identificati da atomi.
6645 <!-- ----------------------------------------------------------------- -->
6646 <sect1> Recuperare le selezioni
6650 Il recupero di una selezione è un processo asincrono. Per iniziare
6651 il processo, si chiama:
6653 gint gtk_selection_convert (GtkWidget *widget,
6659 Questo <em>converte</em> la selezione nella forma specificata
6660 dall'obiettivo <tt/target/. Se possibile, il campo <tt/time/
6661 dovrebbe essere il tempo dell'evento che ha attivato la selezione.
6662 Questo aiuta a far si che gli eventi avvengano nell'ordine in cui
6663 l'utente li ha richiesti. Se comunque non fosse disponibile (per
6664 esempio, se la conversione è stata attivata da un segnale di
6665 ``cliccato''), allora si può usare la costante
6666 <tt>GDK_CURRENT_TIME</tt>.
6669 Quando il proprietario di una selezione risponde ad una richiesta,
6670 un segnale ``selection_received'' (selezione ricevuta) viene inviato
6671 alla vostra applicazione. Il gestore di questo segnale riceve un
6672 puntatore ad una struttura <tt>GtkSelectionData</tt>, che è
6673 definita nel modo seguente:
6675 struct _GtkSelectionData
6685 <tt>selection</tt> e <tt>target</tt> sono i valori da voi specificati
6686 nella chiamata <tt>gtk_selection_convert()</tt>. <tt>type</tt> è
6687 un atomo che identifica il tipo di dati restituiti dal proprietario della
6688 selezione. Alcuni valori possibili sono ``STRING'', una stringa di
6689 caratteri latin-1, ``ATOM'', una serie di atomi, ``INTEGER'', un intero, ecc.
6690 La maggior parte degli obiettivi può restituire solo un tipo.
6691 <tt/format/ ci dà la lunghezza delle unità (per esempio caratteri)
6692 in bit. Di solito, quando si ricevono i dati non ci si cura di questo.
6693 <tt>data</tt> è un puntatore ai dati restituiti, e <tt>length</tt>
6694 è la lunghezza dei dati restituiti, in byte. Se <tt>length</tt>
6695 è negativo allora si è verificato un errore e non è
6696 stato possibile recuperare la selezione. Questo può avvenire se
6697 nessuna applicazione era proprietaria della selezione, o se si è
6698 richiesto un obiettivo non supportato dall'applicazione. Viene garantito
6699 che il buffer sia un byte più lungo di <tt>length</tt>; il byte
6700 in più sarà sempre zero, in modo che non sia necessario
6701 ricopiare le stringhe solo per farle terminare con zero.
6704 Nell'esempio che segue viene recuperato l'obiettivo speciale ``TARGETS'',
6705 che è una lista di tutti gli obiettivi in cui può essere
6706 convertita la selezione.
6710 #include <gtk/gtk.h>
6712 void selection_received (GtkWidget *widget,
6713 GtkSelectionData *selection_data,
6716 /* Gestore di segnale chiamato quando l'utente clicca nel bottone */
6719 get_targets (GtkWidget *widget, gpointer data)
6721 static GdkAtom targets_atom = GDK_NONE;
6723 /* Prende l'atomo corrispondente alla stringa "TARGETS" */
6724 if (targets_atom == GDK_NONE)
6725 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
6727 /* E richiede l'obiettivo "TARGETS" per la selezione primaria */
6728 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
6732 /* Gestore di segnale chiamato quando il proprietario della selezione */
6733 /* restituisce i dati */
6735 selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
6742 /* **** IMPORTANTE **** Controlla che il recupero sia riuscito */
6743 if (selection_data->length < 0)
6745 g_print ("Selection retrieval failed\n");
6748 /* Make sure we got the data in the expected form */
6749 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
6751 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
6755 /* Stampa gli atomi ricevuti */
6756 atoms = (GdkAtom *)selection_data->data;
6759 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
6762 name = gdk_atom_name (atoms[i]);
6764 g_print ("%s\n",name);
6766 g_print ("(bad atom)\n");
6773 main (int argc, char *argv[])
6778 gtk_init (&argc, &argv);
6780 /* Create the toplevel window */
6782 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6783 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
6784 gtk_container_border_width (GTK_CONTAINER (window), 10);
6786 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6787 GTK_SIGNAL_FUNC (gtk_exit), NULL);
6789 /* Crea un bottone che l'utente può cliccare per ottenere gli obiettivi */
6791 button = gtk_button_new_with_label ("Get Targets");
6792 gtk_container_add (GTK_CONTAINER (window), button);
6794 gtk_signal_connect (GTK_OBJECT(button), "clicked",
6795 GTK_SIGNAL_FUNC (get_targets), NULL);
6796 gtk_signal_connect (GTK_OBJECT(button), "selection_received",
6797 GTK_SIGNAL_FUNC (selection_received), NULL);
6799 gtk_widget_show (button);
6800 gtk_widget_show (window);
6808 <!-- ----------------------------------------------------------------- -->
6809 <sect1> Fornire una selezione
6812 Fornire la selezione è un po' più complicato. Bisogna
6813 registrare i gestori che verranno chiamati quando viene richiesta la
6814 propria selezione. Per ogni coppia selezione/obiettivo che si gestirà
6815 occorre una chiamata a:
6818 void gtk_selection_add_handler (GtkWidget *widget,
6821 GtkSelectionFunction function,
6822 GtkRemoveFunction remove_func,
6826 <tt/widget/, <tt/selection/, e <tt/target/ identificano le richieste
6827 che questo gestore soddisferà. <tt/remove_func/, se non è
6828 NULL, verrà chiamato quando il gestore di segnale viene rimosso.
6829 Questo è utile, per esempio, per linguaggi interpretati ai quali
6830 serve di tener traccia di un conteggio di riferimento per <tt/data/.
6833 La funzione di richiamo ha la forma:
6836 typedef void (*GtkSelectionFunction) (GtkWidget *widget,
6837 GtkSelectionData *selection_data,
6842 La GtkSelectionData è la stessa di prima, ma stavolta siamo
6843 responsabili di riempire i campi <tt/type/, <tt/format/, <tt/data/,
6844 e <tt/length/. (Il campo <tt/format/ qui è effettivamente
6845 importante - il server X lo usa per capire se occorre che i byte
6846 dei dati vengano scambiati o no. Di solito sarà 8 - cioè
6847 un carattere - o 32 - cioè un intero.) Questo viene fatto
6848 chiamando la funzione:
6851 void gtk_selection_data_set (GtkSelectionData *selection_data,
6857 Questa funzione si prende cura di fare propriamente una copia dei dati
6858 in modo che non ci si debba preoccupare di conservarli (è opportuno
6859 evitare di riempire a mano i campi della struttura GtkSelectionData).
6862 Quando richiesto dall'utente, richiederete la proprietà della selezione
6866 gint gtk_selection_owner_set (GtkWidget *widget,
6871 Se un'altra applicazione richiede la proprietà della selezione,
6872 riceverete un evento di azzeramento della selezione (``selection_clear_event'').
6874 Come esempio di fornitura della selezione, il programma seguente aggiunge
6875 la funzionalità di selezione a un bottone di attivazione. Quando il
6876 bottone viene premuto, il programma richiede la selezione primaria.
6877 L'unico obiettivo supportato (oltre a certi obiettivi come ``TARGETS''
6878 fornito dalla stessa GTK) è l'obiettivo ``STRING''. Quando viene
6879 richiesto questo obiettivo, viene restituita una rappresentazione stringa
6883 /* setselection.c */
6885 #include <gtk/gtk.h>
6888 /* Richiamata quando l'utente attiva la selezione */
6890 selection_toggled (GtkWidget *widget, gint *have_selection)
6892 if (GTK_TOGGLE_BUTTON(widget)->active)
6894 *have_selection = gtk_selection_owner_set (widget,
6895 GDK_SELECTION_PRIMARY,
6897 /* se il richiamo della selezione è fallito, si riporta il
6898 bottone nello stato non premuto */
6899 if (!*have_selection)
6900 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
6904 if (*have_selection)
6906 /* Prima di annullare la selezione mettendone a NULL il proprietario,
6907 controlliamo se siamo i veri proprietari */
6908 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
6909 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
6911 *have_selection = FALSE;
6916 /* Chiamata quando un'altra applicazione richiede la selezione */
6918 selection_clear (GtkWidget *widget, GdkEventSelection *event,
6919 gint *have_selection)
6921 *have_selection = FALSE;
6922 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
6927 /* Fornisce come selezione il tempo attuale */
6929 selection_handle (GtkWidget *widget,
6930 GtkSelectionData *selection_data,
6934 time_t current_time;
6936 current_time = time (NULL);
6937 timestr = asctime (localtime(&current_time));
6938 /* Quando si restituisce una singola stringa, non occorre che finisca
6939 con NULL. Questo verrà fatto automaticamente */
6941 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
6942 8, timestr, strlen(timestr));
6946 main (int argc, char *argv[])
6950 GtkWidget *selection_button;
6952 static int have_selection = FALSE;
6954 gtk_init (&argc, &argv);
6956 /* Crea la finestra di livello superiore */
6958 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6959 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
6960 gtk_container_border_width (GTK_CONTAINER (window), 10);
6962 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6963 GTK_SIGNAL_FUNC (gtk_exit), NULL);
6965 /* Crea un bottone a commutazione che agisce come la selezione */
6967 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
6968 gtk_container_add (GTK_CONTAINER (window), selection_button);
6969 gtk_widget_show (selection_button);
6971 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
6972 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
6973 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
6974 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
6976 gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
6977 GDK_SELECTION_TYPE_STRING,
6978 selection_handle, NULL);
6980 gtk_widget_show (selection_button);
6981 gtk_widget_show (window);
6989 <!-- ***************************************************************** -->
6990 <sect>La glib<label id="sec_glib">
6991 <!-- ***************************************************************** -->
6993 La glib fornisce molte funzioni e definizioni utili pronte all'uso quando si
6994 creano applicazioni GDK e GTK. Qui verranno elencate tutte, con una
6995 breve spiegazione. Molte sono duplicati delle funzioni standard della libc,
6996 e quindi per queste non si scenderà nei dettagli. Questa vuole essere una
6997 lista di riferimento, in modo che si sappia cosa è possibile usare.
6999 <!-- ----------------------------------------------------------------- -->
7002 Le definizioni per gli estremi di molti dei tipi standard sono:
7017 Ci sono anche le seguenti definizioni di tipo. Quelle rimaste non specificate
7018 sono dipendenti dall'architettura. Si ricordi di evitare di fare affidamento
7019 sulla dimensione di un puntatore se si vuole la portabilità! P.e., un puntatore
7020 su un Alpha è lungo 8 byte, ma 4 su un Intel.
7029 unsigned char guchar;
7030 unsigned short gushort;
7031 unsigned long gulong;
7036 long double gldouble;
7048 <!-- ----------------------------------------------------------------- -->
7049 <sect1>Liste a doppio collegamento
7051 le seguenti funzioni sono usate per creare, gestire e distruggere liste a
7052 doppio collegamento. Si assume che il lettore sappia già cosa sono le liste
7053 collegate (linked list), poiché descriverle è fuori dagli scopi di
7054 questo documento. Naturalmente non è necessario conoscerle per l'uso
7055 generale di GTK, per quanto conoscerle sia comunque interessante.
7058 GList* g_list_alloc (void);
7060 void g_list_free (GList *list);
7062 void g_list_free_1 (GList *list);
7064 GList* g_list_append (GList *list,
7067 GList* g_list_prepend (GList *list,
7070 GList* g_list_insert (GList *list,
7074 GList* g_list_remove (GList *list,
7077 GList* g_list_remove_link (GList *list,
7080 GList* g_list_reverse (GList *list);
7082 GList* g_list_nth (GList *list,
7085 GList* g_list_find (GList *list,
7088 GList* g_list_last (GList *list);
7090 GList* g_list_first (GList *list);
7092 gint g_list_length (GList *list);
7094 void g_list_foreach (GList *list,
7096 gpointer user_data);
7099 <!-- ----------------------------------------------------------------- -->
7100 <sect1>Liste a collegamento singolo
7102 Molte delle funzioni per le liste a collegamento singolo sono identiche alle
7103 precedenti. Eccone una lista completa:
7105 GSList* g_slist_alloc (void);
7107 void g_slist_free (GSList *list);
7109 void g_slist_free_1 (GSList *list);
7111 GSList* g_slist_append (GSList *list,
7114 GSList* g_slist_prepend (GSList *list,
7117 GSList* g_slist_insert (GSList *list,
7121 GSList* g_slist_remove (GSList *list,
7124 GSList* g_slist_remove_link (GSList *list,
7127 GSList* g_slist_reverse (GSList *list);
7129 GSList* g_slist_nth (GSList *list,
7132 GSList* g_slist_find (GSList *list,
7135 GSList* g_slist_last (GSList *list);
7137 gint g_slist_length (GSList *list);
7139 void g_slist_foreach (GSList *list,
7141 gpointer user_data);
7145 <!-- ----------------------------------------------------------------- -->
7146 <sect1>Gestione della memoria
7149 gpointer g_malloc (gulong size);
7152 Questa è una sostituta di malloc(). Non occorre controllare il valore
7153 restituito, in quanto lo fa già questa funzione.
7156 gpointer g_malloc0 (gulong size);
7159 Come la precedente, ma la memoria viene azzerata prima di restituire un
7163 gpointer g_realloc (gpointer mem,
7167 Riloca ``size'' byte di memoria che inizia a ``mem''. Ovviamente, la memoria
7168 dovrebbe essere stata allocata precedentemente.
7171 void g_free (gpointer mem);
7174 Libera la memoria. Facile!
7177 void g_mem_profile (void);
7180 Emette un profilo della memoria usata, ma occorre ricompilare e reinstallare
7181 la libreria aggiungendo #define MEM_PROFILE all'inizio del file glib/gmem.c.
7184 void g_mem_check (gpointer mem);
7187 Controlla che una locazione di memoria sia valida. Occorre ricompilare e
7188 reinstallare la libreria aggiungendo #define MEM_CHECK all'inizio del file
7191 <!-- ----------------------------------------------------------------- -->
7194 Funzioni legate ai timer...
7197 GTimer* g_timer_new (void);
7199 void g_timer_destroy (GTimer *timer);
7201 void g_timer_start (GTimer *timer);
7203 void g_timer_stop (GTimer *timer);
7205 void g_timer_reset (GTimer *timer);
7207 gdouble g_timer_elapsed (GTimer *timer,
7208 gulong *microseconds);
7211 <!-- ----------------------------------------------------------------- -->
7212 <sect1>Gestione delle stringhe
7214 Un'accozzaglia di funzioni per la gestione delle stringhe. Sembrano tutte molto
7215 interessanti, e probabilmente migliori per molte caratteristiche delle funzioni
7216 standard del C per le stringhe, ma necessitano di documentazione.
7219 GString* g_string_new (gchar *init);
7220 void g_string_free (GString *string,
7223 GString* g_string_assign (GString *lval,
7226 GString* g_string_truncate (GString *string,
7229 GString* g_string_append (GString *string,
7232 GString* g_string_append_c (GString *string,
7235 GString* g_string_prepend (GString *string,
7238 GString* g_string_prepend_c (GString *string,
7241 void g_string_sprintf (GString *string,
7245 void g_string_sprintfa (GString *string,
7250 <!-- ----------------------------------------------------------------- -->
7251 <sect1>Funzioni d'utilità e di errore
7254 gchar* g_strdup (const gchar *str);
7257 Funzione sostitutiva della strdup. Copia i contenuti originari delle stringhe
7258 in memoria appena allocata, restituendo un puntatore ad essa.
7261 gchar* g_strerror (gint errnum);
7263 Si raccomanda di usare questa gunzione per tutti i messaggi di errore. E' molto
7264 più graziosa, e più portabile di perror() o di altre. L'output di solito ha la
7268 nome programma:funzione fallita:file o altre descrizioni:strerror
7271 Di seguito un esempio di una chiamata di questo tipo usata nel nostro
7272 programma Hello World:
7275 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
7279 void g_error (gchar *format, ...);
7282 Visualizza un messaggio di errore. Il formato è come quello di printf,
7283 ma prepone ``** ERROR **: '' al messaggio e termina il programma. Da usare solo
7287 void g_warning (gchar *format, ...);
7290 Come la precedente, ma prepone ``** WARNING **: '' e non termina il programma.
7293 void g_message (gchar *format, ...);
7296 Visualizza ``message: '' e poi il messaggio.
7299 void g_print (gchar *format, ...);
7302 Sostituta di printf().
7307 gchar* g_strsignal (gint signum);
7310 Visualizza il nome del messaggio del sistema Unix associato al numero di
7311 segnale. Utile nelle funzioni generiche di gestione dei segnali.
7313 Tutte le funzioni elencate sono più o meno prese da glib.h. Se qualcuno volesse
7314 documentare qualche funzione, mandi una email all'autore!
7316 <!-- ***************************************************************** -->
7317 <sect>I file rc di GTK
7318 <!-- ***************************************************************** -->
7321 GTK ha un suo modo di trattare le preferenze delle applicazioni, usando
7322 i file rc. Questi possono essere usati per scegliere i colori di quasi tutti
7323 i widget, e possono anche essere usati per inserire delle pixmap nello sfondo
7326 <!-- ----------------------------------------------------------------- -->
7327 <sect1>Funzioni per i file rc
7329 All'inizio della vostra applicazione dovrebbe esserci una chiamata a
7331 void gtk_rc_parse (char *filename);
7334 passando come parametro il nome del vostro file rc. Questo farà si che GTK
7335 analizzi tale file e usi le impostazioni di stile per i tipi di widget ivi
7338 Se si desidera avere un insieme speciale di widget che abbia uno stile diverso
7339 dagli altri, o qualsiasi altra divisione logica dei widget, si chiami
7341 void gtk_widget_set_name (GtkWidget *widget,
7345 passando un widget appena creato come primo argomento, e il nome che gli si
7346 vuole dare come secondo. Questo consentirà di cambiare gli attributi di
7347 questo widget per nome tramite il file rc.
7349 Effettuando una chiamata come questa:
7352 button = gtk_button_new_with_label ("Special Button");
7353 gtk_widget_set_name (button, "special button");
7356 allora a questo bottone viene dato il nome ``special button'' ed esso può essere
7357 riferito per nome nel file rc come ``special button.GtkButton''. [<--- Verificatemi!]
7359 Il seguente esempio di file rc imposta le proprietà della finestra principale,
7360 e fa si che tutti i figli di questa finestra ereditino lo stile descritto
7361 dallo stile ``main button''. Il codice usato nell'applicazione è:
7364 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7365 gtk_widget_set_name (window, "main window");
7368 Lo stile viene definito nel file rc usando:
7371 widget "main window.*GtkButton*" style "main_button"
7374 che assegna a tutti i widget GtkButton nella finestra principale lo stile
7375 ``main_buttons'' secondo la definizione data nel file rc.
7377 Come si può vedere, questo sistema è molto potente e flessibile. Usate la
7378 vostra immaginazione per trarre il massimo vantaggio da esso.
7380 <!-- ----------------------------------------------------------------- -->
7381 <sect1>Il formato dei file rc di GTK
7383 Nell'esempio che segue viene illustrato il formato del file GTK. Si tratta
7384 del file testgkrc dalla distribuzione del GTK, a cui sono stati aggiunti
7385 vari commenti e varie cose. Potete includere questa spiegazione nella
7386 vostra applicazione per consentire all'utente di personalizzarla finemente.
7388 There are several directives to change the attributes of a widget.
7389 Ci sono diverse direttive per cambiare gli attributi di un widget.
7391 <item>fg - Assegna il colore di primo piano di un widget.
7392 <item>bg - Assegna il colore di sfondo di un widget.
7393 <item>bg_pixmap - Inserisce nello sfondo di un widget una pixmap.
7394 <item>font - Sceglie il font da usarsi con il dato widget.
7397 Inoltre ci sono diversi stati in cui può trovarsi un widget, e si possono
7398 assegnare diversi colori, pixmap e font per ogni stato. Essi sono:
7400 <item>NORMAL - Lo stato normale di un widget, quando il mouse non si trova su
7401 di esso, quando non è premuto, ecc.
7402 <item>PRELIGHT (evidenziato)- Quando il mouse si trova sopra al widget
7403 verranno usati i colori assegnati per questo stato.
7404 <item>ACTIVE (attivo) - Quando il widget è premuto o cliccato esso sarà attivo,
7405 e verranno usati gli attributi assegnati da questa etichetta.
7406 <item>INSENSITIVE (insensibile)- Quando un widget viene reso insensibile,
7407 e non può essere attivato, prenderà questi attributi.
7408 <item>SELECTED (selezionato) - Quando un oggetto viene selezionato, prende
7412 Quando si usano le parole chiave ``fg'' e ``bg'' per assegnare i colori dei
7413 widget il formato è:
7415 fg[<STATE>] = { Rosso, Verde, Blu }
7418 Dove STATE è uno degli stati visti prima (PRELIGHT, ACTIVE ecc.), e Rosso,
7419 Verde e Blu sono valori nell'intervallo 0 - 1.0; { 1.0, 1.0, 1.0 } rappresenta
7421 Devono essere in formato float, o verranno visti come 0, sicché un ``1'' diretto
7422 non funziona, deve essere ``1.0''. Uno ``0'' diretto va invece bene, poiché poco
7423 importa se non viene riconosciuto: valori non riconosciuti vengono considerati
7426 bg_pixmap è molto simile al precedente, tranne per i colori che vengono
7427 sostituiti dal nome di un file.
7429 pixmap_path è una lista di percorsi separati da ``:''. In questi percorsi vengono
7430 cercate le pixmap specificate.
7432 La direttiva font è semplicemente:
7434 font = "<font name>"
7437 dove l'unica parte complicata è immaginare la stringa del font. Allo scopo
7438 può servire usare xfontsel o una utilità analoga.
7440 ``widget_class'' assegna lo stile di una classe di widget. Queste classi sono
7441 elencate nell'introduzione ai widget sulla gerarchia delle classi.
7443 La direttiva ``widget'' assegna un insieme di widget dal nome specificato ad
7444 un dato stile, annullando qualsiasi stile assegnato per la data classe di widget.
7445 Questi widget vengono registrati nell'applicazione usando la chiamata
7446 gtk_widget_set_name(). Questo consente di specificare gli attributi di un
7447 widget singlarmente, piuttosto che assegnando gli attributi di un'intera classe
7448 di widget. E' opportuno documentare tutti questi widget speciali in modo che
7449 gli utenti possano personalizzarli.
7451 Quando la parola chiave ``<tt>parent</>'' viene usata come un attributo, il
7452 widget erediterà gli attributi del suo genitore nell'applicazione.
7454 Quando si definisce uno stile si possono assegnare gli attributi di uno
7455 stile definito precedentemente a quello nuovo.
7457 style "main_button" = "button"
7459 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
7460 bg[PRELIGHT] = { 0.75, 0, 0 }
7464 Questo esempio prende lo stile ``button'' e crea un nuovo stile
7465 semplicemente cambiando il font e il colore di sfondo dello stato ``prelight''
7466 nello stile ``button''.
7468 Naturalmente, molti di questi attributi non sono applicabili a tutti i widget.
7469 E' veramente un semplice problema di buon senso. Tutto quello che potrebbe
7470 applicarsi, dovrebbe.
7472 <!-- ----------------------------------------------------------------- -->
7473 <sect1>Esempio di file rc
7477 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
7479 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
7481 # style <name> [= <name>]
7486 # widget <widget_set> style <style_name>
7487 # widget_class <widget_class_set> style <style_name>
7490 # Ecco una lista di tutti gli stati possibili. Si noti che alcuni non sono
7491 # applicabili a certi widget.
7493 # NORMAL - Lo stato normale di un widget, quando il mouse non si trova su
7494 # di esso, quando non è premuto, ecc.
7496 # PRELIGHT (evidenziato)- Quando il mouse si trova sopra al widget
7497 # verranno usati i colori assegnati per questo stato.
7499 # ACTIVE (attivo) - Quando il widget è premuto o cliccato esso sarà attivo,
7500 # e verranno usati gli attributi assegnati da questa etichetta.
7502 # INSENSITIVE (insensibile)- Quando un widget viene reso insensibile,
7503 # e non può essere attivato, prenderà questi attributi.
7505 # SELECTED (selezionato) - Quando un oggetto viene selezionato, prende
7508 # Dati questi stati, è possibile assegnare gli attributi dei widget in
7509 # ognuno di questi stati usando le seguenti direttive.
7511 # fg - Assegna il colore di primo piano di un widget.
7512 # bg - Assegna il colore di sfondo di un widget.
7513 # bg_pixmap - Inserisce nello sfondo di un widget una pixmap.
7514 # font - Sceglie il font da usarsi con il dato widget.
7517 # Questo è uno stile chiamato "button". Il nome non è veramente importante,
7518 # in quanto viene assegnato ai veri widget alla fine del file.
7522 # Questo inserisce nella spaziatura attorno alla finestra la pixmap
7524 #bg_pixmap[<STATE>] = "<pixmap filename>"
7525 bg_pixmap[NORMAL] = "warning.xpm"
7530 # Mette il colore di primo piano (il colore del font) a rosso nello
7533 fg[NORMAL] = { 1.0, 0, 0 }
7535 # Inserisce nello sfondo del gadget la stessa pixmap usata dal suo genitore.
7536 bg_pixmap[NORMAL] = "<parent>"
7541 # Questo mostra tutti i possibili stati per un bottone. L'unico che
7542 # non è applicabile è lo stato "SELECTED".
7544 fg[PRELIGHT] = { 0, 1.0, 1.0 }
7545 bg[PRELIGHT] = { 0, 0, 1.0 }
7546 bg[ACTIVE] = { 1.0, 0, 0 }
7547 fg[ACTIVE] = { 0, 1.0, 0 }
7548 bg[NORMAL] = { 1.0, 1.0, 0 }
7549 fg[NORMAL] = { .99, 0, .99 }
7550 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
7551 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
7554 # In questi esempio ereditiamo gli attributi dello stile "button" e poi
7555 # alteriamo il font e il colore di sfondo quando evidenziato per creare
7556 # un nuovo stile "main_button".
7558 style "main_button" = "button"
7560 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
7561 bg[PRELIGHT] = { 0.75, 0, 0 }
7564 style "toggle_button" = "button"
7566 fg[NORMAL] = { 1.0, 0, 0 }
7567 fg[ACTIVE] = { 1.0, 0, 0 }
7569 # Questo seleziona come pixmap di sfondo per il toggle_button quella del
7570 # suo widget genitore (definita nell'applicazione).
7571 bg_pixmap[NORMAL] = "<parent>"
7576 bg_pixmap[NORMAL] = "marble.xpm"
7577 fg[NORMAL] = { 1.0, 1.0, 1.0 }
7582 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
7585 # pixmap_path "~/.pixmaps"
7587 # Queste assegnano ai tipi di widget gli stili definiti prima.
7588 # I tipi di widget sono elencati nella gerarchia delle classi, ma probabilmente
7589 # dovrebbero essere elencati in questo documento come riferimento per l'utente.
7591 widget_class "GtkWindow" style "window"
7592 widget_class "GtkDialog" style "window"
7593 widget_class "GtkFileSelection" style "window"
7594 widget_class "*Gtk*Scale" style "scale"
7595 widget_class "*GtkCheckButton*" style "toggle_button"
7596 widget_class "*GtkRadioButton*" style "toggle_button"
7597 widget_class "*GtkButton*" style "button"
7598 widget_class "*Ruler" style "ruler"
7599 widget_class "*GtkText" style "text"
7601 # Questo assegna lo stile main_button a tutti i bottoni che sono figli della
7602 # "main window" (finestra principale). Questi devono essere documenati per
7603 # potersene avvantaggiare.
7604 widget "main window.*GtkButton*" style "main_button"
7608 <!-- ***************************************************************** -->
7609 <sect>Scrivere un proprio Widget
7610 <!-- ***************************************************************** -->
7612 <!-- ----------------------------------------------------------------- -->
7615 Anche se la distribuzione GTK contiene molto tipi di widget che possono
7616 coprire molte necessità basilari, può essere necessario costruirsi
7617 un proprio widget. GTK usa molto l'ereditarietà tra i vari
7618 widget e, di solito, vi è un widget che si avvicina a quello che ti
7619 servirebbe, ed è spesso possibile creare un nuovo widget con poche linee
7620 di codice. Ma prima di iniziare il lavoro su un nuovo widget, vediamo
7621 se qualcuno non lo ha già creato. Questo eviterà un duplicazione
7622 di lavoro e farà sì che i widget non-GTK puri siano minimi, così da
7623 aiutare sia chi crea il codice che chi l'interfaccia per applicazioni GTK
7624 molto grosse. D'altra parte, quando hai finito di scrivere un widget,
7625 annuncialo a tutto il mondo così che le altre persone ne possano
7626 beneficiare. Il miglioro modo dove farlo è la <tt>gtk-list</tt>.
7628 I sorgenti completi per i widget di esempio possono essere presi dallo stesso
7629 sito da cui avete scaricato questo tutorial, oppure da:
7631 <htmlurl url="http://www.msc.cornell.edu/~otaylor/gtk-gimp/tutorial"
7632 name="http://www.msc.cornell.edu/~otaylor/gtk-gimp/tutorial">
7635 <!-- ----------------------------------------------------------------- -->
7636 <sect1> L'anatomia di un widget
7639 Per creare un nuovo widget è importante aver capito come gli ogetti
7640 di GTK lavorano. Questa sezione è solo una breve spiegazione. Guarda la
7641 documentazione di riferimento per maggiori dettagli.
7644 I widget GTK sono implementati in un modo orientato agli oggetti,
7645 anche se usando il C standard. Questo aumenta notevolmente la portabilità
7646 e la stabilità, specialmente per le correnti generazioni di compilatori C++;
7647 comunque questo significa che chi scrive un widget deve fare attenzione
7648 ad alcuni dettagli di implementazione. L'informazione comune a tutte le
7649 istanze di una classe di widget (ad esempio: a tutti i bottoni) è memorizzata
7650 <em>class structure</em>. C'e' solamente una copia di questo in cui
7651 sono memorizzate le informazioni riguardanti i segnali della classe
7652 (assomiglia ad una funzione virtuale in C). Per supportare l'ereditarietà
7653 il primo campo della struttura di una classe deve essere una copia della
7654 struttura della classe genitore. La dichiarazione della struttura della
7655 classe GtkButton è:
7658 struct _GtkButtonClass
7660 GtkContainerClass parent_class;
7662 void (* pressed) (GtkButton *button);
7663 void (* released) (GtkButton *button);
7664 void (* clicked) (GtkButton *button);
7665 void (* enter) (GtkButton *button);
7666 void (* leave) (GtkButton *button);
7671 Quando un bottone viene trattato come un contenitore (ad esempio quando viene
7672 ridimensionato) si può fare il cast della struttura della sua classe con la
7673 GtkContainerClass, e usare i campi rilevanti per gestire i segnali.
7676 C'è anche una struttura per ogni widget che viene creata
7677 ad ogni istanza. Questa struttura ha campi per
7678 memorizzare le informazioni che sono differenti per ogni volta che il widget
7679 viene istanziato. Chiameremo questa struttura la <em> struttura
7680 oggetto</em>. Per la classe Bottone, questa ha l'aspetto:
7685 GtkContainer container;
7689 guint in_button : 1;
7690 guint button_down : 1;
7695 Si noti che, similmente alla struttura della classe, il primo campo
7696 è la struttura dell'oggetto della classe madre, così che, se necessario, si può fare il
7697 cast di questa struttura con quella dell'oggetto della classe madre.
7699 <!-- ----------------------------------------------------------------- -->
7700 <sect1> Creare un Widget composto
7702 <!-- ----------------------------------------------------------------- -->
7703 <sect2> Introduzione
7706 Un tipo di widget a cui potreste essere interessati è un widget che
7707 è semplicemnte un aggregato di altri widget GTK. Questo tipo di
7708 widget non fa nulla che non possa essere fatto creando un nuovo
7709 widget, ma fornisce un modo conveniente per inscatolare elementi
7710 dell'interfaccia utente per poi riutilizzarli.
7711 I widget FileSelection e ColorSelection della ditribuzione standard
7712 sono esempi di questo tipo di widget.
7715 Il widget di esempio che creeremo in questo capitolo è il
7716 Tictactoe, un vettore 3x3 di bottoni a commutazione il quale emette
7717 un segnale quando tutti e 3 i bottoni di una riga, colonna o di una
7718 diagonale sono premuti.
7720 <!-- ----------------------------------------------------------------- -->
7721 <sect2> Scegliere la classe madre
7724 La classe madre per un widget composto e' tipicamente la classe
7725 contenitrice che racchiude tutti gli elementi del widget composto.
7726 Per esempio, la classe madre del widget FileSelection è la classe
7727 Dialog. Visto che i nostri bottoni sono inseriti in una tabella, è
7728 naturale pensare che la nostra classe madre possa essere la GtkTable.
7729 Sfortunatamente, così non è. La creazione di un widget è diviso
7730 tra 2 funzioni : la funzione <tt/WIDGETNAME_new()/ che viene invocata
7731 dall'utente, e la funzione <tt/WIDGETNAME_init()/ che ha il compito
7732 principale di inizializzare il widget che è indipendente dai valori
7733 passati alla funzione <tt/_new()/. Widget figli o discendenti possono
7734 chiamare, solamente, la funzione del loro widget genitore.
7735 Ma questa divisione del lavoro non funziona bene per la tabella, la
7736 quale, quando creata, necessita di conoscere il numero di righe e
7737 colonne che la comporrà. A meno che non vogliamo duplicare molte delle
7738 fuinzionalità della <tt/gtk_table_new()/ nel nostro widget
7739 Tictactoe, faremmo meglio a evitare di derivarlo dalla GtkTable. Per questa
7740 ragione lo deriviamo invece da GtkVBox, e uniamo la nostra tabella
7743 <!-- ----------------------------------------------------------------- -->
7744 <sect2> Il File Header
7747 Ogni classe di widget ha un file header il quale dichiara l'oggetto e la
7748 struttura della classe del widget, comprese le funzioni pubbliche.
7749 Per prevenire duplicati di definizioni, noi includiamo l'intero file header fra:
7752 #ifndef __TICTACTOE_H__
7753 #define __TICTACTOE_H__
7757 #endif /* __TICTACTOE_H__ */
7760 E per far felici i programmi in C++ che includono il nostro file header, in:
7765 #endif /* __cplusplus */
7771 #endif /* __cplusplus */
7774 Insieme alle funzioni e alle strutture, dichiariamo tre macro
7775 standard nel nostro file header, <tt/TICTACTOE(obj)/,
7776 <tt/TICTACTOE_CLASS(klass)/, e <tt/IS_TICTACTOE(obj)/, i quali rispettivamente
7777 fanno il cast di un puntatore ad un puntatore ad un ogetto od ad una struttura
7778 di classe, e guarda se un oggetto è un widget Tictactoe.
7781 Qui vi è il file header completo:
7786 #ifndef __TICTACTOE_H__
7787 #define __TICTACTOE_H__
7789 #include <gdk/gdk.h>
7790 #include <gtk/gtkvbox.h>
7794 #endif /* __cplusplus */
7796 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
7797 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
7798 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
7801 typedef struct _Tictactoe Tictactoe;
7802 typedef struct _TictactoeClass TictactoeClass;
7808 GtkWidget *buttons[3][3];
7811 struct _TictactoeClass
7813 GtkVBoxClass parent_class;
7815 void (* tictactoe) (Tictactoe *ttt);
7818 guint tictactoe_get_type (void);
7819 GtkWidget* tictactoe_new (void);
7820 void tictactoe_clear (Tictactoe *ttt);
7824 #endif /* __cplusplus */
7826 #endif /* __TICTACTOE_H__ */
7830 <!-- ----------------------------------------------------------------- -->
7831 <sect2> La funzione <tt/_get_type()/
7834 Continuiamo ora con l'implementazione del nostro widget. Una funzione
7835 basilare di ogni widget è la funzione <tt/WIDGETNAME_get_type()/.
7836 Questa funzione, quando chiamata la prima volta, comunica a GTK la classe
7837 del widget, e ottiene un identificativo univoco per la classe del
7838 widget. Chiamate successive restituiscono semplicemente l'identificativo.
7842 tictactoe_get_type ()
7844 static guint ttt_type = 0;
7848 GtkTypeInfo ttt_info =
7852 sizeof (TictactoeClass),
7853 (GtkClassInitFunc) tictactoe_class_init,
7854 (GtkObjectInitFunc) tictactoe_init,
7855 (GtkArgSetFunc) NULL,
7856 (GtkArgGetFunc) NULL
7859 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
7867 La struttura GtkTypeInfo ha la seguente definizione:
7875 GtkClassInitFunc class_init_func;
7876 GtkObjectInitFunc object_init_func;
7877 GtkArgSetFunc arg_set_func;
7878 GtkArgGetFunc arg_get_func;
7883 I campi di questa struttura sono abbastanza auto-esplicativi.
7884 Ignoreremo, per ora, i campi <tt/arg_set_func/ e <tt/arg_get_func/:
7885 hanno un ruolo importante, ma ancora largamente non
7886 implementato, nel permettere ai linguaggi interpretati
7887 di settare convenientemente le opzioni del widget.
7888 Una volta che il GTK ha completato correttamente una copia di questa
7889 struttura, sa come creare un oggetto di un particolare widget.
7891 <!-- ----------------------------------------------------------------- -->
7892 <sect2> La funzione <tt/_class_init()/
7894 La funzione <tt/WIDGETNAME_class_init()/ inizialiazza i campi della
7895 struttura della classe del widget, e setta ogni segnale della classe.
7896 Per il nostro widget Tictactoe ha il seguente aspetto:
7905 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
7908 tictactoe_class_init (TictactoeClass *class)
7910 GtkObjectClass *object_class;
7912 object_class = (GtkObjectClass*) class;
7914 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
7917 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
7918 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
7921 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
7923 class->tictactoe = NULL;
7928 Il nostro widget ha semplicemente il segnale ``tictactoe'' che è
7929 invocato quando una riga, colonna o diagonale è completamente premuta.
7930 Non tutti i widget composti necessitano di segnali, quindi se stai
7931 leggendo questo per la prima volta, puoi anche saltare alla prossima sezione,
7932 dal momento che a questo punto le cose diventano un po' complicate.
7936 gint gtk_signal_new (const gchar *name,
7937 GtkSignalRunType run_type,
7938 GtkType object_type,
7939 gint function_offset,
7940 GtkSignalMarshaller marshaller,
7947 crea un nuovo segnale. I parametri sono:
7950 <item> <tt/name/: Il nome del segnale.
7951 <item> <tt/run_type/: Se il segstore predefinito viene eseguito prima o dopo
7952 di quello dell'utente. Di norma questo sarà <tt/GTK_RUN_FIRST/, o <tt/GTK_RUN_LAST/,
7953 anche se ci sono altre possibilità.
7954 <item> <tt/object_type/: l'identificativo dell'oggetto a cui questo segnale si
7955 riferisce. Esso sarà anche applicato agli oggetti discendenti.
7956 <item> <tt/function_offset/: L'offset nella struttura della classe di un
7957 puntatore al gestore predefinito.
7958 <item> <tt/marshaller/: una funzione che è usata per invocare il gestore
7959 del segnale. Per gestori di segnali che non hanno argomenti oltre
7960 all'oggetto che emette il segnale e i dati dell'utente, possiamo usare
7961 la funzione predefinita <tt/gtk_signal_default_marshaller/
7962 <item> <tt/return_val/: Il tipo del valore di ritorno.
7963 <item> <tt/nparams/: Il numero di parametri del gestore di segnali (oltre
7964 ai due predefiniti menzionati sopra)
7965 <item> <tt/.../: i tipi dei parametri
7968 Quando si specificano i tipi, si usa l'enumerazione <tt/GtkType/:
7993 /* sarebbe bello poter togliere alla fine i prossimi due */
7995 GTK_TYPE_C_CALLBACK,
7999 } GtkFundamentalType;
8003 <tt/gtk_signal_new()/ restituisce un identificatore unico intero per il segnale,
8004 che memorizziamo nel vettore <tt/tictactoe_signals/, che
8005 indicizzeremo usando una enumerazione. (Convenzionalmente, gli elementi dell'enumerazione
8006 sono i nomi dei segnali, in maiuscolo,
8007 ma qui ci potrebbe essere un conflitto con la macro <tt/TICTACTOE()/,
8008 quindi l'abbiamo chiamato <tt/TICTACTOE_SIGNAL/
8010 Dopo aver creato un nostro segnale, abbiamo bisogno di dire a GTK
8011 di associare il nostro segnale alla classe Tictactoe. Lo facciamo
8012 invocando <tt/gtk_object_class_add_signals()/. Settiamo quindi a NULL
8013 il puntatore che punta al gestore predefinito per il segnale
8014 ``tictactoe'' a NULL, indicando che non ci sono azioni predefinite.
8016 <!-- ----------------------------------------------------------------- -->
8017 <sect2> La funzione <tt/_init()/
8021 Ogni classe di Widget necessita anche di una funzione per inizializzare
8022 la struttura dell'oggetto. Usualmente questa funzione ha il ruolo abbastanza
8023 limitato di assegnare ai campi della struttura i valori predefiniti.
8024 Per widget composti, comunque, questa funzione crea, anche,
8025 i widget componenti del widget composto.
8030 tictactoe_init (Tictactoe *ttt)
8035 table = gtk_table_new (3, 3, TRUE);
8036 gtk_container_add (GTK_CONTAINER(ttt), table);
8037 gtk_widget_show (table);
8042 ttt->buttons[i][j] = gtk_toggle_button_new ();
8043 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
8045 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
8046 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
8047 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
8048 gtk_widget_show (ttt->buttons[i][j]);
8053 <!-- ----------------------------------------------------------------- -->
8054 <sect2> E il resto...
8058 C'è un'altra funzione che ogni widget (eccetto i Widget di base come
8059 GtkBin che non possono essere instanziati) deve avere : la funzione
8060 che l'utente invoca per creare un oggetto di quel tipo. Questa è
8061 convenzionalmente chiamata <tt/WIDGETNAME_new()/. In alcuni widget,
8062 non nel caso del nostro Tictactoe, questa funzione richiede degli
8063 argomenti, e fa alcune operazioni basandosi su di essi. Le altre
8064 due funzioni sono specifiche del widget Tictactoe.
8067 <tt/tictactoe_clear()/ è una funzione pubblica che resetta tutti i
8068 bottoni, nel widget, allo stato iniziale (non premuto). Notate l'uso
8069 di <tt/gtk_signal_handler_block_by_data()/ per impedire che il nostro
8070 gestore dei segnali venga attivato quando non ce n'è bisogno.
8073 <tt/tictactoe_toggle()/ è il gestore del segnale che viene invocato
8074 quando l'utente preme il bottone. Esso guarda se vi è
8075 qualche combinazione vincente che coinvolge i bottoni premuti, e nel
8076 caso ci fosse, emette il segnale ``tictactoe''.
8082 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
8086 tictactoe_clear (Tictactoe *ttt)
8093 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
8094 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
8096 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
8101 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
8105 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
8106 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
8107 { 0, 1, 2 }, { 0, 1, 2 } };
8108 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
8109 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
8110 { 0, 1, 2 }, { 2, 1, 0 } };
8121 success = success &&
8122 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
8124 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
8127 if (success && found)
8129 gtk_signal_emit (GTK_OBJECT (ttt),
8130 tictactoe_signals[TICTACTOE_SIGNAL]);
8139 E finalmente un programma di esempio che usa il nostro widget
8143 #include <gtk/gtk.h>
8144 #include "tictactoe.h"
8146 /* Invocato quando una riga, colonna o diagonale e' completata. */
8148 win (GtkWidget *widget, gpointer data)
8151 tictactoe_clear (TICTACTOE (widget));
8155 main (int argc, char *argv[])
8160 gtk_init (&argc, &argv);
8162 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8164 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
8166 gtk_signal_connect (GTK_OBJECT (window), "destroy",
8167 GTK_SIGNAL_FUNC (gtk_exit), NULL);
8169 gtk_container_border_width (GTK_CONTAINER (window), 10);
8171 /* Crea un nuovo widget Tictactoe. */
8172 ttt = tictactoe_new ();
8173 gtk_container_add (GTK_CONTAINER (window), ttt);
8174 gtk_widget_show (ttt);
8176 /* E gli aggancia il segnale "tictactoe" */
8177 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
8178 GTK_SIGNAL_FUNC (win), NULL);
8180 gtk_widget_show (window);
8189 <!-- ----------------------------------------------------------------- -->
8190 <sect1> Creare un widget a partire da zero
8192 <!-- ----------------------------------------------------------------- -->
8193 <sect2> Introduzione
8197 In questa sezione impareremo meglio come i widget si mostrano sullo schermo
8198 e interagiscono con gli eventi. Come esempio, creeremo
8199 un widget di quadrante analogico con un puntatore che l'utente
8200 può trascinare per assegnare il valore.
8202 <!-- ----------------------------------------------------------------- -->
8203 <sect2> Mostrare un widget sullo schermo
8206 Ci sono alcuni passi che sono necessari nella visualizzazione sullo
8207 schermo. Dopo che il widget è stato creato con una chiamata a
8208 <tt/WIDGETNAME_new()/, sono necessarie alcune altre funzioni:
8211 <item> <tt/WIDGETNAME_realize()/ è responsabile della creazione di
8212 una finestra X per il widget se ne ha una.
8213 <item> <tt/WIDGETNAME_map()/ è invocata dopo che l'utente ha
8214 chiamato <tt/gtk_widget_show()/. E' responsabile di vedere se il
8215 widget è attualmente disegnato sullo schermo (<em/mappato/). Per
8216 una classe contenitore, essa deve anche creare chiamate alle
8217 funzioni <tt/map()/> per ogni widget figlio.
8218 <item> <tt/WIDGETNAME_draw()/ è invocata quando
8219 <tt/gtk_widget_draw()/ viene chiamata per il widget o per uno dei suoi
8220 predecessori. Esso fa sì che l'attuale chiamata alla
8221 funzione di disegno del widget disegni il widget sullo schermo.
8222 Per la classe contenitore, questa funzione deve eseguire le
8223 chiamate alla funzioni <tt/gtk_widget_draw()/ di ogni suo widget
8225 <item> <tt/WIDGETNAME_expose()/ è un gestore per l'evento di esposizione
8226 per il widget. Esso crea le chiamate necessarie alle funzioni di disegno
8227 per disegnare la porzione che si è resa visibile. Per le classi
8228 contenitore, questa funzione deve generare gli eventi di ``expose'' per
8229 tutti i widget figli che non hanno una propria finestra (se essi hanno
8230 una loro finestra, sarà X che genererà i necessari eventi di expose).
8234 Potete notare che le ultime due funzioni sono molto simili, ognuna è
8235 responsabile per il disegno del widget sullo schermo. Infatti molti
8236 tipi di widget non sanno relamente la differenza tra le due.
8237 La funzione di predefinita <tt/draw()/ nella classe widget, semplicemente
8238 genera un sintetico evento di ``expose'' per l'area da ridisegnare.
8239 Comunque, alcuni tipi di widget possono risparmiare tempo distinguendo
8240 le due funzioni. Per esempio, se un widget ha piu' finestre X, allora
8241 visto che l'evento ``expose'' identifica solo la finestra esposta,
8242 esso può ridisegnare solo la finestra interessata, cosa che non è
8243 possibile per chiamate a <tt/draw()/.
8246 I widget contenitori, anche se essi non farebbero differenze,
8247 non possono semplicemente usare la funzione <tt/draw()/ perchè per i
8248 loro widget figli la differenza potrebbere essere importante. Comunque,
8249 sarebbe uno spreco duplicare il codice di disegno nelle due
8250 funzioni. La convenzione è che questi widget abbiano una funzione
8251 chiamata <tt/WIDGETNAME_paint()/ che disegna il widget, che è poi
8252 chiamata dalle funzioni <tt/draw()/ e <tt/expose()/
8255 Nell'approccio del nostro esempio, visto che il widget, ha
8256 una sola finestra, possiamo utilizzare il modo piu' semplice
8257 ed usare la funzione predefinita <tt/draw()/ e implementare
8258 solamente la funzione <tt/expose()/.
8260 <!-- ----------------------------------------------------------------- -->
8261 <sect2> Le origini del widget Dial
8264 Come tutti gli animali terresti sono semplicemente varianti del primo
8265 amfibio, i widget Gtk tendono ad essere varianti di altri widget, precedentemente
8266 scritti. Così, anche se questa sezione è intitolata ``Creare
8267 un widget a partire da zero", il nostro widget inizia in realtà con il codice
8268 sorgente del widget Range. Questo è stato preso come punto d'inizio
8269 perche' sarebbe carino se il nostro widget avesse la
8270 stessa interfaccia del widget Scale il quale è semplicemente una
8271 specializzazione del widget Range. Così, sebbene il codice sorgente e'
8272 presentato sotto in forma definitiva, non si deve pensare che sia stato
8273 scritto <em>deus ex machina</em> in questo modo. Se poi non avete familiarità
8274 con il funzionamento del widget Scale dal punto di vista di chi scrive
8275 un'applicazione, potrebbe essere una buona idea guardare indietro prima
8278 <!-- ----------------------------------------------------------------- -->
8282 Una parte del nostro widget potrebbe essere simile
8283 al widget Tictactoe. In primo luogo, abbiamo il file header:
8286 /* GTK - The GIMP Toolkit
8287 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
8289 * This library is free software; you can redistribute it and/or
8290 * modify it under the terms of the GNU Library General Public
8291 * License as published by the Free Software Foundation; either
8292 * version 2 of the License, or (at your option) any later version.
8294 * This library is distributed in the hope that it will be useful,
8295 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8296 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8297 * Library General Public License for more details.
8299 * You should have received a copy of the GNU Library General Public
8300 * License along with this library; if not, write to the Free
8301 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
8304 #ifndef __GTK_DIAL_H__
8305 #define __GTK_DIAL_H__
8307 #include <gdk/gdk.h>
8308 #include <gtk/gtkadjustment.h>
8309 #include <gtk/gtkwidget.h>
8314 #endif /* __cplusplus */
8317 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
8318 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
8319 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
8322 typedef struct _GtkDial GtkDial;
8323 typedef struct _GtkDialClass GtkDialClass;
8329 /* Politica di update (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
8332 /* Bottone correntemente premuto o 0 altrimenti */
8335 /* Dimensione della componente Dial. */
8339 /* ID del timer di update, o 0 altrimenti */
8342 /* Angolo corrente. */
8345 /* Vecchi valori dell'aggiustamento così sappiamo quando
8346 * qualcosa cambia */
8351 /* L'oggetto adjustament che memorizza i dati per questo dial */
8352 GtkAdjustment *adjustment;
8355 struct _GtkDialClass
8357 GtkWidgetClass parent_class;
8361 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
8362 guint gtk_dial_get_type (void);
8363 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
8364 void gtk_dial_set_update_policy (GtkDial *dial,
8365 GtkUpdateType policy);
8367 void gtk_dial_set_adjustment (GtkDial *dial,
8368 GtkAdjustment *adjustment);
8371 #endif /* __cplusplus */
8374 #endif /* __GTK_DIAL_H__ */
8377 Essendoci più cose da fare con questo widget, rispetto al precedente,
8378 abbiamo più cambi nella struttura dati, ma le altre cose sono
8381 Dopo aver incluso i file di header e aver dichiarato alcune costanti,
8382 dobbiamo fornire alcune funzioni circa il widget e la sua
8388 #include <gtk/gtkmain.h>
8389 #include <gtk/gtksignal.h>
8391 #include "gtkdial.h"
8393 #define SCROLL_DELAY_LENGTH 300
8394 #define DIAL_DEFAULT_SIZE 100
8396 /* Dichiarazioni di funzioni successive */
8398 [ omesse per salvare spazio ]
8400 /* variabili locali. */
8402 static GtkWidgetClass *parent_class = NULL;
8405 gtk_dial_get_type ()
8407 static guint dial_type = 0;
8411 GtkTypeInfo dial_info =
8415 sizeof (GtkDialClass),
8416 (GtkClassInitFunc) gtk_dial_class_init,
8417 (GtkObjectInitFunc) gtk_dial_init,
8418 (GtkArgSetFunc) NULL,
8419 (GtkArgGetFunc) NULL,
8422 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
8429 gtk_dial_class_init (GtkDialClass *class)
8431 GtkObjectClass *object_class;
8432 GtkWidgetClass *widget_class;
8434 object_class = (GtkObjectClass*) class;
8435 widget_class = (GtkWidgetClass*) class;
8437 parent_class = gtk_type_class (gtk_widget_get_type ());
8439 object_class->destroy = gtk_dial_destroy;
8441 widget_class->realize = gtk_dial_realize;
8442 widget_class->expose_event = gtk_dial_expose;
8443 widget_class->size_request = gtk_dial_size_request;
8444 widget_class->size_allocate = gtk_dial_size_allocate;
8445 widget_class->button_press_event = gtk_dial_button_press;
8446 widget_class->button_release_event = gtk_dial_button_release;
8447 widget_class->motion_notify_event = gtk_dial_motion_notify;
8451 gtk_dial_init (GtkDial *dial)
8454 dial->policy = GTK_UPDATE_CONTINUOUS;
8457 dial->pointer_width = 0;
8459 dial->old_value = 0.0;
8460 dial->old_lower = 0.0;
8461 dial->old_upper = 0.0;
8462 dial->adjustment = NULL;
8466 gtk_dial_new (GtkAdjustment *adjustment)
8470 dial = gtk_type_new (gtk_dial_get_type ());
8473 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
8475 gtk_dial_set_adjustment (dial, adjustment);
8477 return GTK_WIDGET (dial);
8481 gtk_dial_destroy (GtkObject *object)
8485 g_return_if_fail (object != NULL);
8486 g_return_if_fail (GTK_IS_DIAL (object));
8488 dial = GTK_DIAL (object);
8490 if (dial->adjustment)
8491 gtk_object_unref (GTK_OBJECT (dial->adjustment));
8493 if (GTK_OBJECT_CLASS (parent_class)->destroy)
8494 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
8498 Notate che questa funzione <tt/init()/ fa meno rispetto all'analoga del
8499 widget Tictactoe, essendo questo un widget non composto, e la
8500 funzione <tt/new()/ fa di più, essendoci un argomento. Inoltre,
8501 notate che quando memorizziamo un puntatore all'oggetto Adjustment,
8502 incrementiamo il conteggio dei suoi riferimenti(e corrispondentemente
8503 lo decrementato quando non lo usiamo più) così che GTK può tener traccia di
8504 quando è possibile distruggerlo senza causare guai.
8507 Inoltre, ci sono alcune funzioni per manipolare le opzioni del widget:
8511 gtk_dial_get_adjustment (GtkDial *dial)
8513 g_return_val_if_fail (dial != NULL, NULL);
8514 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
8516 return dial->adjustment;
8520 gtk_dial_set_update_policy (GtkDial *dial,
8521 GtkUpdateType policy)
8523 g_return_if_fail (dial != NULL);
8524 g_return_if_fail (GTK_IS_DIAL (dial));
8526 dial->policy = policy;
8530 gtk_dial_set_adjustment (GtkDial *dial,
8531 GtkAdjustment *adjustment)
8533 g_return_if_fail (dial != NULL);
8534 g_return_if_fail (GTK_IS_DIAL (dial));
8536 if (dial->adjustment)
8538 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
8539 gtk_object_unref (GTK_OBJECT (dial->adjustment));
8542 dial->adjustment = adjustment;
8543 gtk_object_ref (GTK_OBJECT (dial->adjustment));
8545 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
8546 (GtkSignalFunc) gtk_dial_adjustment_changed,
8548 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
8549 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
8552 dial->old_value = adjustment->value;
8553 dial->old_lower = adjustment->lower;
8554 dial->old_upper = adjustment->upper;
8556 gtk_dial_update (dial);
8560 <!-- ----------------------------------------------------------------- -->
8561 <sect2> <tt/gtk_dial_realize()/
8564 Abbiamo ora raggiunto alcuni nuovi tipi di funzione. In primo luogo,
8565 abbiamo una funzione che crea la finestra di X. Noterete che viene
8566 passata alla funzione <tt/gdk_window_new()/ una maschera che
8567 specifica quali campi della struttura GdkWindowAttr non sono vuoti
8568 (ai rimanenti campi può essere dato il valore predefinito). Anche
8569 il modo con cui la maschera degli eventi del widget creata non è
8570 complicato. Chiameremo <tt/gtk_widget_get_events()/ per sapere la
8571 maschera degli eventi che l'utente ha specificato per questo widget
8572 (con <tt/gtk_widget_set_events()/) e aggiungeremo gli eventi che ci possono
8576 Dopo aver creato la finestra, settiamo lo stile e lo sfondo,
8577 e creiamo un puntatore al widget nel campo dei dati utente (user data)
8578 del GdkWindow. Quest'ultimo passo permette a GTK di mandare gli
8579 eventi della finestra al widget corretto.
8583 gtk_dial_realize (GtkWidget *widget)
8586 GdkWindowAttr attributes;
8587 gint attributes_mask;
8589 g_return_if_fail (widget != NULL);
8590 g_return_if_fail (GTK_IS_DIAL (widget));
8592 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
8593 dial = GTK_DIAL (widget);
8595 attributes.x = widget->allocation.x;
8596 attributes.y = widget->allocation.y;
8597 attributes.width = widget->allocation.width;
8598 attributes.height = widget->allocation.height;
8599 attributes.wclass = GDK_INPUT_OUTPUT;
8600 attributes.window_type = GDK_WINDOW_CHILD;
8601 attributes.event_mask = gtk_widget_get_events (widget) |
8602 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
8603 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
8604 GDK_POINTER_MOTION_HINT_MASK;
8605 attributes.visual = gtk_widget_get_visual (widget);
8606 attributes.colormap = gtk_widget_get_colormap (widget);
8608 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
8609 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
8611 widget->style = gtk_style_attach (widget->style, widget->window);
8613 gdk_window_set_user_data (widget->window, widget);
8615 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
8619 <!-- ----------------------------------------------------------------- -->
8620 <sect2> Negoziazione della dimensione
8623 Prima di visualizzare per la prima volta la finestra, e se il
8624 layout della finestra cambia, GTK chiede ad ogni widget, incluso nella
8625 finestra, la propria dimensione. Questa richiesta è fatta dalla
8626 funzione <tt/gtk_dial_size_request()/. Non essendo il nostro widget
8627 un contenitore, e non avendo dei veri limiti per la propria
8628 dimensione, restituiamo semplicemnte un valore ragionevole.
8632 gtk_dial_size_request (GtkWidget *widget,
8633 GtkRequisition *requisition)
8635 requisition->width = DIAL_DEFAULT_SIZE;
8636 requisition->height = DIAL_DEFAULT_SIZE;
8641 Dopo che tutti i widget hanno restituito una dimensione ideale, viene
8642 calcolata la disposizione della finestra e ad ogni widget figlio è
8643 notificata la propria dimensione attuale <!--ndMichel : che può essere diversa
8644 da quella restitutita con la funzione sopra -->. Usualmente, questo sarà
8645 almeno quanto richiesto, ma occasionalmente può essere più piccolo.
8646 La notifica della dimensione viene fatta dalla funzione
8647 <tt/gtk_dial_size_allocate()/. Notate che questa funzione è utilizzata
8648 anche quando la finestra X del widget è spostata o modificata come
8653 gtk_dial_size_allocate (GtkWidget *widget,
8654 GtkAllocation *allocation)
8658 g_return_if_fail (widget != NULL);
8659 g_return_if_fail (GTK_IS_DIAL (widget));
8660 g_return_if_fail (allocation != NULL);
8662 widget->allocation = *allocation;
8663 if (GTK_WIDGET_REALIZED (widget))
8665 dial = GTK_DIAL (widget);
8667 gdk_window_move_resize (widget->window,
8668 allocation->x, allocation->y,
8669 allocation->width, allocation->height);
8671 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
8672 dial->pointer_width = dial->radius / 5;
8677 <!-- ----------------------------------------------------------------- -->
8678 <sect2> <tt/gtk_dial_expose()/
8681 Come menzionato sopra, tutto il lavoro di questo widget viene fatto nella
8682 gestione dell'evento ``expose''. Non c'è molto da notare su questo eccetto
8683 l'uso della funzione <tt/gtk_draw_polygon/ per disegnare il
8684 puntatore con un'ombreggiatura a tre dimensioni in accordo con il colore
8685 memorizzato nello stile del wiget.
8689 gtk_dial_expose (GtkWidget *widget,
8690 GdkEventExpose *event)
8700 g_return_val_if_fail (widget != NULL, FALSE);
8701 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
8702 g_return_val_if_fail (event != NULL, FALSE);
8704 if (event->count > 0)
8707 dial = GTK_DIAL (widget);
8709 gdk_window_clear_area (widget->window,
8711 widget->allocation.width,
8712 widget->allocation.height);
8714 xc = widget->allocation.width/2;
8715 yc = widget->allocation.height/2;
8719 for (i=0; i<25; i++)
8721 theta = (i*M_PI/18. - M_PI/6.);
8725 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
8727 gdk_draw_line (widget->window,
8728 widget->style->fg_gc[widget->state],
8729 xc + c*(dial->radius - tick_length),
8730 yc - s*(dial->radius - tick_length),
8731 xc + c*dial->radius,
8732 yc - s*dial->radius);
8737 s = sin(dial->angle);
8738 c = cos(dial->angle);
8741 points[0].x = xc + s*dial->pointer_width/2;
8742 points[0].y = yc + c*dial->pointer_width/2;
8743 points[1].x = xc + c*dial->radius;
8744 points[1].y = yc - s*dial->radius;
8745 points[2].x = xc - s*dial->pointer_width/2;
8746 points[2].y = yc - c*dial->pointer_width/2;
8748 gtk_draw_polygon (widget->style,
8759 <!-- ----------------------------------------------------------------- -->
8760 <sect2> Gestione degli eventi
8764 Il resto del codice del widget manipola vari tipi di eventi, e non
8765 è differente da quello che può essere trovato in molte applicazione
8766 GTK. Due tipi di eventi possono verificarsi: l'utente può
8767 clickare sul widget con il mouse e trascinare per muovere il puntatore,
8768 o il valore dell'oggetto Adjustmente può cambiare a causa di alcune
8769 circostanze esterne.
8772 Quando l'utente clicka sul widget, noi vediamo se la pressione
8773 era veramente vicina al puntatore, e se così, memorizziamo il bottone
8774 premuto dall'utente con il campo <tt/button/ della struttura del
8775 widget, e prendiamo tutti gli eventi del mouse con una chiamata alla
8776 funzione <tt/gtk_grab_add()/. Successivi movimenti del mouse causano il
8777 ricalcolo dei valori di controllo (fatto dalla funzione
8778 <tt/gtk_dial_update_mouse/). Dipendentemente dalla politica che abbiamo
8779 stabilito, gli eventi ``value_changed'' possono essere generati
8780 istantaneamente (<tt/GTK_UPDATE_CONTINUOUS/), dopo un certo tempo aggiunto
8781 con la funzione <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), o
8782 solamente quando il bottone del mouse e' rilasciato
8783 (<tt/GTK_UPDATE_DISCONTINUOUS/).
8787 gtk_dial_button_press (GtkWidget *widget,
8788 GdkEventButton *event)
8794 double d_perpendicular;
8796 g_return_val_if_fail (widget != NULL, FALSE);
8797 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
8798 g_return_val_if_fail (event != NULL, FALSE);
8800 dial = GTK_DIAL (widget);
8802 /* Determina se il bottone premuto era dentro la regione del puntatore:
8803 lo facciamo calcolando la distanza parallela e
8804 perpendicolare dal punto dove il bottone del mouse e' stato premuto
8805 alla linea passante per il puntatore. */
8807 dx = event->x - widget->allocation.width / 2;
8808 dy = widget->allocation.height / 2 - event->y;
8810 s = sin(dial->angle);
8811 c = cos(dial->angle);
8813 d_parallel = s*dy + c*dx;
8814 d_perpendicular = fabs(s*dx - c*dy);
8816 if (!dial->button &&
8817 (d_perpendicular < dial->pointer_width/2) &&
8818 (d_parallel > - dial->pointer_width))
8820 gtk_grab_add (widget);
8822 dial->button = event->button;
8824 gtk_dial_update_mouse (dial, event->x, event->y);
8831 gtk_dial_button_release (GtkWidget *widget,
8832 GdkEventButton *event)
8836 g_return_val_if_fail (widget != NULL, FALSE);
8837 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
8838 g_return_val_if_fail (event != NULL, FALSE);
8840 dial = GTK_DIAL (widget);
8842 if (dial->button == event->button)
8844 gtk_grab_remove (widget);
8848 if (dial->policy == GTK_UPDATE_DELAYED)
8849 gtk_timeout_remove (dial->timer);
8851 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
8852 (dial->old_value != dial->adjustment->value))
8853 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
8860 gtk_dial_motion_notify (GtkWidget *widget,
8861 GdkEventMotion *event)
8864 GdkModifierType mods;
8867 g_return_val_if_fail (widget != NULL, FALSE);
8868 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
8869 g_return_val_if_fail (event != NULL, FALSE);
8871 dial = GTK_DIAL (widget);
8873 if (dial->button != 0)
8878 if (event->is_hint || (event->window != widget->window))
8879 gdk_window_get_pointer (widget->window, &x, &y, &mods);
8881 switch (dial->button)
8884 mask = GDK_BUTTON1_MASK;
8887 mask = GDK_BUTTON2_MASK;
8890 mask = GDK_BUTTON3_MASK;
8898 gtk_dial_update_mouse (dial, x,y);
8905 gtk_dial_timer (GtkDial *dial)
8907 g_return_val_if_fail (dial != NULL, FALSE);
8908 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
8910 if (dial->policy == GTK_UPDATE_DELAYED)
8911 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
8917 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
8922 g_return_if_fail (dial != NULL);
8923 g_return_if_fail (GTK_IS_DIAL (dial));
8925 xc = GTK_WIDGET(dial)->allocation.width / 2;
8926 yc = GTK_WIDGET(dial)->allocation.height / 2;
8928 old_value = dial->adjustment->value;
8929 dial->angle = atan2(yc-y, x-xc);
8931 if (dial->angle < -M_PI/2.)
8932 dial->angle += 2*M_PI;
8934 if (dial->angle < -M_PI/6)
8935 dial->angle = -M_PI/6;
8937 if (dial->angle > 7.*M_PI/6.)
8938 dial->angle = 7.*M_PI/6.;
8940 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
8941 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
8943 if (dial->adjustment->value != old_value)
8945 if (dial->policy == GTK_UPDATE_CONTINUOUS)
8947 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
8951 gtk_widget_draw (GTK_WIDGET(dial), NULL);
8953 if (dial->policy == GTK_UPDATE_DELAYED)
8956 gtk_timeout_remove (dial->timer);
8958 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
8959 (GtkFunction) gtk_dial_timer,
8968 Cambiamenti esterni all'Adjustment sono comunicati al nostro widget
8969 dai segnali ``changed'' e ``value_changed''. Il gestore per
8970 queste funzioni chiama <tt/gtk_dial_update()/ per validare gli
8971 argomenti, calcolare il nuovo angolo del puntatore e ridisegnare il
8972 widget (chiamando <tt/gtk_widget_draw()/).
8976 gtk_dial_update (GtkDial *dial)
8980 g_return_if_fail (dial != NULL);
8981 g_return_if_fail (GTK_IS_DIAL (dial));
8983 new_value = dial->adjustment->value;
8985 if (new_value < dial->adjustment->lower)
8986 new_value = dial->adjustment->lower;
8988 if (new_value > dial->adjustment->upper)
8989 new_value = dial->adjustment->upper;
8991 if (new_value != dial->adjustment->value)
8993 dial->adjustment->value = new_value;
8994 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
8997 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
8998 (dial->adjustment->upper - dial->adjustment->lower);
9000 gtk_widget_draw (GTK_WIDGET(dial), NULL);
9004 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
9009 g_return_if_fail (adjustment != NULL);
9010 g_return_if_fail (data != NULL);
9012 dial = GTK_DIAL (data);
9014 if ((dial->old_value != adjustment->value) ||
9015 (dial->old_lower != adjustment->lower) ||
9016 (dial->old_upper != adjustment->upper))
9018 gtk_dial_update (dial);
9020 dial->old_value = adjustment->value;
9021 dial->old_lower = adjustment->lower;
9022 dial->old_upper = adjustment->upper;
9027 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
9032 g_return_if_fail (adjustment != NULL);
9033 g_return_if_fail (data != NULL);
9035 dial = GTK_DIAL (data);
9037 if (dial->old_value != adjustment->value)
9039 gtk_dial_update (dial);
9041 dial->old_value = adjustment->value;
9046 <!-- ----------------------------------------------------------------- -->
9047 <sect2> Possibili Miglioramenti
9050 Il widget Dial, da come l'abbiamo costruito, è lungo circa 670 linee
9051 di codice C. Anche se questo potrebbe sembrare un po' troppo, abbiamo
9052 realmente fatto un bel po' con quel tanto di codice, specialmente
9053 considerando che molta della lunghezza è costituita da file header e
9054 commmenti. Comunque ci sono alcuni miglioramenti che potrebbero essere
9055 fatti a questo widget:
9058 <item> Se tu provate questo widget, troverete che ci sono alcuni lampeggiamenti
9059 quando il puntatore viene trascinato in giro. Questo
9060 perchè l'intero widget è cancellato ogni volta che il
9061 puntatore viene mosso, prima di essere ridisegnato. Spesso, il modo migliore
9062 per gestire questo tipo di problema è il disegnare il tutto su una
9063 pixmap non visibile, poi copiare il risultato finale sullo schermo
9064 in una passata sola (il widget ProgressBar viene disegnato in questo
9067 <item> L'utente potrebbe essere abilitato ad usare le frecce su e giu per
9068 incrementare e diminuire il valore.
9070 <item> Potrebbe essere carino se il widget avesse i bottoni per
9071 incrementare e decrementare il valore di step. Anche se potrebbe essere
9072 possibile usare dei widget Bottone incorporati per questo, possiamo anche
9073 far sì che il bottone sia auto-ripentente quando premuto, come le frecce
9074 in una barra di scorrimento. Molto del codice per implementare questo tipo di
9075 comportamento può essere trovato nel widget GtkRange.
9077 <item> il widget Dial potrebbe essere fatto/creato dentro un widget
9078 contenitore con un singolo widget figlio posizionato all'inizio tra i
9079 2 bottoni menzionati prima. L'utente potrebbe poi aggiungere o una etichetta
9080 o un widget ``entry'' per mostrare il valore corrente del dial.
9084 <!-- ----------------------------------------------------------------- -->
9085 <sect1> Impararne di più
9088 Fin qui abbiamo esposto solo una piccola parte di tutto quello che serve
9089 per creare un widget. Se volete davvero scrivere un vostro widget, la
9090 miglior risorsa di esempi è lo stesso codice sorgente GTK. Chiedete a voi
9091 stessi alcune cose su come deve essere il widget che volete scrivere: è
9092 un widget contenitore? dovrà avere una propria finestra? è una modifica di
9093 un widget precedente? Trovate poi un widget simile e iniziate a fargli
9097 <!-- ***************************************************************** -->
9098 <sect>Scribble, Un semplice esempio di Programma di Disegno
9099 <!-- ***************************************************************** -->
9101 <!-- ----------------------------------------------------------------- -->
9105 In questa sezione, creeremo un semplice programma di disegno. Durante
9106 questo processo, esamineremo come gestire gli eventi generati dal mouse,
9107 come disegnare all'interno di una finestra e come disegnare in modo migliore
9108 usando una pixmap di supporto. Dopo averlo creato, lo amplieremo aggiungendo
9109 il supporto per i dispositivi XInput, per esempio le tavolette grafiche.
9110 Il GTK fornisce delle routine di supporto grazie alle quali risulta piuttosto
9111 semplice ottenere informazioni estese, come la pressione o l'inclinazione.
9113 <!-- ----------------------------------------------------------------- -->
9114 <sect1> Gestione degli Eventi
9117 I segnali di GTK che abbiamo discusso finora si riferivano ad azioni di
9118 alto livello, ad esempio la selezione di un elemento di un menù. Però, a volte
9119 è utile sapere qualcosa su cose che si svolgono a livello più basso livello,
9120 come possono essere il movimento del mouse o la pressione di un tasto.
9121 Ci sono segnali di GTK anche per questi <em>eventi</em> di basso livello.
9122 I gestori di questo tipo di segnali hanno un parametro caratteristico in più,
9123 che è il puntatore ad una struttura che contiene informazioni riguardo
9124 all'evento. Per esempio, ai gestori di eventi che riguardano dei movimenti,
9125 si passa un puntatore ad una struttura GdkEventMotion, che è fatta (in parte)
9129 struct _GdkEventMotion
9142 <tt/type/ avrà il valore del tipo di evento, in questo caso
9143 <tt/GDK_MOTION_NOTIFY/, <tt/window/ rappresenta la finestra in cui l'evento
9144 si è verificato. <tt/x/ e <tt/y/ forniscono le coordinate dell'evento e
9145 <tt/state/ specifica lo stato dei modificatori nel momento in cui l'evento
9146 si è verificato (cioè, specifica quali tasti modificatori e tasti del mouse
9147 erano premuti in quel momento). E' un OR bit per bit dei seguenti valori:
9166 Come succede per gli altri segnali, per determinare cosa deve accadere in
9167 corrispondenza di un evento, si chiama <tt>gtk_signal_connect()</tt>. Ma
9168 è anche necessario far sì che GTK sappia di quali eventi vogliamo essere
9169 informati. A questo fine, chiamiamo la funzione:
9172 void gtk_widget_set_events (GtkWidget *widget, gint events);
9175 Il secondo campo specifica gli eventi che ci interessano. Si tratta dell'OR
9176 bit per bit delle costanti che identificano i diversi tipi di eventi. La lista
9177 dei tipi di eventi è la seguente:
9181 GDK_POINTER_MOTION_MASK
9182 GDK_POINTER_MOTION_HINT_MASK
9183 GDK_BUTTON_MOTION_MASK
9184 GDK_BUTTON1_MOTION_MASK
9185 GDK_BUTTON2_MOTION_MASK
9186 GDK_BUTTON3_MOTION_MASK
9187 GDK_BUTTON_PRESS_MASK
9188 GDK_BUTTON_RELEASE_MASK
9190 GDK_KEY_RELEASE_MASK
9191 GDK_ENTER_NOTIFY_MASK
9192 GDK_LEAVE_NOTIFY_MASK
9193 GDK_FOCUS_CHANGE_MASK
9195 GDK_PROPERTY_CHANGE_MASK
9196 GDK_PROXIMITY_IN_MASK
9197 GDK_PROXIMITY_OUT_MASK
9200 Per chiamare <tt/gtk_widget_set_events()/, si devono fare alcune osservazioni
9201 sottili. In primo luogo, la si deve chiamare prima che sia stata creata la
9202 finestra X per il widget GTK. In pratica, ciò significa che la si deve
9203 chiamare subito dopo aver creato il widget. In secondo luogo, il widget
9204 deve avere una finestra X associata. Molti widget, per ragioni di
9205 efficienza, non hanno una propria finetra, e vengono mostrati nella
9206 finestra madre. Questi widget sono:
9228 Per catturare degli eventi per questo tipo di widget, si deve fare uso
9229 del widget EventBox. Si veda a questo proposito la sezione su
9230 <ref id="sec_The_EventBox_Widget" name="The EventBox Widget">.
9233 Per il nostro programma di disegno, vogliamo sapere quando il pulsante del
9234 mouse è premuto e quando viene mosso, quindi specificheremo
9235 <tt/GDK_POINTER_MOTION_MASK/ e <tt/GDK_BUTTON_PRESS_MASK/. Vogliamo anche
9236 essere informati su quando è necessario ridisegnare la nostra finestra,
9237 quindi specifichiamo <tt/GDK_EXPOSURE_MASK/. Anche se vogliamo essere
9238 avvertiti con un evento ``Configure'' se la dimensione della nostra finestra
9239 cambia, non è necessario specificare il flag <tt/GDK_STRUCTURE_MASK/, dal
9240 momento che questo viene specificato automaticamente per tutte le finestre.
9243 Risulta, conunque, che specificando semplicemente <tt/GDK_POINTER_MOTION_MASK/
9244 si crea un problema. Ciò infatti fa sì che il server aggiunga nella coda un
9245 un nuovo evento di movimento ogni volta che l'utente muovoe il mouse. Immaginate
9246 che ci vogliano 0.1 secondi per gestire uno di questi eventi, e che il server
9247 X metta in coda un nuovo evento ogni 0.05 secondi. Rimarremo ben presto indietro
9248 rispetto al disegno dell'utente. Se l'utente disegna per 5 secondi, ci metteremmo
9249 altri 5 secondi prima di finire dopo che l'utente ha rilasciato il pulsante del
9250 mouse! Vorremmo quindi che venga notificato un solo evento di movimento per
9251 ogni evento che processiamo. Il modo per farlo è di specificare
9252 <tt/GDK_POINTER_MOTION_HINT_MASK/.
9255 Quando specifichiamo <tt/GDK_POINTER_MOTION_HINT_MASK/, il server ci notifica
9256 un evento di movimento la prima volta che il puntatore si muove dopo essere
9257 entrato nella nostra finestra, oppure dopo ogni rilascio di un pulsante del
9258 mouse. Gli altri eventi di movimento verranno soppressi finché non richiediamo
9259 esplicitamente la posizione del puntatore con la funzione:
9262 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
9265 GdkModifierType *mask);
9268 (c'è anche un'altra funzione, <tt>gtk_widget_get_pointer()</tt>, che ha
9269 un'interfaccia più semplice, ma che non risulta molto utile dal momento
9270 che restituisce solo la posizione del puntatore, senza dettagli sullo
9274 Quindi, il codice per assegnare gli eventi per la nostra finestra, avrà l'aspetto:
9277 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
9278 (GtkSignalFunc) expose_event, NULL);
9279 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
9280 (GtkSignalFunc) configure_event, NULL);
9281 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
9282 (GtkSignalFunc) motion_notify_event, NULL);
9283 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
9284 (GtkSignalFunc) button_press_event, NULL);
9286 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
9287 | GDK_LEAVE_NOTIFY_MASK
9288 | GDK_BUTTON_PRESS_MASK
9289 | GDK_POINTER_MOTION_MASK
9290 | GDK_POINTER_MOTION_HINT_MASK);
9293 Teniamo per dopo i gestori di ``expose_event'' e ``configure_event''. Quelli di
9294 ``motion_notify_event'' e ``button_press_event'' sono piuttosto semplici:
9298 button_press_event (GtkWidget *widget, GdkEventButton *event)
9300 if (event->button == 1 && pixmap != NULL)
9301 draw_brush (widget, event->x, event->y);
9307 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
9310 GdkModifierType state;
9313 gdk_window_get_pointer (event->window, &x, &y, &state);
9318 state = event->state;
9321 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
9322 draw_brush (widget, x, y);
9328 <!-- ----------------------------------------------------------------- -->
9329 <sect1> Il widget Area di Disegno (DrawingArea) e il procedimento per Disegnare
9332 Vediamo ora il procedimento per disegnare sullo schermo. Il
9333 widget da usare è l'Area di Disegno (DrawingArea). Essenzialmente si
9334 tratta di una finestra X e nient'altro. E' una tela bianca su cui possimo
9335 disegnare tutto quello che vogliamo. Per crearne una usiamo la chiamata:
9338 GtkWidget* gtk_drawing_area_new (void);
9341 Per specificare una dimensione predefinita, si puo fare:
9344 void gtk_drawing_area_size (GtkDrawingArea *darea,
9349 Come è vero per tutti i widget, si può modificare questa dimensione
9350 predefinita, tramite la chamata a <tt>gtk_widget_set_usize()</tt>, e
9351 questa a sua volta può essere modificata dall'utente ridimensionando
9352 manualmente la finestra che contiene l'area di disegno.
9355 Si deve notare che nel momento in cui creiamo un widget DrawingArea, siamo
9356 <em>completamente</em> responsabili di disegnarne il contenuto. Se ad
9357 esempio la nostra finestra viene prima nascosta e poi dinuovo portata in
9358 primo piano, otteniamo un evento di ``esposizione'' e doppiamo ridisegnare
9359 ciò che era stato precedente nascosto.
9362 Dover ricordare tutto quello che era disegnato sulla finestra in modo da
9363 poterlo ridisegnare successivamente, può essere, come minimo, noioso.
9364 In più, può essere spiacevole dal punto di vista visivo, se delle porzioni
9365 dello schermo vengono prima cancellate e poi ridisegnate passo per passo.
9366 La soluzione per questo problema è di usare una <em>pixmap di supporto</em>.
9367 Invece di disegnare direttamente sullo schermo, disegnamo su un'iimagine
9368 conservata nella memoria del server ma che non viene mostrata; quindi, quando
9369 l'immagine cambia o ne vengono mostrate nuove porzioni, copiamo sullo schermo
9370 le parti corrispondenti.
9373 Per creare una ppixmap fuori dallo schermo, usiamo la funzione:
9376 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
9382 Il parametro <tt>window</tt>specifica una finestra GDK dalla quale questa
9383 pixmap prende alcune delle sue proprietà. <tt>width</tt> e <tt>height</tt>
9384 specificano le dimensioni della pixmap. <tt>depth</tt> specifica la
9385 <em>profondità di colore</em>, cioè il numero di bit per ogni pixel, per
9386 la nuova pixmap. Se alla profondità è assegnato il valore <tt>-1</tt>, questa
9387 verrà posta identica a quella di <tt>window</tt>.
9390 Creiamo la pixmap all'interno del gestore di ``configure_event''. Questo evento
9391 è generato ogni volta che la finestra cambia di dimensione, compreso il
9392 momento in cui viene creata per la prima volta.
9395 /* Pixmap di supporto per l'area di disegno */
9396 static GdkPixmap *pixmap = NULL;
9398 /* Creare una pixmap della dimensione appropriata */
9400 configure_event (GtkWidget *widget, GdkEventConfigure *event)
9404 gdk_pixmap_destroy(pixmap);
9406 pixmap = gdk_pixmap_new(widget->window,
9407 widget->allocation.width,
9408 widget->allocation.height,
9410 gdk_draw_rectangle (pixmap,
9411 widget->style->white_gc,
9414 widget->allocation.width,
9415 widget->allocation.height);
9421 La chiamata a <tt>gdk_draw_rectangle()</tt> inizialmente rende bianca l'intera
9422 pixmap. Fra un momento ne riparleremo.
9425 Il gestore dell'evento ``esposizione'', copia quindi la porzione appropriata
9426 della pixmap sullo schermo (determiniamo qual è l'area da ridisegnare usando
9427 il campo event->area dell'evento di esposizione):
9430 /* Ridisegna sullo schermo a partire dalla pixmap di supporto */
9432 expose_event (GtkWidget *widget, GdkEventExpose *event)
9434 gdk_draw_pixmap(widget->window,
9435 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
9437 event->area.x, event->area.y,
9438 event->area.x, event->area.y,
9439 event->area.width, event->area.height);
9445 Abbiamo quindi visto come tenete aggiornato lo schermo con la nostra
9446 pixmap, ma come facciamo per disegnare delle cose interessanti sulla
9447 pixmap? Ci sono un bel po' di funzioni nella libreria GDK di GTK che
9448 servono per disegnare su superfici <em>disegnabili</em>. Una superficie
9449 disegnabile è semplicemente qualcosa su cui si può disegnare un'immagine.
9450 Può essere una finestra, una pixmap o una bitmap (un'immagine in bianco e
9451 nero). Abbiamo già visto sopra due di chiamate,
9452 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. La lista
9453 completa è la seguente:
9457 gdk_draw_rectangle ()
9466 gdk_draw_segments ()
9469 Per ulteriori dettagli su queste funzioni, vedete la documentazione di
9470 riferimento nei file header <tt><gdk/gdk.h></tt>.
9471 Tutte queste funzioni hanno i medesimi primi due argomenti. Il primo
9472 è la superficie disegnabili su cui disegnare, il secondo è un
9473 <em>contesto grafico</em> (GC).
9476 Un contesto grafico incapsula delle informazioni riguardo a cose come
9477 il colore di sfondo e di primo piano e lo spessore della linea.
9478 GDK ha un ampio insieme di funzioni per crare e modificare contesti grafici,
9479 ma per tenere le cose semplici useremo solo dei contesti grafici predefiniti.
9480 Ogni widget ha uno stile associato (che può essere modificato agendo su un
9481 file gtkrc). Questo, fra le altre cose, contiene un certo numero di contesti
9482 grafici. Alcuni esempi di come accedere a questi contesti grafici sono
9486 widget->style->white_gc
9487 widget->style->black_gc
9488 widget->style->fg_gc[GTK_STATE_NORMAL]
9489 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
9492 I campi <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, e
9493 <tt>light_gc</tt> sono indicizzati tramite un parametri di tipo
9494 <tt>GtkStateType</tt>, che può assumere i valori:
9501 GTK_STATE_INSENSITIVE
9504 Per esempio, per <tt/GTK_STATE_SELECTED/ il colore di sfondo predefinito
9505 è blu scuro e quello di primo piano bianco.
9508 La nostra funzione <tt>draw_brush()</tt>, che efettivamente disegna sullo
9509 schermo, diventa quindi:
9512 /* Disegna un rettangolo sullo schermo */
9514 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
9516 GdkRectangle update_rect;
9518 update_rect.x = x - 5;
9519 update_rect.y = y - 5;
9520 update_rect.width = 10;
9521 update_rect.height = 10;
9522 gdk_draw_rectangle (pixmap,
9523 widget->style->black_gc,
9525 update_rect.x, update_rect.y,
9526 update_rect.width, update_rect.height);
9527 gtk_widget_draw (widget, &update_rect);
9531 Dopo aver disegnato il rettangolo sulla pixmap, chiamiamo la funzione:
9534 void gtk_widget_draw (GtkWidget *widget,
9535 GdkRectangle *area);
9538 che notifica a X che l'area data dal parametro <tt>area</tt> deve essere
9539 aggiornata. X poi genererà un evento di esposizione (che può essere combinato
9540 con le aree passate da diverse chiamate a <tt>gtk_widget_draw()</tt>) che
9541 farà sì che il nostro gestore dell'evento di esposizione, copi le porzioni
9542 rilevanti sullo schermo.
9545 Abbiamo a questo punto creato tutto il programma di disegno, tranne che
9546 per qualche dettaglio irrilevante come la creazione della finestra principale.
9547 Il codice sorgente completo è reperibile dove avete ottenuto questo tutorial,
9550 <htmlurl url="http://www.msc.cornell.edu/~otaylor/gtk-gimp/tutorial"
9551 name="http://www.msc.cornell.edu/~otaylor/gtk-gimp/tutorial">
9553 <!-- ----------------------------------------------------------------- -->
9554 <sect1> Aggiungere il supporto per XInput
9557 Al giorno d'oggi è possibile acquistare dei dispositivi abbastanza a buon
9558 mercato, come tavolette grafice, che permettono di disegnare con una
9559 espressività artistica molto semplificata rispetto ad un mouse.
9560 Il modo più semplice per usare questi dispositivi è di sostituirli
9561 semplicemente al mouse, ma in questo modo si perdono molti dei loro
9565 <item> Sensibilità alla pressione
9566 <item> Sensibilità all'inclinazione
9567 <item> Posizionamento infra-pixel
9568 <item> Ingressi multipli (per esempio, uno stilo che contiene sia una ``matita''
9572 Per ulteriori informazioni sulle estensioni XInput, vedere l'<htmlurl
9573 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
9574 name="XInput-HOWTO">.
9577 Se esaminiamo, per esempio, la definizione completa della struttura
9578 GdkEventMotion, possiamo vedere che contiene dei campi per il supporto
9579 delle informazioni estese dai dispositivi.
9582 struct _GdkEventMotion
9594 GdkInputSource source;
9599 <tt/pressure/ fornisce la pressione sotto forma di un numero decimale
9600 compreso fra 0 e 1. <tt/xtilt/ e <tt/ytilt/ possono assumere valori
9601 compresi fra -1 e 1, corrispondenti al grado di inclinazione in ciascuna
9602 direzione. <tt/source/ e <tt/deviceid/ specificano il dispositivo per il
9603 quale si è verificato l'evento in due modi distinti. <tt/source/ da alcune
9604 semplici informazioni sul tipo di dispositivo, e può assumere i valori:
9613 <tt/deviceid/ specifica invece un identificativo numerico univoco per il
9614 dispositivo. Questo può essere a sua volta utilizzato per avere ulteriori
9615 informazioni sul dispositivo tramite la chiamata a <tt/gdk_input_list_devices()/
9616 (vedi sotto). Il valore speciale <tt/GDK_CORE_POINTER/ viene usato per identificare
9617 il dispositivo di puntamento principale (di solito il mouse).
9619 <sect2> Abilitare le informazioni estese
9622 Per far sì che GTK sappia che ci interessano le informazioni estese dai
9623 dispositivi, basta aggiungere un'unica linea al nostro programma:
9626 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
9629 Dando il valore <tt/GDK_EXTENSION_EVENTS_CURSOR/, diciamo che ci interessano
9630 gli eventi relativi alle estensioni, ma solo se non dobbiamo disegnare da noi
9631 il nostro cursore. Si veda più sotto alla sezione <ref
9632 id="sec_Further_Sophistications" name="Ulteriori Sofisticazioni"> per ulteriori
9633 informazioni sul modo si disegnare i cursori. Potremmo anche dare i valori
9634 <tt/GDK_EXTENSION_EVENTS_ALL/ se vogliamo disegnare il nostro cursore o
9635 <tt/GDK_EXTENSION_EVENTS_NONE/ se vogliamo tornare alle condizioni predefinite.
9638 Comunque, non finisce tutto qui. Non ci sono estensioni abilitate per difetto.
9639 Abbiamo bisogno di un meccanismo per permettere agli utenti l'abilitazione e
9640 la configurazione delle estensioni dei loro dispositivi, GTK fornisce il
9641 widget InputDialog per automatizzare questo processo. La seguente procedura
9642 mostra come gestire un widget InputDialog. Crea la finestra di dialogo nel
9643 caso non sia presente, mentre la porta in primo piano in caso contrario.
9647 input_dialog_destroy (GtkWidget *w, gpointer data)
9649 *((GtkWidget **)data) = NULL;
9653 create_input_dialog ()
9655 static GtkWidget *inputd = NULL;
9659 inputd = gtk_input_dialog_new();
9661 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
9662 (GtkSignalFunc)input_dialog_destroy, &inputd);
9663 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
9665 (GtkSignalFunc)gtk_widget_hide,
9666 GTK_OBJECT(inputd));
9667 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
9669 gtk_widget_show (inputd);
9673 if (!GTK_WIDGET_MAPPED(inputd))
9674 gtk_widget_show(inputd);
9676 gdk_window_raise(inputd->window);
9681 (Notate come gestiamo questo dialogo. Con la connessione del segnale
9682 ``destroy'' ci assicuriamo di non tenerci in giro il puntatore al dialogo
9683 dopo che lo abbiamo distrutto, cosa che potrebbe portare ad un errore di
9687 L'InputDialog ha due pulsanti, ``Close'' e ``Save'', i quali non hanno alcuna
9688 azione predefinita assegnata ad essi. Nella funzione precedente, abbiamo
9689 fatto in modo che ``Close'' nasconda la finestra di dialogo, e abbiamo nascosto
9690 il pulsante ``Save'' dal momento che in questo programma non implementiamo il
9691 salvataggio delle opzioni di XInput.
9693 <sect2> Usare le informazioni estese
9696 Una volta abilitato il dipositivo, possiamo usare le informazioni estese
9697 che si trovano nei corrispondenti campi delle strutture che descrivono gli
9698 eventi. A dire il vero, l'utilizzo di questi campi è sempre sicuro, perché
9699 sono tutti posti per difetto a valori ragionevoli ancje quando la gestione
9700 degli eventi estesi non è abilitata.
9703 Un cambiamento che dobbiamo fare è di chiamare <tt/gdk_input_window_get_pointer()/
9704 invece di <tt/gdk_window_get_pointer/. Ciò si rende necessario perché
9705 <tt/gdk_window_get_pointer/ non restituisce le informazioni esetese.
9708 void gdk_input_window_get_pointer (GdkWindow *window,
9715 GdkModifierType *mask);
9718 Quando chiamiamo questa funzione, dobbiamo specificare l'identificativo
9719 del dispositivo e la finestra. Normalmente questo identificativo lo si
9720 ottiene dal campo <tt/deviceid/ della struttura dell'evento.
9721 Questa funzione restituirà valori ragionevoli nel caso che la gestione
9722 degli eventi estesi non sia attivata (in questo caso, <tt/event->deviceid/
9723 avrà il valore <tt/GDK_CORE_POINTER/).
9725 Quindi, la struttura di base dei gestori degli eventi relativi alla
9726 pressione di bottoni e ai movomenti non cambia molto - abbiamo solo
9727 bisogno di aggiungere il codice necessario per tenere conto delle
9728 informazioni estese.
9732 button_press_event (GtkWidget *widget, GdkEventButton *event)
9734 print_button_press (event->deviceid);
9736 if (event->button == 1 && pixmap != NULL)
9737 draw_brush (widget, event->source, event->x, event->y, event->pressure);
9743 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
9747 GdkModifierType state;
9750 gdk_input_window_get_pointer (event->window, event->deviceid,
9751 &x, &y, &pressure, NULL, NULL, &state);
9756 pressure = event->pressure;
9757 state = event->state;
9760 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
9761 draw_brush (widget, event->source, x, y, pressure);
9767 Avremo anche bisogno di fare qualcosa con queste nuove informazioni. La
9768 nostra nuova funzione <tt/draw_brush/ disegna con un colore diverso per
9769 ogni <tt/event->source/ e cambia la dimensione della linea in funzione
9773 /* Disegna un rettangolo sullo schermo, con la dimensione dipendente
9774 dalla pressione e il colore dipendente dal tipo di dispositivo */
9776 draw_brush (GtkWidget *widget, GdkInputSource source,
9777 gdouble x, gdouble y, gdouble pressure)
9780 GdkRectangle update_rect;
9784 case GDK_SOURCE_MOUSE:
9785 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
9787 case GDK_SOURCE_PEN:
9788 gc = widget->style->black_gc;
9790 case GDK_SOURCE_ERASER:
9791 gc = widget->style->white_gc;
9794 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
9797 update_rect.x = x - 10 * pressure;
9798 update_rect.y = y - 10 * pressure;
9799 update_rect.width = 20 * pressure;
9800 update_rect.height = 20 * pressure;
9801 gdk_draw_rectangle (pixmap, gc, TRUE,
9802 update_rect.x, update_rect.y,
9803 update_rect.width, update_rect.height);
9804 gtk_widget_draw (widget, &update_rect);
9808 <sect2> Trovare ulteriori informazioni su di un dispositivo
9811 Come esempio del modo di trovare altre informazioni su di un dispositivo,
9812 il nostro programma stamperà il nome di ogni dispositivo che genera un
9813 evento di pressione di un pulsante. Per avere il nome di un dispositivo,
9814 chiamiamo la funzione
9817 GList *gdk_input_list_devices (void);
9820 che restituisce una GList (un tipo di lista collegata che si trova nella
9821 libreria glib) di strutture di tipo GdkDeviceInfo. La definizione di
9822 GdkDeviceInfo è la seguente:
9825 struct _GdkDeviceInfo
9829 GdkInputSource source;
9839 La maggior parte di questi campi rappresentano informazioni di configurazione
9840 che potete ignorare a meno che non implementiate il salvataggio della
9841 configurazione di un XInput. Quelle che ci interessano sono <tt/name/, che
9842 è semplicemente il nome che X assegna al dispositivo, e <tt/has_cursor/. Anche
9843 <tt/has_cursor/ non è informazione di configurazione, e indica, nel caso
9844 abbia valore ``falso'', che dobbiamo disegnare da soli il nostro cursore. Ma
9845 dal momento che abbiamo specificato <tt/GDK_EXTENSION_EVENTS_CURSOR/,
9846 possiamo anche non preoccuparcene.
9850 La nostra funzione <tt/print_button_press()/ scorre semplicemente la lista
9851 che è stata restituita finché non trova il valore corretto, e poi stampa
9852 il nome del dispositivo.
9856 print_button_press (guint32 deviceid)
9860 /* gdk_input_list_devices restituisce una lista interna, così poi
9861 non dobbiamo liberarla */
9862 tmp_list = gdk_input_list_devices();
9866 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
9868 if (info->deviceid == deviceid)
9870 printf("Button press on device '%s'\n", info->name);
9874 tmp_list = tmp_list->next;
9878 Questo completa i cambiamenti necessari per usare gli XInput nel nostro
9879 programma. Come per la prima versione, i sorgenti completi sono prelevabili
9880 da dove avete prelevato questo tutorial, oppure da:
9882 <htmlurl url="http://www.msc.cornell.edu/~otaylor/gtk-gimp/tutorial"
9883 name="http://www.msc.cornell.edu/~otaylor/gtk-gimp/tutorial">
9885 <sect2> Ulteriori sofisticazioni <label id="sec_Further_Sophistications">
9888 Anche se ora il nostro programma supporta XInput pittosto bene, gli mancano
9889 alcune caratteristiche che probabilmente vorremmo mettere in una applicazione
9890 completa. In primo luogo, probabilmente all'utente non farà piacere dover
9891 configurare i propri dispositivi ogni volta che lanciano il programma, per
9892 cui dovremmo dare la possibilità di salvare la configurazione dei dispositivi.
9893 Ciò può essere fatto scorrendo la lista restituita da <tt/gdk_input_list_devices()/
9894 e scrivendo la configurazione su di un file.
9897 Per tornare allo stato salvato la prossima volta che il programma viene
9898 eseguito, GDK mette a disposizione delle funzioni per cambiare la configurazione
9902 gdk_input_set_extension_events()
9903 gdk_input_set_source()
9904 gdk_input_set_mode()
9905 gdk_input_set_axes()
9909 (La lista restituita da <tt/gdk_input_list_devices()/ non dovrebbe
9910 essere modificata direttamente.) Un esempio di come fare può essere
9911 trovato nel programma di disegno gsumi (disponibile da <htmlurl
9912 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
9913 name="http://www.msc.cornell.edu/~otaylor/gsumi/">). Sarebbe bello
9914 avere alla fine un modo standard di recuperare le informazioni per tutte
9915 le applicazioni. Questo probabilmente appartiene ad un livello un po'
9916 più elevato ripetto a GTK, forse alla libreria GNOME.
9919 Un'altra notevole omissione a cui abbiamo accennato precedentemente è il
9920 fatto di non disegnare il cursore direttamente. Piattaforme diverse da
9921 XFree86 non permettono in questo momento di usare contemporaneamente un
9922 dispositivo sia come puntatore principale sia direttamente da una
9923 applicazione. Vedere <url url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
9924 name="XInput-HOWTO"> per ulteriori informazioni. Ciò significa che le
9925 applicazioni che vogliono rivolgersi al pubblico più ampio dovranno prevedere
9926 di disegnare esse stesse il proprio cursore.
9929 Un'applicazione che voglia disegnare il proprio cursore dovrà fare due cose:
9930 determinare se il dispositivo corrente necessita che venga disegnato un
9931 cursore, e determinare se il dispositivo corrente è in prossimità. (Se il
9932 dispositivo è una tavoletta grafica, un tocco di finezza è fare sparire
9933 il puntatore quando lo stilo viene sollevato dalla tavoletta. Quando c'è
9934 contatto fra lo stilo e la tavoletta, si dice che il dispositivo è ``in
9935 prossimità".) La prima cosa viene fatta scorrendo la lista dei dispositivi,
9936 come abbiamo fatto per trovare il nome del dispositivo. La seconda cosa
9937 viene ottenuta selezionando gli eventi ``proximity_out''. Un esempio di
9938 disegno del proprio cursore si trova nel programma 'testinput' incluso nella
9939 distribuzione di GTK.
9941 <!-- ***************************************************************** -->
9942 <sect>Consigli per scrivere Applicazioni GTK
9943 <!-- ***************************************************************** -->
9947 Questa sezione è semplicemente una raccolta di saggezza, una
9948 guida di stile e un aiuto per creare buone applicazioni GTK. E' totalmente
9949 inutile per ora perché è solamente un appunto.
9951 Usa autoconf e automake! Sono tuoi amici :) Ho intenzione di fare una
9952 piccola introduzione su di loro qui.
9954 <!-- ***************************************************************** -->
9956 <!-- ***************************************************************** -->
9959 Questo documento, come molti altri grandi software là fuori, è stato
9960 creato da volontari. Se sai tutto quello che c'è da sapere su GTK e non
9961 lo hai trovato qui allora considera la possibilità di contribuire a questo
9965 Se decidi di contribuire, ti prego di trasmettere il tuo lavoro a Tony Gale,
9966 <tt><htmlurl url="mailto:gale@gtk.org"
9967 name="gale@gtk.org"></tt>. Inoltre, ricorda che l'intero documento è
9968 ``free'', e che ogni tua aggiunta sarà considerata allo stesso modo.
9969 Per questo motivo le persone possono usare porzioni dei tuoi esempi nei loro
9970 programmi, copie di questo documento possono essere distribuite all'infinito,
9976 <!-- ***************************************************************** -->
9978 <!-- ***************************************************************** -->
9980 Voglio qui ringraziare le persone che seguono, per il loro contributo
9981 alla stesura di questo testo.
9984 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
9985 name="chamele0n@geocities.com"></tt> per il tutorial sui menù.
9987 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
9988 name="raph@acm.org"></tt>
9989 per il "hello world" alla GTK, l'immpacchettamento del widget, e in generale
9990 per tutta la sua saggezza.
9991 Lui ha anche donato una casa per questo tutorial.
9993 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
9994 name="petm@xcf.berkeley.edu"></tt> Per il più semplice programma GTK e l'abilità
9997 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
9998 name="werner.koch@guug.de"></tt> per la conversione da testo semplice a SGML
9999 e la gerarchia delle classi di widget.
10001 <item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
10002 name="crichton@expert.cc.purdue.edu"></tt> per il codice della "MenuFactory"
10003 e per la parte sull'impacchettamento nelle tabelle del tutorial.
10005 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
10006 name="mailto:owt1@cornell.edu"></tt> per la sezione del widget EventBox
10007 (e il patch alla distribuzione). Lui è anche responsabile per il codice
10008 e il tutorial delle selezioni, come per la sezione sulla scrittura di un
10009 proprio widget, e l'applicazione d'esempio. Grazie di tutto Owen.
10011 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
10012 name="mailto:mailto:mvboom42@calvin.edu"></tt> per il suo meraviglioso lavoro
10013 sul Notebook, Progres Bar, Dialogs e File selection. Grazie molto Mark. Sei
10014 stato di grande aiuto.
10016 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
10017 name="mailto:timj@gtk.org"></tt> per il suo grande lavoro sul widget List.
10020 <item> Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
10021 name="johnsonm@redhat.com"> </tt> per le informazioni e il codice dei menu
10026 E a tutti voi che avete fatto commenti e avete aiutato a raffinare questo documento.
10031 <!-- ***************************************************************** -->
10032 <sect> Dichiarazione di Copyright e Licenza
10033 <!-- ***************************************************************** -->
10035 A questa traduzione, Copyright (c) 1997-1998 di Michel Morelli,
10036 Daniele Canazza e Antonio Schifano, si applica la medesime licenza
10037 prevista dal lavoro originale di Ian Main e Tony Gale. Segue la traduzione
10038 di quelle disposizioni e la loro versione originale. In caso di discordanze
10039 fra traduzione e versione originale, fa fede quest'ultima.
10041 Il GTK Tutorial è Copyright (c) 1997 Ian Main.
10043 Copyright (c) 1998 Tony Gale.
10045 E' permesso fare e distribuire copie non modificate di questo manuale,
10046 sotto la condizione che la dichiarazione di copyright e queste disposizioni
10047 siano riportate su tutte le copie.
10048 <p>E' permesso fare e distribuire copie di versioni modificate di questo
10049 documento, sotto le stesse condizioni previste per la copia non modificata,
10050 e che questa dichiarazione di copyright sia inclusa esattamente come
10051 nell'originale, e che l'intero lavoro risultante sia distribuito sotto
10052 i termini di una licenza identica a questa.
10053 <p>E' permesso fare e distribuire copie di traduzioni di questo documento in
10054 altre lingue, sotto le stesse condizioni previste per le versioni modificate.
10055 <p>Nel caso si intenda includere questo documento in un lavoro pubblicato,
10056 si prega di contattarne il curatore, che cercherà di mettere a
10057 disposizione le informazioni più aggiornate.
10058 <p>Non c'è garanzia che questo documento sia rispondente ai propri
10059 propositi. Esso viene semplicemente fornito come una risorsa "free" (libera e
10060 gratuita). In quanto tale, gli autori e i curatori delle informazioni contenute
10061 in esso, non possono dare alcuna garanzia nemmeno sul fatto che tali informazioni
10064 <p>---------------------
10066 The GTK Tutorial is Copyright (C) 1997 Ian Main.
10068 Copyright (C) 1998 Tony Gale.
10070 Permission is granted to make and distribute verbatim copies of this
10071 manual provided the copyright notice and this permission notice are
10072 preserved on all copies.
10073 <P>Permission is granted to copy and distribute modified versions of
10074 this document under the conditions for verbatim copying, provided that
10075 this copyright notice is included exactly as in the original,
10076 and that the entire resulting derived work is distributed under
10077 the terms of a permission notice identical to this one.
10078 <P>Permission is granted to copy and distribute translations of this
10079 document into another language, under the above conditions for modified
10081 <P>If you are intending to incorporate this document into a published
10082 work, please contact the maintainer, and we will make an effort
10083 to ensure that you have the most up to date information available.
10084 <P>There is no guarentee that this document lives up to its intended
10085 purpose. This is simply provided as a free resource. As such,
10086 the authors and maintainers of the information provided within can
10087 not make any guarentee that the information is even accurate.