2 <!doctype linuxdoc system>
5 <author>Ian Main, <tt><htmlurl url="mailto:slow@intergate.bc.ca"
6 name="slow@intergate.bc.ca"></tt>
8 <date>December 1, 1997 - Traduzione Aggiornata al 19 Gennaio 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>
15 GTK (GIMP Toolkit) era orginariamente sviluppato come toolkit per il programma
16 GIMP (General Image Manipulation Program). GTK è costruito sulla base del
17 kit di disegno di GIMP, il GDK (GIMP Drawing Kit) il quale è costruito a sua
18 volta attorno alle funzioni della Xlib. E' chiamato ``toolkit di GIMP'' perché
19 era inizialmente scritto per sviluppare GIMP, ma ora viene utilizzato nello
20 sviluppo di molti progetti software liberi. Gli autori sono
22 <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
23 name="petm@xcf.berkeley.edu"></tt>
24 <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
25 name="spencer@xcf.berkeley.edu"></tt>
26 <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
27 name="jmacd@xcf.berkeley.edu"></tt>
31 GTK è essenzialmente una API (application programmers interface)
32 orientata agli oggetti.
33 Anche se scritto completamente in C, è implementato usando l'idea delle
34 classi e delle funzioni di callback (puntatori a funzioni).
37 C'è anche una terza componente chiamata glib che contiene una serie di
38 implementazioni differenti di alcune chiamate di funzioni standard e anche
39 alcune funzioni aggiuntive, per esempio per la manipolazione delle liste
40 collegate, eccetera. Le funzioni sostitutive sono usate per migliorare la
41 portabilità di GTK. Alcune delle funzioni implementate qui non sono
42 disponibili o non sono standard, altre sono uniche come g_strerror().
43 Altre contengono miglioramenti alle stesse della libc come g_malloc che ha
44 delle utility di debugging migliorate.
47 Questo tutorial è un tentativo di documentare il meglio possibile la libreria gtk
48 e non pretende di essere completo. Questo tutorial suppone una buona conoscenza del
49 linugaggio C e di come creare programmi in C. Saranno facilitati i lettori che hanno una
50 precedente esperienza nella programmazione in X. Se il GTK è il primo insieme di widget
51 che studiate, siete pregati di dirmi come avete trovato questo tutorial e che tipo di problemi
53 Notate che c'è anche una versione per il C++ della libreria GTK (chiamata GTK--), quindi
54 se preferite utilizzare questo linguaggio al posto del C potreste cercare questa versione
56 Ci sono poi un ``wrapper'' Objective C e un collegamento a Guile, ma non ne seguo
60 Mi farebbe molto piacere conoscere qualsiasi problema che abbiate avuto nell'imparare il GTK
61 da questo documento e apprezzerei anche critiche sul come migliorarlo.
65 La prima cosa da fare è certamente quella di scaricare il GTK e installarlo. Potete prendere
66 l'ultima versione dal sito ftp.gimp.org nella directory /pub/gimp. Un'altra possibile sorgente
67 di informazioni è il sito http://www.gimp.org/gtk. GTK usa il comando GNU autoconf per
69 Una volta estratti i file dall'archivio tar, eseguite configure --help per vedere una lista delle
70 opzioni del comando configure.
73 Per iniziare la nostra introduzione a GTK, cominceremo con il più semplice programma
74 possibile . Questo programma crea una finestra con dimensioni (in pixel) di 200x200 e
75 l'unica possibilità di uscita è di ucciderlo ucciso usando la shell o il Window Manager.
80 int main (int argc, char *argv[])
84 gtk_init (&argc, &argv);
86 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
87 gtk_widget_show (window);
95 Tutti i programmi certamente includeranno <gtk/gtk.h> che dichiara le variabili, le funzioni,
96 le strutture, etc. che saranno usate nella tua applicazione GTK.
102 gtk_init (&argc, &argv);
105 invoca la funzione gtk_init(gint *argc, gchar ***argv) che sarà usata in tutte le
106 applicazioni GTK. Questa funzione sistema alcune cose al posto nostro, come la visuale
107 predefinita e la mappa dei colori, e procede poi chiamando gdk_init(gint *argc, gchar ***argv).
108 Questa funzione inizializza la libreria per l'uso, setta il gestore predefinito dei segnali
109 e guarda negli argomenti, passati via linea di comando alla tua applicazione, alla ricerca
110 di uno di questi argomenti:
112 <item> <tt/--display/
113 <item> <tt/--debug-level/
114 <item> <tt/--no-xshm/
116 <item> <tt/--show-events/
117 <item> <tt/--no-show-events/
120 Rimuove questi argomenti dalla lista degli argomenti passati, lasciando quelli non
121 riconosciuti a disposizione della tua applicazione che potrà tenerne conto o ignorarli.
122 In questo modo si crea un set di argomenti standard accettato da tutte le applicazione GTK.
125 Le seguenti 2 linee di codice creano e mostrano la finestra.
128 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
129 gtk_widget_show (window);
132 L'argomento GTK_WINDOW_TOPLEVEL specifica che noi vogliamo che la nostra finestra si
133 sottometta alle decorazioni del windows manager e alla posizione che quest'ultimo indicherà.
134 Invece di creare una finestra avente dimensioni 0x0, la dimensione di una finestra senza
135 figli (altri widget, come i bottoni, etc) è predefinita a 200x200 così che si possa manipolarla.
136 La funzione gtk_widget_show() fa sì che GTK sappia che abbiamo finito di settare gli
137 attributi di questo widget e che quindi quest'ultimo può essere visualizzato.
140 L'ultima linea ci fa entrare nel ciclo principale del GTK.
146 gtk_main() è un'altra chiamata che tu vedrete in tutte le applicazioni GTK. Quando il controllo
147 raggiunge questo punto, l'applicazione si metterà a dormire aspettando che si verifichino eventi
148 di X (come la pressione di un bottone o di un tasto), timeout o notifiche di Input/Output dei file
149 Nel nostro esempio, comunque, tutti gli eventi sono ignorati.
151 <sect1>Hello World in GTK
153 Ok, ora un programma con un widget (un bottone). E' il classico ``Hello World'' alla GTK.
160 /* E' una funzione di ritorno (callback). Gli argomenti passati sono ignorati in questo
162 * Piu' informazioni sulle callback in seguito. */
164 void hello (GtkWidget *widget, gpointer data)
166 g_print ("Hello World\n");
169 gint delete_event(GtkWidget *widget, gpointer data)
171 g_print ("delete event occured\n");
172 /* Se si dà TRUE al manipolatore del segnale ``delete_event'', GTK emettera' il segnale
173 ``destroy''. Fornire FALSE significa non volere che la finestra sia distrutta.
174 Cambia FALSE con TRUE e la finestra principale sara' distrutta con un "delete_event"
177 /* Un'altra callback */
178 void destroy (GtkWidget *widget, gpointer data)
183 int main (int argc, char *argv[])
185 /* GtkWidget e' il tipo di dato per i Widget */
189 /* Questa e' una chiamata presente in tutte le applicazioni GTK. Gli argomenti della
190 linea di comando vengono scorsi e restituiti alla applicazione */
191 gtk_init (&argc, &argv);
193 /* Crea una nuova finestra */
194 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
196 /* Quando alla finestra viene passato il segnale ``delete_event'' (questo
197 * segnale viene passato Windows Manager di solito con l'opzione 'close'
198 * o con la barra del titolo (title bar)) noi chiediamo che la funzione
199 * delete_event() (definita sopra) venga invocata.
200 * Il dato passato come argomento alla funzione di ritorno é NULL
201 * ed é ignorato dalla funzione stessa. */
202 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
203 GTK_SIGNAL_FUNC (destroy), NULL);
205 /* Qui connettiamo l'evento ``destroy'' al gestore del segnale.
206 * Questo evento accade quando noi chiamimo la funzione gtk_widget_destroy()
207 * sulla finestra o se ritorniamo TRUE dalla callback ``delete_event''. */
208 gtk_signal_connect (GTK_OBJECT (window), "destroy",
209 GTK_SIGNAL_FUNC (destroy), NULL);
211 /* Setta il bordo interno della finestra */
212 gtk_container_border_width (GTK_CONTAINER (window), 10);
214 /* Crea un nuovo bottone avente etichetta (label) uguale a ``Hello World'' */
215 button = gtk_button_new_with_label ("Hello World");
217 /* Quando il bottone riceve il segnale ``clicked'', invochera' la funzione
218 * hello() passando NULL come argomento della funzione. La funzione
219 * hello() é definita sopra. */
220 gtk_signal_connect (GTK_OBJECT (button), "clicked",
221 GTK_SIGNAL_FUNC (hello), NULL);
223 /* Questo farà sì che la finestra venga distrutta dalla chiamata
224 * gtk_widget_destroy(window) quando il bottone verrà premuto. Ancora,
225 * questo segnale (``destroy'') puo' arrivare da qui o dal windows
227 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
228 GTK_SIGNAL_FUNC (gtk_widget_destroy),
229 GTK_OBJECT (window));
231 /* Questo inserisce il bottone nella finestra
232 * (un contenitore GTK) */
233 gtk_container_add (GTK_CONTAINER (window), button);
235 /* Il passo finale é il mostrare questo nuovo widget appena creato */
236 gtk_widget_show (button);
239 gtk_widget_show (window);
241 /* Tutte le applicazioni GTK devono avere la funzione gtk_main().
242 * Il controllo finisce qui e attende un evento (come la pressione
243 * di un tasto o l'evento di un mouse).
250 <sect1>Compilare hello World
252 Per compilare si utilizza :
255 gcc -Wall -g helloworld.c -o hello_world -L/usr/X11R6/lib \
256 -lglib -lgdk -lgtk -lX11 -lXext -lm
259 Le librerie sopra (glib, gtk,...) devono essere tutte nel percorso predefinito
260 delle librerie. Se cosi' non fosse aggiungi ``-L<directory>'' e il gcc
261 guarderà in questa directory per cercare le librerie di cui necessita.
262 Per esempio sul mio sistema debian-linux io ho dovuto aggiungere
263 <tt>-L/usr/X11R6/lib</> per riuscire a far trovare le librerie di X11.
266 L'odine della dichiarazione delle librerie é significativo. Il linker
267 sa quali funzioni di una libreria ha bisogno prima di processarla.
270 le librerie che noi linkiamo sono:
272 <item> la libreria glib (-lglib), contiene varie funzioni, ma solo
273 g_print() é usato in questo esempio. GTK si appoggia a questa
274 libreria cosi' devi sempre, comunque, linkarla. Vedi comunque la <ref
275 id="sec_glib" name="glib"> sezione sulla glib per altri dettagli.
276 <item>La libreria GDK (-lgdk), la copertura della X11.
277 <item>La libreria GTK (-lgtk), la libreria dei widget, basata sulla GDK.
278 <item>La libreria xlib(-lX11) la quale è usata dalla GDK.
279 <item>La libreria Xext(-lXext). Questa contiene il codice per le pixmap a
280 memoria condivisa e altre estensioni di X.
281 <item>La libreria matematica (-lm). Questa é usata dalla GTK per vari scopi.
284 <sect1>Teoria dei segnali e delle funzioni di ritorno (callback)
286 Prima di guardare in dettaglio ``Hello World'', discuteremo gli eventi e le
287 funzioni di ritorno. GTK è un toolkit guidato dagli eventi, il che significa
288 che se ne starà a dorimire in gtk_main finché non succederà un evento ed il
289 controllo passerà alla funzione appropriata.
292 Questo passaggio di controllo è fatto usando l'idea dei segnali. Quando succede un
293 evento, come la pressione di un bottone del mouse, verrà emesso il segnale appropriato
294 dal widget che é stato premuto.
295 Questo è il modo in cui GTK fa molto del suo utile lavoro. Per fare sì che un
296 bottone esegua una azione, noi prepareremo un gestore del segnale che catturi
297 questi segnali e chiami la funzione corretta. Questo è fatto usando una
301 gint gtk_signal_connect (GtkObject *object,
308 Dove, il primo argomento è il widget che emetterà il segnale, il secondo è il nome
309 del segnale che si vuole catturare,il terzo è la funzione che verrà invocata
310 quando il segnale sarà catturato e il quarto è il dato che potr essere passato a
314 La funzione specificata come terzo argomento è chiamata ``funzione di ritorno (callback)'',
315 e dovrebbe essere della forma:
318 void callback_func(GtkWidget *widget, gpointer *callback_data);
321 Dove il primo argomento sarà un puntatore al widget che emette il segnale e il
322 secondo un puntatore al dato passato come ultimo argomento della funzione
323 gtk_signal_connect() come descritto sopra.
326 Un'altra chiamata usata nell'esempio Hello World è:
329 gint gtk_signal_connect_object (GtkObject *object,
332 GtkObject *slot_object);
335 gtk_signal_connect_object() è uguale a gtk_signal_connect() eccetto che la
336 funzione di callback usa solo un argomento, un puntatore ad un'oggetto GTK.
337 Cosi' quando usa questa funzione per connettere i segnali, la callback
338 potrebbe essere della forma :
341 void callback_func (GtkObject *object);
344 Dove object è di solito un widget. Noi, generalmente, non assegnamo una callback per
345 gtk_signal_connect_object. Queste sono invocate ,usualmente, per chiamare
346 una funzione GTK che accetta un widget singolo o un oggetto come argomento,
347 come nel caso dell'esempio Hello World.
349 Lo scopo di avere due funzioni per connettere i segnali è semplicemente quello di
350 permettere alla funzione di callback di avere un numero di argomenti diverso.
351 Molte funzioni della libreria GTK accettano solo un singolo puntatore ad un widget
352 GTK come argomento, così per queste si può usare la funzione gtk_signal_connect_object(),
353 mentre per le vostre funzioni potreste aver bisogno di passare dati supplementari alle
356 <sect1>Attraverso Hello World passo per passo
358 Ora che conosciamo la teoria che vi è dietro, iniziamo ad essere più chiari
359 camminando attraverso il programma di Hello World.
362 Questa è la funzione di callback che sarà invocata quando il bottone è clickato.
363 Noi, in questo esempio, ignoriamo sia il widget che i dati passati, ma non è
364 difficile farci invece qualcosa. Il prossimo esempio userà l'argomento passato
365 per dire quale bottone è stato premuto.
368 void hello (GtkWidget *widget, gpointer *data)
370 g_print ("Hello World\n");
375 Questa callback è un po' speciale. L'evento ``delete'' avviene quanto il Window Manager
376 manda questo evento all'applicazione. Qui abbiamo una scelta da fare: cosa fare di questo evento.
377 Possiamo ignorarlo, creare qualche tipo di risposta, o semplicemente terminare
380 Il valore che si restituisce in questa callback fa sì che la GTK sappia cosa fare.
381 Restituire FALSE significa che noi non vogliamo che il segnale ``destroy'' sia emesso,
382 quindi far sì che la nostra applicazione continui a procedere. Ritornare TRUE vuole dire
383 far emettere il segnale ``destroy'' il quale chiamerà il gestore del segnale ``destroy''
384 (o meglio : la nostra funzione di callback).
387 gint delete_event(GtkWidget *widget, gpointer data)
389 g_print ("delete event occured\n");
396 Questa è un'altra funzione di callback la quale fa uscire dal programma chiamando
397 gtk_main_quit(). Non c'è molto da dire al riguardo, è abbastanza auto-esplicativa.
400 void destroy (GtkWidget *widget, gpointer *data)
406 Ritengo che conosciate la funzione main()... si, come tutte le altre applicazioni
407 anche le applicazioni GTK hanno questa funzione.
410 int main (int argc, char *argv[])
415 Questa parte dichiara un puntatore ad una struttura di tipo GtkWidget. Queste sono
416 usate sotto per creare una finestra ed un bottone.
423 Qui vi è ancora la nostra gtk_init. Come prima questa inizializza il toolkit e
424 analizza gli argomenti trovati nella linea di comando_ Tutti gli argomenti riconosciuti
425 nella linea di comando sono rimossi dalla lista degli argomenti e vengono così modificati
426 argc e argv per far sì che sembri che questi non siano mai esisitie permettere alla
427 tua applicazione di analizzare gli argomenti rimasti.
430 gtk_init (&argc, &argv);
433 Crea una nuova finestra. Questo viene spiegato abbastanza approfonditamente più avanti.
434 Viene allocata la memoria per la struttura GtkWidget *window così che si punti ad una struttura
435 valida. In questo modo si predispone la nuova finestra, ma non la si visualizza fino a sotto dove, quasi
436 alla fine del nostro programma, invochiamo gtk_widget_show(window).
438 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
441 Questo è un esempio di come connettere un gestore dei segnali con un oggetto, in questo
442 caso la finestra. Qui viene catturato il segnale ``destroy''. Questo è emesso quando usiamo
443 il Window Manager per uccidere la finestra (e noi restituiamo TRUE dal gestore di ``delete_event'')
444 o quando emettiamo la chiamata gtk_widget_destroy() passando l'oggetto finestra
445 come oggetto da distruggere. Sistemando le cose così, trattiamo entrambi i casi con una singola
446 chiamata. Qui è giusto invocare la funzione destroy() definita sopra con NULL come argomento,
447 la quale termina l'applicazione GTK per noi.
448 Questo ci permetterà di utilizzare il Window Manager per uccidere il programma.
451 GTK_OBJECT e GTK_SIGNAL_FUNC sono macro che interpretano il casting e il controllo di tipo per noi,
452 così da rendere piu' leggibile il codice.
455 gtk_signal_connect (GTK_OBJECT (window), "destroy",
456 GTK_SIGNAL_FUNC (destroy), NULL);
459 La prossima funzione è usata per settare un attributo di un oggetto contenitore. Questo
460 sistema la finestra così da avere un'area vuota all'interno della finestrra larga 10 pixel dove
461 non potrà andare nessun widget. Ci sono altre funzioni simili che vedremo nella
462 sezione <ref id="sec_setting_widget_attributes" name="Settare gli attributi del Widget.">
465 E ancora, GTK_CONTAINER è una macro per interpretare il casting di tipo.
468 gtk_container_border_width (GTK_CONTAINER (window), 10);
471 Questa chiamata crea un nuovo bottone. Alloca spazio in memoria per un nuovo GtkWidget,
472 inizializzandolo e facendo sì che il puntatore a bottone punti ad esso.
473 Quando sarà visualizzato, avrà etichetta ``Hello World''.
476 button = gtk_button_new_with_label ("Hello World");
479 Qui prendiamo il bottone e gli facciamo fare qualcosa di utile.
480 Gli colleghiamo un un gestore di segnale in modo che quando emetterà il
481 segnale ``clicked'', verrà invocata la nostra funzione hello(). Il dato passato
482 alla funzione è ignorato, cosicché alla funzione di callback hello() passiamo
483 semplicemente NULL. Evidentemente il segnale ``clicked'' viene emesso quando
484 premiamo il bottone con il mouse.
487 gtk_signal_connect (GTK_OBJECT (button), "clicked",
488 GTK_SIGNAL_FUNC (hello), NULL);
491 Usiamo questo bottone anche per uscire dal programma. Questo illustrera'
492 come il segnale ``destroy'' può arrivare sia dal Window Manager che dal nostro programma.
493 Quando il bottone è ``clicked'', come sopra, chiamera' la funzione di callback
494 hello() e poi questa nell'ordine in cui sono definite. Si possono avere
495 tante funzioni di callback, quante sono necessarie, e saranno eseguite nell'ordine in cui
496 sono connesse. Visto che la funzione gtk_widget_destroy() accetta come argomento solo un
497 GtkWidget *widget, usiamo la funzione gtk_signal_connect_object()
498 al posto della semplice gtk_signal_connect().
501 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
502 GTK_SIGNAL_FUNC (gtk_widget_destroy),
503 GTK_OBJECT (window));
506 Questa é una chiamata di ``impacchettamento'' che sarà spiegata più avanti.
507 Ma è molto facile da capire. Semplicemente dice alla libreria GTK che il
508 bottone è da mettere nella finestra dove sarà visualizzato.
511 gtk_container_add (GTK_CONTAINER (window), button);
514 A questo punto abbiamo predisposto tutto quello che ci eravamo prefissati.
515 Con tutti i gestori di segnale a posto e il bottone messo nella finestra in cui
516 dovrebbe essere, possiamo dire a GTK di mostrare gli oggetti sullo schermo.
517 L'oggetto finestra viene mostrato per ultimo così che la finestra completa di tutti
518 i suoi oggetti sarà mostrata in una volta sola, invece di vedere
519 prima la finestra spoglia e poi la comparsa del bottone all'interno di essa.
520 Per quanto, con questi semplici esempi, questo l'avrai già notato.
522 gtk_widget_show (button);
524 gtk_widget_show (window);
527 E naturalmente chiamiamo gtk_main(), la quale aspetta l'arrivo degli eventi
528 dal server X e chiamerà l'oggetto interessato per fargli emettere il segnale
533 E il return finale. Il controllo ritorna qui dopo che viene invocata gtk_quit().
539 Ora, quando premiamo il bottone del mouse su un bottone GTK, questo oggetto
540 emette il segnale ``clicked''. Per poter utilizzare queste informazioni, il nostro
541 programma predispone un gestore di segnale per catturare quel segnale, il quale
542 avvia la funzione da noi scelta. Nel nostro esempio, quando il bottone creato viene
543 clickato , la funzione hello() è invocata con un argomento NULL, dopoodiché
544 viene invocato il successivo gestore di questo segnale. Questo chiama la funziona
545 gtk_widget_destroy(), passandole l'oggetto-finestra (window) come argomento, che
546 distruggerà la finestra. Questo fa sì che la finestra emetta il segnale
547 ``destroy'' che viene catturato e che fa invocare la funzione di ritorno
548 destroy(), che semplicemente esce dal programma GTK.
551 Un'altro modo in cui possono andare le cose è l'uso del window manager per uccidere
552 la finestra. Questo causera' l'emissione del segnale ``delete_event'' che
553 automaticamente chiamerà il gestore del segnale ``delete_event''. Se qui noi
554 restituiamo il valore FALSE, la finestra non verrà toccata e tutto procederà come
555 se nulla fosse successo. Dare invece il valore TRUE causerà l'emissione da parte
556 di GTK del segnale ``destroy'' il quale, a sua volta, invocherà la callback ``destroy'',
557 uscendo dall'applicazione.
560 Nota che questi segnali non sono gli stessi del sistema Unix e che non sono
561 implementati usando quei segnali, anche se la terminologia è praticamente identica.
567 Ci sono alcune cose che avrete probabilmente notato nei precedenti esempi che
568 hanno bisogno di una spiegazione. I gint, gchar ecc. che vedete sono tipi di dato
569 riferiti rispettivamente a int e char. Questo viene fatto per rimediare alla brutta
570 dipendenza dalle dimensioni di semplici tipi di dato quando si fanno dei calcoli.
571 Un buon esempio è ``gint32'' il quale sarà un tipo di dato riferito ad un intero a
572 32 bit per tutte le piattaforme x86 e ad un 64 bit per gli alpha.
573 I tipi di dato sono ben spiegati più avanti ed intuitivi. Sono definiti in
574 glib/glib.h (il quale viene incluso da gtk.h).
577 Noterete anche la possibilità di utilizzare un GtkWidget quando la funzione richiede
578 un GtkObject. GTK è una libreria orienta agli oggetti ed un widget è un oggetto.
580 <sect1>Altri Dettagli sui Segnali
582 Diamo un'altra occhiata alla dichiarazione della funzione gtk_signal_connect.
585 gint gtk_signal_connect (GtkObject *object, gchar *name,
586 GtkSignalFunc func, gpointer func_data);
588 Notate il valore di ritorno definito come gint? questo è un identificatore per
589 la tua funzione di callback. Come detto sopra, si possono avere più funzioni di
590 ritorno per ogni segnale e per ogni ogetto a seconda delle necessità. ed ognuna sarà
591 eseguita in sequenza, nell'ordine in cui sono state collegate. Questo identificatore
592 ti permette di rimuovere una funzione dalla lista delle funzioni di ritorno tramite
595 void gtk_signal_disconnect (GtkObject *object,
598 Così passando il widget da cui vuoi rimuovere il gestore di segnale, e
599 l'identificativo restituito da una delle funzioni signal_connect, puoi rimuovere
600 il gestore di segnale che desideri da quella del widget.
603 Un'altra funzione per rimuovere tutti i segnali di un widget in una volta sola è:
606 gtk_signal_handlers_destroy (GtkObject *object);
609 Questa chiamata è abbastanza auto esplicativa. Semplicemente rimuove tutti i segnali
610 collegati al widget che passi alla funzione come argomento.
612 <sect1>Miglioriamo Hello World
615 Diamo un'occhiata ad una migliorata versione di Hello World con altri esempi sulle
616 callback. Questo anche ci introdurrà al nostro prossimo argomento,
617 l'impacchettamento dei widget.
622 /* La nostra funzione di callback migliorata. I dati passati a questa
623 * vengono stampati su stdout. */
624 void callback (GtkWidget *widget, gpointer *data)
626 g_print ("Hello again - %s was pressed\n", (char *) data);
629 /* Un'altra callback */
630 void delete_event (GtkWidget *widget, gpointer *data)
635 int main (int argc, char *argv[])
637 /* GtkWidget e' il tipo di dato per i widget */
642 /* Questa funzione e' invocata in tutte le applicazioni GTK, gli
643 argomenti sono analizzati e restituiti all'applicazione. */
644 gtk_init (&argc, &argv);
646 /* Crea una nuova finestra */
647 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
649 /* Questa e' una nuova chiamata. Assegna "Hello Buttons" come titolo
650 della nostra finestra */
651 gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
653 /* Qui settiamo il gestore per il segnale "delete_event" che
654 immediatamente esce dalla applicazione.
655 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
656 GTK_SIGNAL_FUNC (delete_event), NULL);
659 /* predispone il bordo della finestra */
660 gtk_container_border_width (GTK_CONTAINER (window), 10);
662 /* creiamo una scatola dove mettere tutti i widget. Questa è descritta
663 dettagliatamente nella sezione "packing". La scatola non è realmente
664 visibile, è solamente usata per sistemare i widget. */
665 box1 = gtk_hbox_new(FALSE, 0);
667 /* Inseriamo la scatola nella finestra */
668 gtk_container_add (GTK_CONTAINER (window), box1);
670 /* Creiamo un nuovo bottone con etichetta "Button 1" */
671 button = gtk_button_new_with_label ("Button 1");
673 /* Quando il bottone e' premuto, noi invocheremo la funzione di callback,
674 con un puntatore alla stringa "button 1" come proprio argomento) */
675 gtk_signal_connect (GTK_OBJECT (button), "clicked",
676 GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
678 /* invece di aggiungerlo alla finestra, lo inseriamo nella scatola invisibile,
679 la quale e' stata inserita nella finstra. */
680 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
682 /* Ricordati sempre questo passo. Dice a GTK che la preparazione di questo
683 bottone e' finita e che quindi puo' essere mostrato. */
684 gtk_widget_show(button);
686 /* Facciamo la stessa cosa per il secondo bottone. */
687 button = gtk_button_new_with_label ("Button 2");
689 /* Chiamiamo la stessa funzione ma passandogli un argomento differente,
690 gli passiamo un puntatore alla stringa "button 2" */
691 gtk_signal_connect (GTK_OBJECT (button), "clicked",
692 GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
694 gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
696 /* L'ordine nel quale i bottoni sono visualizzati non e' realmente importante,
697 ma io ti raccomando di mostrare per ultima la finestra cosi' che tutto
698 sia visualizzato in una volta sola */
699 gtk_widget_show(button);
701 gtk_widget_show(box1);
703 gtk_widget_show (window);
705 /* e ora ci mettiamo in gtk_main e aspettiamo che il diverimento inizi.
712 Compilate questo programma usando gli stessi argomenti di link del nostro primo
713 esempio. Noterete che questa volta non c'è un modo semplice per uscire dal programma,
714 si deve usare il nostro window manager o la linea di comando per uccidere
716 Un buon esercizio per il lettore è quello di inserire un tezo bottone ``quit'' che
717 faccia uscire dal programma. Potete anche divertirvi con le opzioni di
718 gtk_box_pack_start() mentre leggete il prossimo capitolo. Provate a ridimensionare
719 la finestra ed a osservare cosa succede.
722 Solo una piccola nota, c'è un'altra definizione di gtk_window_new() -
723 GTK_WINDOW_DIALOG. Questa interagisce con il window manager in un modo un po'
724 diverso, e dovrebbe essere usata per finestre temporanee.
726 <sect>Come ``Impacchettare'' i Widget
728 Nel momento in cui si crea un'applicazione, normalmente si avrà la necessità di mettere più
729 di un unico bottone all'interno di una finestra. Il nostro primo esempio ``Hello World''
730 usava un solo oggetto, cosicché abbiamo potuto usare semplicemente una chiamata
731 a gtk_container_add per impacchettare il widget nella finestra. Quando invece si vuole
732 inserire più di un unico widget in una finestra, come si fa a controllare dove vengono
733 posizionati i propri oggetti? E' qui che entra in gioco il meccanismo dell'``impacchettamento''.
734 <sect1>Teoria delle Scatole per Impacchettamento
736 La maggior parte dell'impacchettamento viene effettuata creando delle scatole
737 come nell'esempio più sopra. Le scatole sono dei contenitori invisibili di
738 widget che possiamo usare per imballarci i nostri oggetti e che esistono in
739 due varietà: in particolare si possono avere scatole orizzontali (hbox) e
741 Quando si impacchentano degli oggetti in una scatola orizzontale, gli oggetti vengono inseriti
742 orizzontalmente da sinistra a destra oppure da destra a sinistra a seconda della
743 chiamata di funzione che si usa. In una scatola verticale, gli oggetti vengono inseriti
744 dall'alto in basso o viceversa. Si può usare qualsiasi combinazione di scatole
745 all'interno o a fianco di altre scatole, fino ad ottenere l'effetto desiderato.
747 Per creare una nuova scatola orizzontale, si usa una chiamata a gtk_hbox_new(), mentre
748 per le scatole verticali si usa gtk_vbox_new(). Per inserire i widget
749 all'interno di questi contenitori si usano le funzioni gtk_box_pack_start() e
750 gtk_box_pack_end(). La funzione gtk_box_pack_start() comincerà dall'alto verso il
751 basso in una vbox e da sinistra a destra in una hbox. gtk_box_pack_end() fa l'opposto,
752 impacchettando dal basso verso l'alto in una vbox e da destra a sinistra in una hbox.
753 Queste funzioni ci permettono di giustificare a destra o a sinistra i nostri
754 widget, e possono essere mescolate in qualsiasi modo per ottenere l'effetto desiderato.
755 Useremo gtk_box_pack_start() nella maggior parte dei nostri esempi. Un oggetto può
756 essere costituito da un altro contenitore o da un oggetto grafico. Infatti, molti
757 oggetti grafici sono a loro volta dei contenitori, compreso il bottone, anche se
758 tipicamente all'interno del bottone mettiamo solo una etichetta.
761 Usando queste chiamate, GTK riesce a capire dove si vogliono piazzare i propri
762 widget, in modo di essere poi in grado di effettuare il ridimensionamento
763 automatico e altre cose interessanti. Esiste poi un insieme di opzioni che riguardano
764 il modo in cui i propri oggetti grafici dovrebbero essere impacchettati. Come
765 si può immaginare, questo metodo dà una buona flessibilità nella creazione e
766 nella disposizione dei propri widget.
767 <sect1>Dettagli sulle Scatole
769 A causa di questa flessibilità, le scatole per impacchettamento del GTK
770 possono, di primo acchito, creare un po' di disorientamento. Sono infatti disponibili
771 molte opzioni, e non è immediato il modo in cui si combinano l'una con l'altra.
772 Alla fine però, si possono ottenere essenzialmente cinque diversi stili.
776 <IMG ALIGN="center" SRC="gtk_tut_packbox1.gif"
777 VSPACE="15" HSPACE="10" ALT="Box Packing Example Image" WIDTH="528"
782 Ogni linea contiene una scatola orizzontale (hbox) con diversi bottoni.
783 La chiamata a gtk_box_pack è una scorciatoia per la chiamata di impacchettamento
784 di ognuno dei bottoni nella hbox. Ognuno dei bottoni viene impacchettato nella
785 hbox nello stesso modo (cioè, con gli stessi argomenti per la funzione gtk_box_pack_start ()).
787 Questa è la dichiarazione della funzione gtk_box_pack_start.
790 void gtk_box_pack_start (GtkBox *box,
796 Il primo argomento è la scatola nella quale si stanno inscatolando i
797 widget, il secondo è il widget stesso. Gli oggetti per ora saranno
798 bottoni, quindi quello che faremo sarà impacchettare bottoni in scatole.
800 L'argomento ``expand'' in gtk_box_pack_start() o gtk_box_pack_end() controlla
801 se gli oggetti devono essere sistemati nella scatola in modo da riempire tutto
802 lo spazio in diponibile presente nella scatola, in modo che la scatola si espanda fino
803 ad occupare tutta l'area assegnatale (valore TRUE).
804 La scatola può anche essere rimpiciolita in modo da contenere esattamente i
805 widget (valore FALSE). Assegnare a expand il valore FALSE permette di giustificare
806 a destra o sinistra i propri oggetti. In caso contrario, tutti gli ogetti si espandono
807 fino ad adattarsi alla scatola, e il medesimo effetto si può ottenere usando solo una
808 delle funzioni gtk_box_pack_start o pack_end.
810 L'argomento ``fill'' delle funzioni gtk_box_pack stabilisce se lo spazio disponibile
811 nella scatola deve essere allocato agli oggetti (TRUE) o se deve essere mantenuto
812 come riempimento attorno a questi oggetti (FALSE). Questo argomento ha effetto
813 solo se a expand è assegnato il valore TRUE.
815 Quando si crea una nuova scatola, la funzione ha questo aspetto:
818 GtkWidget * gtk_hbox_new (gint homogeneous,
822 L'argomento homogeneous di gtk_hbox_new (la stesso per gtk_vbox_new)
823 determina se ogni oggetto nella scatola deve avere la stessa dimensione (cioè
824 la stessa ampiezza in una hbox o la stessa altezza in una vbox). Se è settato,
825 l'argomento expand delle routine gtk_box_pack è sempre attivato.
827 Qual è la differenza fra la spaziatura (che è stabilita quando la scatola
828 viene creata) e il riempimento (che viene stabilito quando gli elementi vengono
829 impacchettati)? La spaziatura viene inserita fra gli oggetti, mentre il
830 riempimento viene aggiuno a ciascuno dei lati dell'oggetti. La seguente figura
831 dovrebbe chiarire meglio questo punto:
834 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif"
835 VSPACE="15" HSPACE="10" ALT="Box Packing Example Image" WIDTH="509"
840 Di seguito è riportato il codice usato per creare le immagini precedenti.
841 L'ho commentato in modo piuttosto pesante, in modo che non dovreste avere
842 problemi nel seguirlo. Compilatelo voi stessi e preovate a giocarci un po'.
844 <sect1>Programma Dimostrativo di Impacchettamento
851 delete_event (GtkWidget *widget, gpointer *data)
856 /* Costruisco una nuova hbox riempita con bottoni-etichette. Gli
857 * argomenti per le varabili che ci interessano sono passati
858 * in questa funzione. Non mostriamo la scatola, ma mostriamo
859 * tutto quello che c'è dentro. */
860 GtkWidget *make_box (gint homogeneous, gint spacing,
861 gint expand, gint fill, gint padding)
867 /* costruisco una nuova hbox con i valori appropriati di
868 * homogeneous e spacing */
869 box = gtk_hbox_new (homogeneous, spacing);
871 /* costruisco una serie di bottoni con i valori appropriati */
872 button = gtk_button_new_with_label ("gtk_box_pack");
873 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
874 gtk_widget_show (button);
876 button = gtk_button_new_with_label ("(box,");
877 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
878 gtk_widget_show (button);
880 button = gtk_button_new_with_label ("button,");
881 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
882 gtk_widget_show (button);
884 /* costruisco un bottone con l'etichetta che dipende dal valore di
887 button = gtk_button_new_with_label ("TRUE,");
889 button = gtk_button_new_with_label ("FALSE,");
891 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
892 gtk_widget_show (button);
894 /* Questo è la stessa cosa della creazione del bottone per "expand"
895 * più sopra, ma usa la forma breve. */
896 button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
897 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
898 gtk_widget_show (button);
900 sprintf (padstr, "%d);", padding);
902 button = gtk_button_new_with_label (padstr);
903 gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
904 gtk_widget_show (button);
910 main (int argc, char *argv[])
916 GtkWidget *separator;
921 /* La nostra inizializzazione, non dimenticatela! :) */
922 gtk_init (&argc, &argv);
925 fprintf (stderr, "uso: packbox num, dove num è 1, 2, o 3.\n");
926 /* questo fa solo un po' di pulizia in GTK, ed esce con un valore 1. */
930 which = atoi (argv[1]);
932 /* Creiamo la nostra finestra */
933 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
935 /* Ci si dovrebbe sempre ricordare di connettere il segnale di destroy
936 * alla finestra principale. Ciò è molto importante per avere un funzionamento
937 * corretto dal punto di vista intuitivo */
938 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
939 GTK_SIGNAL_FUNC (delete_event), NULL);
940 gtk_container_border_width (GTK_CONTAINER (window), 10);
942 /* Creiamo una scatola verticale (vbox) in cui impacchettare quelle
943 * orizzontali. Questo ci permette di impilare le scatole orizzontali
944 * piene di bottoni una sull'altra in questa vbox. */
946 box1 = gtk_vbox_new (FALSE, 0);
948 /* Decide quale esempio si deve mostrare. Corrispondono alle figure precedenti */
951 /* creare una nuova etichetta. */
952 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
954 /* allineare l'etichetta al lato sinistro. Discuteremo questa e altre
955 * funzioni nella sezione dedicata agli attributi degli oggetti grafici. */
956 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
958 /* Impacchettare l'etichetta nella scatola verticale (vbox box1).
959 * Ricordare che gli oggetti che vengono aggiunti in una vbox vengono
960 * impacchettati uno sopra all'altro in ordine. */
961 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
963 /* mostrare l'etichetta */
964 gtk_widget_show (label);
966 /* chiamare la nostra funzione make_box - homogeneous = FALSE,
967 * spacing = 0, expand = FALSE, fill = FALSE, padding = 0 */
968 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
969 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
970 gtk_widget_show (box2);
972 /* chiamare la nostra funzione make_box - homogeneous = FALSE, spacing = 0,
973 * expand = FALSE, fill = FALSE, padding = 0 */
974 box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
975 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
976 gtk_widget_show (box2);
978 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
979 box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
980 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
981 gtk_widget_show (box2);
983 /* Questo crea un separatore. Li conosceremo meglio in seguito,
984 * comunque sono piuttosto semplici. */
985 separator = gtk_hseparator_new ();
987 /* Impacchetta il separatore nella vbox. Ricordare che stiamo impacchettando
988 * ognuno di questi oggetti in una vbox, cosicché essi verranno
989 * impacchettati verticalmente. */
990 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
991 gtk_widget_show (separator);
993 /* crea un'altra nuova etichetta e mostrala. */
994 label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
995 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
996 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
997 gtk_widget_show (label);
999 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1000 box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1001 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1002 gtk_widget_show (box2);
1004 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1005 box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1006 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1007 gtk_widget_show (box2);
1009 /* ancora un nuovo separatore. */
1010 separator = gtk_hseparator_new ();
1011 /* Gli ultimi 3 argumenti per gtk_box_pack_start sono: expand, fill, padding. */
1012 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1013 gtk_widget_show (separator);
1019 /* creare una nuova etichetta, ricordare che box1 è la vbox creata
1020 * vicino all'inizio di main() */
1021 label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1022 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1023 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1024 gtk_widget_show (label);
1026 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1027 box2 = make_box (FALSE, 10, 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, 10, TRUE, TRUE, 0);
1033 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1034 gtk_widget_show (box2);
1036 separator = gtk_hseparator_new ();
1037 /* Gli ultimi tre arcomenti di gtk_box_pack_start sono: expand, fill, padding. */
1038 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1039 gtk_widget_show (separator);
1041 label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1042 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1043 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1044 gtk_widget_show (label);
1046 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1047 box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1048 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1049 gtk_widget_show (box2);
1051 /* Gli argomenti sono: homogeneous, spacing, expand, fill, padding */
1052 box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1053 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1054 gtk_widget_show (box2);
1056 separator = gtk_hseparator_new ();
1057 /* Gli ultimi tre argomenti di gtk_box_pack_start sono: expand, fill, padding. */
1058 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1059 gtk_widget_show (separator);
1064 /* Questo dimostra la possibilità di usare use gtk_box_pack_end() per
1065 * giustificare gli oggetti a destra. Per prima cosa creiamo una
1067 * nuova scatola come prima. */
1068 box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1069 /* creiamo l'etichetta che sarà aggiunta alla fine. */
1070 label = gtk_label_new ("end");
1071 /* impacchettiamola usando gtk_box_pack_end(), così che viene inserita
1072 * sul lato destro della hbox creata nella chiamata a the make_box(). */
1073 gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1074 /* mostriamo l'etichetta. */
1075 gtk_widget_show (label);
1077 /* impacchettiamo box2 in box1 (the vbox, ricordate? :) */
1078 gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1079 gtk_widget_show (box2);
1081 /* un separatore per il fondo */
1082 separator = gtk_hseparator_new ();
1083 /* Questo assegna esplicitamente al separatore l'ampiezza di 400 pixel
1084 * e l'altezza di 5 pixel. Ciò fa sì che la hbox che abbiamo creato sia
1085 * anche essa larga 400 pixel, e che l'etichetta finale sia separata dalle
1086 * altre etichette nella hbox. In caso contrario, tutti gli oggetti nella
1087 * hbox sarebbero impacchettati il più vicino possibile. */
1088 gtk_widget_set_usize (separator, 400, 5);
1089 /* impacchetta il separatore nella vbox (box1) creata vicino all'inizio
1091 gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1092 gtk_widget_show (separator);
1095 /* Creare un'altra nuova hbox.. ricordate che ne possiamo usare quante ne vogliamo! */
1096 quitbox = gtk_hbox_new (FALSE, 0);
1098 /* Il nostro bottone di uscita. */
1099 button = gtk_button_new_with_label ("Quit");
1102 /* Configuriamo il segnale per distruggere la finestra. Ricordate che
1103 * ciò manderà alla finestra il segnale "destroy", che verrà catturato
1104 * dal nostro gestore di segnali che abbiamo definito in precedenza. */
1105 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1106 GTK_SIGNAL_FUNC (gtk_widget_destroy),
1107 GTK_OBJECT (window));
1108 /* impacchetta il bottone in quitbox.
1109 * Gli ultimi tre argomenti di gtk_box_pack_start sono: expand, fill, padding. */
1110 gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1111 /* impacchetta quitbox nella vbox (box1) */
1112 gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1114 /* impacchetta la vbox (box1), che ora contiene tutti i nostri oggetti,
1115 * nella finestra principale. */
1116 gtk_container_add (GTK_CONTAINER (window), box1);
1118 /* e mostra tutto quel che rimane */
1119 gtk_widget_show (button);
1120 gtk_widget_show (quitbox);
1122 gtk_widget_show (box1);
1123 /* Mostriamo la finestra alla fine in modo che tutto spunti fuori assieme. */
1124 gtk_widget_show (window);
1126 /* E, naturalmente, la nostra funzione main. */
1129 /* Il controllo ritorna a questo punto quando viene chiamata gtk_main_quit(),
1130 * ma non quando si usa gtk_exit. */
1137 <sect1>Impacchettamento con uso di Tabelle
1139 Diamo ora un'occhiata ad un altro modo di impacchettare - le Tabelle.
1140 In certe situazioni, possono risultare estremamente utili.
1142 Usando le tabelle, creiamo una griglia in cui possiamo piazzare gli oggetti.
1143 Gli oggetti possono occupare tanti spazi quanti ne specifichiamo.
1145 Naturalmente, la prima cosa da vedere è la funzione gtk_table_new:
1148 GtkWidget* gtk_table_new (gint rows,
1153 Il primo argomento rappresenta il numero di righe da mettere nella tabella,
1154 mentre il secondo è ovviamente il numero di colonne.
1156 L'argomento homogeneous ha a che fare con il modo in cui le caselle della tabella
1157 sono dimensionate. Se homogeneous ha il valore TRUE, le caselle sono ridimensionate
1158 fino alla dimensione del più grande oggetto contenuto nella tabelle. Se è FALSE, la
1159 dimensione delle caselleè decisa dal più alto oggetto in una certa riga e dal più
1160 largo oggetto in una stessa colonna.
1162 Le righe e le colonne sono disposte a partire da 0 fino a n, dove n è il numero
1163 che era stato specificato nella chiamata a gtk_table_new. Così, se specificate
1164 rows = 2 e columns = 2, lo schema avrà questo aspetto:
1168 0+----------+----------+
1170 1+----------+----------+
1172 2+----------+----------+
1175 Notate che il sistema di coordinate ha origine nel vertice in alto a sinistra. Per
1176 mettere un oggetto in una tabella, usate la seguente funzione:
1179 void gtk_table_attach (GtkTable *table,
1191 In cui il primo argomento (``table'') è la tabella che avete creato e il secondo
1192 (``child'') è l'oggetto che volete piazzare nella tabella.
1194 Gli argomenti ``attach'' (right, left, top, bottom) specificano dove mettere l'oggetto
1195 e quante caselle adoperare. Se volete mettere un bottone nella casella in basso a destra
1196 nella nostra tabella 2x2, e volete che esso riempia SOLO quella casella, dovete porre
1197 left_attach = 1, right_attach = 2, top_attach = 1, bottom_attach = 2.
1199 Se invece volete che un oggetto si prenda tutta la riga più in alto nella nostra tabella
1200 2x2, dovreste usare left_attach = 0, right_attach =2, top_attach = 0,
1203 Gli argomenti ``xoptions'' e ``yoptions'' sono usati per specificare le opzioni di impacchettamento;
1204 di essi si può fare l'OR in modo di ottenere opzioni multiple.
1208 <item>GTK_FILL - Se la parte di tabella in cui si vuole inserire il widget è più
1209 grande dell'oggetto, e se si specifica GTK_FILL, l'oggetto viene espanso fino ad
1210 occupare tutto lo spazio disponibile.
1212 <item>GTK_SHRINK - Se si alloca all'oggetto nella tabella meno spazio del necessario
1213 (di solito succede quando l'utente ridimensiona la finestra), allora normalmente
1214 l'oggetto verrebbe spinto fuori dal fondo della finestra fino a sparire.
1215 Se invece si specifica GTK_SHRINK is specified, gli oggetti si rimpiccioliscono
1216 assieme alla tabella.
1218 <item>GTK_EXPAND - Questo fa sì che la tabella si espanda fino ad occupare tutto lo
1219 spazio che rimane nella finestra.
1222 Il riempimento funziona come nelle scatole, con la creazione di un'area vuota
1223 attorno all'oggetto la cui dimensione viene specificata in pixel.
1225 La funzione gtk_table_attach() ha UN MUCCHIO di opzioni. Quindi, ecco una scorciatoia:
1228 void gtk_table_attach_defaults (GtkTable *table,
1233 gint bottom_attach);
1236 Le xoptions e yoptions vengono posti per difetto a GTK_FILL | GTK_EXPAND, e sia xpadding
1237 che ypadding vengono posti a 0. Il resto degli argomenti sono identici a quelli della funzione
1240 Ci sono poi le funzioni gtk_table_set_row_spacing() and gtk_table_set_col_spacing().
1241 Queste mettono dello spazio fra le righe (o colonne)in corrispondenza di una specifica
1245 void gtk_table_set_row_spacing (GtkTable *table,
1251 void gtk_table_set_col_spacing (GtkTable *table,
1256 Notate che per le colonne lo spazio viene posto alla destra della colonna, mentre
1257 per le righe lo spazio viene posto al di sotto della riga.
1259 Si può poi inserire una spaziatura identica fra tutte le righe e/o colonne usando:
1262 void gtk_table_set_row_spacings (GtkTable *table,
1268 void gtk_table_set_col_spacings (GtkTable *table,
1272 Notate che con queste chiamate, all'ultima riga e all'ultima colonna
1273 non viene assegnata alcuna spaziatura.
1275 <sect1>Esempio di Impacchettamento con Tabelle
1277 Per il momento, si prega di fare riferimento all'esempio di tabella in
1278 testgtk.c distribuito con i sorgenti di gtk.
1281 <sect>Panoramica sui Widget
1284 La procedura generale di creazione di un widget in GTK prevede i seguenti passi:
1286 <item> gtk_*_new - una delle varie funzioni che servono per greare un nuovo widget.
1287 In questa sezione le vedremo tutte in dettaglio.
1289 <item> Connettere tutti i segnali che si vogliono usare alle funzione gestione appropriate.
1291 <item> Assegnare gli attributi all'oggetto.
1293 <item> Impacchettare l'oggetto in un contenitore usando la chiamate appropriata,
1294 per esempio gtk_container_add() o gtk_box_pack_start().
1296 <item> Mostrare l'oggetto con gtk_widget_show().
1299 gtk_widget_show() fa sì che GTK sappia che abbiamo terminato di assegnare gli
1300 attributi dell'oggetto grafico, e che è pronto per essere visualizzato.
1301 Si può anche usare la funzione gtk_widget_hide per farlo sparire di nuovo.
1302 L'ordine in cui mostrate gli oggetti grafici non è importante, ma io suggerisco
1303 di mostrare per ultima la finestra, in modo che questa spunti fuori già completa,
1304 invece di vedere i singoli oggetti che arrivano sullo schermo a mano a mano che si
1305 formano. I figli di un oggetto grafico (anche una finestra è un oggetto grafico) non
1306 vengono infatti mostrati finché la finestra stessa non viene mostrata usando la
1307 funzione gtk_widget_show().
1312 Noterete andando avanti che GTK usa un sistema di casting di tipo. Questa operazione
1313 viene sempre effettuata usando delle macro che allo stesso tempo controllano la
1314 possibilità di effettuare il cast sull'elemento dato e lo effettuano realmente.
1315 Alcune macro che avrete modo di incontrare sono:
1318 <item> GTK_WIDGET(widget)
1319 <item> GTK_OBJECT(object)
1320 <item> GTK_SIGNAL_FUNC(function)
1321 <item> GTK_CONTAINER(container)
1322 <item> GTK_WINDOW(window)
1326 Tutte queste funzioni sono usate per fare il cast di argomenti di funzione. Le vedrete
1327 negli esempi, e capirete se è il caso di usarle semplicemente guardando alle
1328 dichiarazioni delle funzioni.
1330 Come potrete vedere più sotto nella gerarchia delle classi, tutti i GtkWidgets
1331 sono derivati dalla classe base GtkObject. Ciò significa che potete usare un
1332 widget in ogni posto in cui una funzione richiede un oggetto - semplicemente
1333 usate la macro GTK_OBJECT().
1338 gtk_signal_connect(GTK_OBJECT(button), "clicked",
1339 GTK_SIGNAL_FUNC(callback_function), callback_data);
1342 Questo fa il cast del bottone in un oggetto e fornisce alla chiamata di ritorno
1343 un cast al puntatore a funzione.
1345 Molti oggetti grafici sono anche contenitori. Se guardate alla gerarchia delle
1346 classi più sotto, vedrete che molti oggetti grafici sono derivati dalla classe
1347 GtkContainer. Ognuna di queste classi può essere usata, con la macro GTK_CONTAINER,
1348 come argomento per funzioni che richiedono un contenitore.
1350 Sfortunatamente, in questo tutorial non si parlerà in modo estensivo di queste macro,
1351 ma raccomando di dare un'occhiata ai file header di GTK. Può essere una cosa molto
1352 educativa. Infatti, non è difficile imparare come funziona un oggetto solo guardando
1353 le dichiarazioni delle funzioni.
1356 <sect1>Gerarchia degli Oggetti Grafici
1358 Ecco, per vostro riferimento, la gerarchia delle classi usata per implementare gli
1369 | | +-- GtkAlignment
1371 | | | *-- GtkAspectFrame
1374 | | | +-- GtkListItem
1375 | | | +-- GtkMenuItem
1376 | | | | +-- GtkCheckMenuItem
1377 | | | | *-- GtkRadioMenuItem
1379 | | | *-- GtkTreeItem
1384 | | \-- GtkFileSelection
1389 | | +-- GtkColorSelection
1393 | | +-- GtkOptionMenu
1394 | | \-- GtkToggleButton
1395 | | \-- GtkCheckButton
1396 | | \-- GtkRadioButton
1404 | +-- GtkScrolledWindow
1438 <sect1>Oggetti senza Finestre
1440 Gli oggetti seguenti non hanno una finestra associata. Se volete catturare
1441 degli eventi, dovrete usare l'oggetto GtkEventBox. Vedete anche la sezione su
1442 <ref id="sec_The_EventBox_Widget" name="Il Widget EventBox">
1468 Proseguiremo la nostra esplorazione di GTK esaminando uno alla volta tutti
1469 gli oggetti, creando qualche semplice funzione per mostrarli. Un'altra
1470 buona sorgente è il programma testgtk.c che viene fornito con GTK. Potete
1471 trovarlo in gtk/testgtk.c.
1473 <sect>Il Widget Bottone (Button)
1475 <sect1>Bottoni Normali
1477 Ormai abbiamo visto tutto quello che c'è da vedere riguardo all'oggetto
1478 ``bottone''. E' piuttosto semplice, ma ci sono due modi per crare un bottone.
1479 Potete usare gtk_button_new_with_label() per creare un bottone con una
1480 etichetta, o usare gtk_button_new() per creare un bottone vuoto. In tal caso è poi
1481 vostro compito impacchettare un'etichetta o una pixmap sul bottone creato.
1482 Per fare ciò, create una nuova scatola, e poi impacchettateci i vostri
1483 oggetti usando la solita gtk_box_pack_start, e infine usate la funzione
1484 gtk_container_add per impacchettare la scatola nel bottone.
1486 Ecco un esempio di utilizzo di gtk_button_new per creare un bottone con
1487 un'immagine ed un'etichetta su di sè. Ho separato il codice usato per
1488 creare la scatola in modo che lo possiate usare nei vostri programmi.
1491 #include <gtk/gtk.h>
1494 /* crea una nuova hbox contenente un'immagine ed un'etichetta
1495 * e ritorna la scatola creata. */
1497 GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
1501 GtkWidget *pixmapwid;
1506 /* creare una scatola per una xpm ed una etichetta */
1507 box1 = gtk_hbox_new (FALSE, 0);
1508 gtk_container_border_width (GTK_CONTAINER (box1), 2);
1510 /* ottengo lo stile del bottone. Penso che sia per avere il colore
1511 * dello sfondo. Se qualcuno sa il vero motivo, è pregato di dirmelo. */
1512 style = gtk_widget_get_style(parent);
1514 /* e ora via con le faccende dell'xpm stuff. Carichiamo l'xpm*/
1515 pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
1516 &style->bg[GTK_STATE_NORMAL],
1518 pixmapwid = gtk_pixmap_new (pixmap, mask);
1520 /* creiamo l'etichetta per il bottone */
1521 label = gtk_label_new (label_text);
1523 /* impacchettiamo la pixmap e l'etichetta nella scatola */
1524 gtk_box_pack_start (GTK_BOX (box1),
1525 pixmapwid, FALSE, FALSE, 3);
1527 gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
1529 gtk_widget_show(pixmapwid);
1530 gtk_widget_show(label);
1535 /* la nostra solita funzione di callback */
1536 void callback (GtkWidget *widget, gpointer *data)
1538 g_print ("Hello again - %s was pressed\n", (char *) data);
1542 int main (int argc, char *argv[])
1544 /* GtkWidget è il tipo per contenere gli oggetti */
1549 gtk_init (&argc, &argv);
1551 /* creiamo una nuova finestra */
1552 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1554 gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
1556 /* E' una buona idea fare questo per tutte le finestre. */
1557 gtk_signal_connect (GTK_OBJECT (window), "destroy",
1558 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1561 /* assegnamo lo spessore del bordo della finestra */
1562 gtk_container_border_width (GTK_CONTAINER (window), 10);
1564 /* creiamo un nuovo bottone */
1565 button = gtk_button_new ();
1567 /* Ormai dovreste esservi abituati a vedere la maggior parte di
1568 * queste funzioni */
1569 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1570 GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
1572 /* questa chiama la nostra funzione di creazione di scatole */
1573 box1 = xpm_label_box(window, "info.xpm", "cool button");
1575 /* impacchetta e mostra tutti i nostri oggetti */
1576 gtk_widget_show(box1);
1578 gtk_container_add (GTK_CONTAINER (button), box1);
1580 gtk_widget_show(button);
1582 gtk_container_add (GTK_CONTAINER (window), button);
1584 gtk_widget_show (window);
1586 /* mettiti in gtk_main e aspetta che cominci il divertimento! */
1592 La funzione xpm_label_box può essere usata per impacchettare delle xpm
1593 e delle etichette su qualsiasi oggetto che può essere un contenitore.
1595 <sect1> Bottoni a Commutazione (Toggle Buttons)
1597 I bottoni a commutazione sono molto simili ai bottoni normali, tranne che per il
1598 fatto che essi si trovano sempre in uno di due stati, che si alternano ad ogni
1599 click. Possono trovarsi nello stato ``premuto'', e quando li si ripreme, tornano
1600 ad essere sollevati. Ri-clickandoli, torneranno giù.
1602 I bottoni a commutazione sono la base per i bottoni di controllo (check button) e
1603 per i radio-bottoni, e quindi molte delle chiamate disponibili per i bottoni
1604 a commutazione vengono ereditati dai radio-bottoni e dai bottoni di controllo.
1605 Ma vedremo questi aspetti nel momento in cui li incontreremo.
1607 Creare un nuovo bottone a commutazione:
1610 GtkWidget* gtk_toggle_button_new (void);
1612 GtkWidget* gtk_toggle_button_new_with_label (gchar *label);
1615 Come potete immaginare, queste funzioni lavorano in modo identico che per
1616 i bottoni normali. La prima crea un bottone a commutazione vuoto e la seconda un
1617 bottone con un'etichetta.
1619 Per ottenere lo stato dei widget a commutazione, compresi i radio-bottoni e i
1620 bottoni di controllo, si può usare una macro come mostrato nell'esempio
1621 più sotto. In questo modo lo stato dell'oggetto commutabile viene valutato in
1622 una funzione di ritorno. Il segnale emesso dai bottoni a commutazione
1623 (toggle button, il radio button o il check button) che ci interessa è il segnale
1624 ``toggled''. Per controllare lo stato di questi bottoni, create un gestore di
1625 segnali che catturi il ``toggled'', e usate la macro per determinare
1626 il suo stato. La funzione di callback avrà un aspetto più o meno così:
1629 void toggle_button_callback (GtkWidget *widget, gpointer data)
1631 if (GTK_TOGGLE_BUTTON (widget)->active)
1633 /* Se il programma si è arrivato a questo punto, il bottone
1634 * a commutazione è sollevato */
1638 /* il bottone è abbassato */
1648 guint gtk_toggle_button_get_type (void);
1651 No idea... they all have this, but I dunno what it is :)
1655 void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
1656 gint draw_indicator);
1663 void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
1667 La chiamata qui sopra può essere usata per fare l'assegnazione dello stato
1668 del bottone a commutazione e dei suoi figli, il radio-bottone e il bottone di
1669 controllo. Passando come primo argomento a questa funzione il vostro bottone e
1670 come secondo argomento il valore TRUE o FALSE, si può specificare se il
1671 bottone deve essere sollevato (rilasciato) o abbassato (premuto). Il valore
1672 di difetto è sollevato, cioè FALSE.
1674 Notate che quando usate la funzione gtk_toggle_button_set_state(), e lo
1675 stato viene cambiato, si ha il risultato che il bottone emette il segnale
1679 void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
1682 Questa funzione semplicemente commuta il bottone, ed emette il segnale ``toggled''.
1684 <sect1> Bottoni di Controllo (Check Buttons)
1686 I bottoni di controllo ereditano molte proprietà e funzioni dal bottone a commutazione,
1687 ma hanno un aspetto un po' diverso. Invece di essere bottoni contenenti del testo,
1688 si tratta di quadratini con del testo alla propria destra. Questi bottoni sono
1689 spesso usati nelle applicazioni per commutare fra lo stato attivato e disattivato delle
1692 Le due funzioni di creazione sono analoghe a quelle del bottone normale..
1695 GtkWidget* gtk_check_button_new (void);
1697 GtkWidget* gtk_check_button_new_with_label (gchar *label);
1700 La funzione new_with_label crea un bottone di controllo con una etichetta
1703 Per controllare lo stato del check button si opera in modo identico al bottone
1706 <sect1> Radio-Bottoni (Radio Buttons)
1708 I radio-bottoni sono simili ai bottoni di controllo, tranne che per il
1709 fatto che sono sempre raggruppati in modo che solo uno alla volta di essi
1710 può essere selezionato (premuto). Tornano utili quando nella propria applicazione
1711 si ha bisogno di selezionare una opzione da una breve lista.
1713 La creazione di un nuovo radio-bottone si fa con una di queste chiamate:
1716 GtkWidget* gtk_radio_button_new (GSList *group);
1718 GtkWidget* gtk_radio_button_new_with_label (GSList *group,
1722 Avrete notato l'argomento in più che c'è in queste chiamate. Queste hanno
1723 infatti bisogno dela specificazione di un ``gruppo'' per svolgere il loro compito.
1724 Per il primo bottone di un gruppo si deve passare come primo argomento il valore
1725 NULL. Dopodiché potete creare un gruppo usando la funzione:
1728 GSList* gtk_radio_button_group (GtkRadioButton *radio_button);
1732 A questo punto potete passare questo gruppo ad ogni chiamata successiva a
1733 gtk_radio_button_new o new_with_label. E' anche una buona idea specificare
1734 esplicitamente quale dei bottoni dovrà essere quello premuto per difetto,
1738 void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
1742 Questa funzione è descritta nella sezione sui bottoni a commutazione, e funziona
1743 nello stesso identico modo.
1746 [Inserirò un esempio di come usare questi oggetti, penso che sarebbe molto
1750 <sect> Alcuni Widget
1752 <sect1> L'Etichetta (Label)
1754 Le etichette sono molto usate in GTK, e sono relativamente semplici. Le
1755 etichette non emettono segnali, dal momento che non hanno una finestra
1756 X a loro assegnata. Se avete la necessità di avere dei segnali o di fare
1757 delle operazioni di clipping, potete usare il widget EventBox.
1759 Per creare una nuova etichetta, si usa:
1762 GtkWidget* gtk_label_new (char *str);
1765 In cui l'unico argomento è la stringa che si vuole sia mostrata.
1767 Per cambiare il testo dell'etichetta dopo che è stata creata, si usa
1771 void gtk_label_set (GtkLabel *label,
1775 in cui il primo argomento è l'etichetta creata in precedenza (di cui si
1776 fa il cast usando la macro GTK_LABEL()), mentre il secondo è la nuova
1779 Nel caso, lo spazio necessario per la nuova stringa verrà regolato automaticamente.
1781 Per ottenere la stringa corrente si usa:
1784 void gtk_label_get (GtkLabel *label,
1788 in cui il primo argomento è l'etichetta che avete creato, e il secondo
1789 è il valore di ritorno per la stringa.
1792 <sect1>Il Widget Suggerimenti (Tooltips)
1794 I suggerimenti sono piccole stringhe di testo che spuntano quando lasciate il
1795 puntatore su un bottone o un altro widget per qualche secondo. Sono piuttosto
1796 semplici da usare, per cui ne darò la spiegazione senza corredarla di esempi.
1797 Se volede vedere un po' di codice, date un'occhiata al programma testgtk.c
1798 distribuito con GTK.
1800 Con alcuni widget (per esempio con l'etichetta) i suggerimenti non funzionano.
1802 La prima chiamata che si usa per creare un nuovo tooltip è la seguente.
1803 In una data funzione, è necessario chiamarla una sola volta: il GtkTooltip
1804 che viene ritornato da questa funzione può essere usato per creare suggerimenti
1808 GtkTooltips *gtk_tooltips_new (void);
1811 Una volta creato un nuovo suggerimento e il widget su cui lo volete usare,
1812 basta usare la seguente chiamata per fare l'assegnazione:
1815 void gtk_tooltips_set_tips (GtkTooltips *tooltips,
1820 Il primo argomento è il suggerimento che era già stato creato, che è seguito
1821 dal widget da cui volete che spunti il suggerimento e dal testo che volete
1824 Ecco un piccolo esempio:
1827 GtkTooltips *tooltips;
1830 tooltips = gtk_tooltips_new ();
1831 button = gtk_button_new_with_label ("button 1");
1833 gtk_tooltips_set_tips (tooltips, button, "This is button 1");
1836 Ci sono anche altre funzioni che si usano con i suggerimenti. Eccone una lista
1837 con una breve descrizione di quello che fanno.
1840 void gtk_tooltips_destroy (GtkTooltips *tooltips);
1843 Distrugge un suggerimento esistente.
1846 void gtk_tooltips_enable (GtkTooltips *tooltips);
1849 Abilita un gruppo di suggerimenti disbilitato.
1852 void gtk_tooltips_disable (GtkTooltips *tooltips);
1855 Disabilita un gruppo di suggerimenti abilitato.
1858 void gtk_tooltips_set_delay (GtkTooltips *tooltips,
1862 Stabilisce quanti millisecondi si deve mantenere il puntatore sopra al
1863 widget prima che venga mostrato il suggerimento. Il valore di difetto
1864 è di 1000 millisecondi.
1867 void gtk_tooltips_set_tips (GtkTooltips *tooltips,
1872 Cambia il testo di un suggerimento già esistente.
1875 void gtk_tooltips_set_colors (GtkTooltips *tooltips,
1876 GdkColor *background,
1877 GdkColor *foreground);
1880 Assegna i colori di primo piano e di sfondo dei suggerimenti. (Non ho idea
1881 di come si specifichino i colori).
1883 E questo è tutto riguardo alle funzioni relative ai suggerimenti. Più
1884 di quanto avreste mai voluto sapere :)
1886 <sect1> La Barra di Avanzamento (Progress Bar)
1888 Le barre di avanzamento sono usate per mostrare lo stato di una operazione. Come potete
1889 vedere nel frammento di codice qui sotto, sono piuttosto semplici da usare.
1890 Ma prima vediamo come cominciare con la chiamata per creare una nuova progrss
1894 GtkWidget *gtk_progress_bar_new (void);
1897 Ora che la barra di avanzamento è stata creata, possiamo usarla..
1900 void gtk_progress_bar_update (GtkProgressBar *pbar, gfloat percentage);
1903 Il primo argomento è la barra di avanzamento su cui volete lavorare, e il secondo
1904 è la quantità 'completato', cioè la quantità di riempimento della progress
1905 bar fra 0 e 100% (un numero reale fra 0 e 1).
1907 Le barre di avanzamento sono usate di solito con funzioni di timeout o altre di
1908 questo tipo (vedi alla sezione <ref id="sec_timeouts" name="Timeouts,
1909 I/O and Idle Functions">) per dare l'illusione del multitasking. Tutte
1910 usano la funzione gtk_progress_bar_update nello stesso modo.
1912 Ecco un esempio di barra di avanzamento, in cui l'aggiornamento avviene usando
1913 dei timeout. Questo codice vi mostra anche come riinizializzare le
1914 barre di avanzamento.
1917 #include <gtk/gtk.h>
1919 static int ptimer = 0;
1922 /* Questa funzione incrementa e aggiorna la barra di avanzamento, e la rimette
1923 a zero se pstat è FALSE */
1924 gint progress (gpointer data)
1928 /* ottiene il valore corrente della status bar */
1929 pvalue = GTK_PROGRESS_BAR (data)->percentage;
1931 if ((pvalue >= 1.0) || (pstat == FALSE)) {
1937 gtk_progress_bar_update (GTK_PROGRESS_BAR (data), pvalue);
1942 /* Questa funzione segnala la riinizializzazione della
1943 barra di avanzamento */
1944 void progress_r (void)
1949 void destroy (GtkWidget *widget, gpointer *data)
1954 int main (int argc, char *argv[])
1962 gtk_init (&argc, &argv);
1964 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1966 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
1967 GTK_SIGNAL_FUNC (destroy), NULL);
1969 gtk_container_border_width (GTK_CONTAINER (window), 10);
1971 table = gtk_table_new(3,2,TRUE);
1972 gtk_container_add (GTK_CONTAINER (window), table);
1974 label = gtk_label_new ("Progress Bar Example");
1975 gtk_table_attach_defaults(GTK_TABLE(table), label, 0,2,0,1);
1976 gtk_widget_show(label);
1977 /* Crea una nuova barra di avanzamento, impacchettala nella tabella
1979 pbar = gtk_progress_bar_new ();
1980 gtk_table_attach_defaults(GTK_TABLE(table), pbar, 0,2,1,2);
1981 gtk_widget_show (pbar);
1983 /* Attiva un timeout che gestisca l'aggiornamento automatico della barra */
1984 ptimer = gtk_timeout_add (100, progress, pbar);
1986 /* Questo bottone segnala alla barra che deve essere resettata */
1987 button = gtk_button_new_with_label ("Reset");
1988 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1989 GTK_SIGNAL_FUNC (progress_r), NULL);
1990 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,2,3);
1991 gtk_widget_show(button);
1993 button = gtk_button_new_with_label ("Cancel");
1994 gtk_signal_connect (GTK_OBJECT (button), "clicked",
1995 GTK_SIGNAL_FUNC (destroy), NULL);
1997 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,2,3);
1998 gtk_widget_show (button);
2000 gtk_widget_show(table);
2001 gtk_widget_show(window);
2009 In questo programmino ci sono quattro aree che riguardano il modo di
2010 uso generale delle Barre di Avanzamento; le vediamo ora nell'ordine.
2013 pbar = gtk_progress_bar_new ();
2016 Questo codice crea una nuova barra ciamata pbar.
2019 ptimer = gtk_timeout_add (100, progress, pbar);
2022 Questo codice usa dei timeout per abilitare degli intervalli di tempo uguali.
2023 Per usare le barre di avanzamento non è però necessario servirsi di timeout.
2026 pvalue = GTK_PROGRESS_BAR (data)->percentage;
2029 Qui si assegna a pvalue il valore corrente della percentuale di avanzamento.
2032 gtk_progress_bar_update (GTK_PROGRESS_BAR (data), pvalue);
2035 Infine, questo codice aggiorna la barra di avanzamento con il valore di pvalue.
2037 Questo è tutto quanto c'è da sapere sulle barre di avanzamento, divertitevi.
2042 Il widget ``Dialogo'' è molto semplice: si tratta in realtà di una finestra
2043 con alcuni elementi pre-impacchettati. La struttura di un dialogo è la
2052 GtkWidget *action_area;
2056 Come potete vedere, crea semplicemente una finestra vi inserisce una vbox
2057 in cima, poi un separatore e infine una hbox come ``area di azione''.
2059 Un Dialogo può essere utilizzato per messaggi per l'utente e
2060 altri scopi simili. E' un widget molto essenziale, che ha una sola funzione,
2064 GtkWidget* gtk_dialog_new (void);
2067 Per cui, per creare una nuova finestra di dialogo, uate:
2071 window = gtk_dialog_new ();
2074 Questa funzione crea una finestra di dialogo, dopodiché sta a voi
2075 utilizzarla. Potete mettere un bottone nella action_area facendo
2080 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button,
2082 gtk_widget_show (button);
2085 Potreste anche aggiungere, ad esempio, un'etichetta all'area della vbox,
2086 con qualcosa di questo genere:
2089 label = gtk_label_new ("Dialogs are groovy");
2090 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), label, TRUE,
2092 gtk_widget_show (label);
2095 Per provare a usare una finestra di dialogo, potreste provare a mettere
2096 due bottoni nella action_area, per esempio un bottone ``Cancella'' ed un
2097 bottone ``OK'' e un'etichetta nella vbox che chieda qualcosa all'utente o
2098 segnali un errore. Poi potreste collegare un diverso segnale a ciascun
2099 bottone ed eseguire l'operazione che l'utente che viene scelta dall'utente.
2105 Le Pixmap sono strutture dati che contengono immagini. Queste immagini
2106 possono poi essere utilizzate in varie occasioni, per esempio come
2107 icone sul desktop X-Window o come cusori. Una bitmap è una pixmap a due
2110 Per usare una pixmap in GTK, dobbiamo in primo luogo creare una struttura
2111 GdkPixmap utilizzando le routine disponibili nello strato GDK. Una Pixmap
2112 può essere creata a partire da dati presenti in memoria o letti da un file.
2113 Vedremo ora una ad una le chiamate utilizzate per creare una pixmap.
2116 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
2122 Si usa questa routine per creare una pixmap ad un solo piano (2 colori) da
2123 dati disponibili in memoria. Ogni bit nei dati indica lo stato acceso o
2124 spento di un pixel. L'altezza (height) e la larghezza (width) sono espresse
2125 in pixel. GdkWindow è un puntatore alla finestra corrente, dal momento che
2126 le risorse di una pixmap hanno significato solo nel contesto dello schermo
2127 in cui deve essere mostrata.
2130 GdkPixmap* gdk_pixmap_create_from_data( GdkWindow *window,
2139 Questa è usata per creare una pixmap con la profondità data (depth, ossia
2140 numero di colori) usando i dati specificati. fg e bg indicano i colori da
2141 usare per il primo piano e per lo sfondo.
2144 GdkPixmap* gdk_pixmap_create_from_xpm( GdkWindow *window,
2146 GdkColor *transparent_color,
2147 const gchar *filename );
2150 Il formato XPM è una rappresentazione di pixmap leggibile per X Window. E' una
2151 rappresentazione molto diffusa, e sono disponibili parecchi programmi per creare
2152 immagini in questo formato. Il file specificato da ``filename'' deve contenere
2153 un'immagine in questo formato, che viene caricato nella struttura pixmap.
2154 La maschera (mask) specifica quali pixel della pixmap devono essere opachi.
2155 Tutti gli altri pixel sono colorati usando il colore specificato da
2156 transparent_color. Più sotto mostreremo un esempio di uso di questa funzione.
2159 GdkPixmap* gdk_pixmap_create_from_xpm_d (GdkWindow *window,
2161 GdkColor *transparent_color,
2165 Si possono incorporare piccole immagini all'interno di un programma sotto
2166 forma di dati in formato XPM. In questo modo, invece di leggerli da un file,
2167 si possono usare questi dati per creare una pixmap. Un esempio di questo tipo
2172 static const char * xpm_data[] = {
2175 ". c #000000000000",
2176 "X c #FFFFFFFFFFFF",
2196 void gdk_pixmap_destroy( GdkPixmap *pixmap );
2199 Quando abbiamo finito di usare una pixmap e pensiamo di non doverla riutilizzare
2200 presto, è una buona idea liberare queste risorse usando la funzione
2201 dk_pixmap_destroy. Le pixmap devono essere considerate una risorsa preziosa.
2203 Quando abbiamo creato una pixmap, possiamo mostrarla come un widget GTK.
2204 E' necessario creare un widget pixmap che contenga una pixmap GDK. Questa
2205 operazione viene compiuta usando
2208 GtkWidget* gtk_pixmap_new( GdkPixmap *pixmap,
2212 Le altre chiamate per i widget pixmap sono
2215 guint gtk_pixmap_get_type( void );
2216 void gtk_pixmap_set( GtkPixmap *pixmap,
2219 void gtk_pixmap_get( GtkPixmap *pixmap,
2224 La funzione gtk_pixmap_set viene usata per cambiare la pixmap che viene
2225 gestita correntemente dal widget.
2226 gtk_pixmap_set is used to change the pixmap that the widget is currently
2227 managing. ``val'' è la pixmap che è stata creata usando il GDK.
2228 Segue un esempio di uso di una pixmap in un bottone.
2232 #include <gtk/gtk.h>
2235 /* dat XPM dell'icona Apri File */
2236 static const char * xpm_data[] = {
2239 ". c #000000000000",
2240 "X c #FFFFFFFFFFFF",
2259 /* quando invocata (con il segnale delete_event), termina l'applicazione. */
2260 void close_application( GtkWidget *widget, gpointer *data ) {
2265 /* invocata se il bottone è clickato. Stampa semplicemente un messaggio */
2266 void button_clicked( GtkWidget *widget, gpointer *data ) {
2267 printf( "button clicked\n" );
2273 int main( int argc, char *argv[] )
2275 /* i widget sono memorizzati nel tipo GtkWidget */
2276 GtkWidget *window, *pixmapwid, *button;
2281 /* crea la finestra principale, e collega il segnale delete_event
2282 alla terminazione dell'applicazione */
2283 gtk_init( &argc, &argv );
2284 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
2285 gtk_signal_connect( GTK_OBJECT (window), "delete_event",
2286 GTK_SIGNAL_FUNC (close_application), NULL );
2287 gtk_container_border_width( GTK_CONTAINER (window), 10 );
2288 gtk_widget_show( window );
2290 /* la pixmap proviene da gdk */
2291 style = gtk_widget_get_style( window );
2292 pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
2293 &style->bg[GTK_STATE_NORMAL],
2294 (gchar **)xpm_data );
2296 /* un widget pixmap per contenere la pixmap */
2297 pixmapwid = gtk_pixmap_new( pixmap, mask );
2298 gtk_widget_show( pixmapwid );
2300 /* un bottone per contenere il widget pixmap */
2301 button = gtk_button_new();
2302 gtk_container_add( GTK_CONTAINER(button), pixmapwid );
2303 gtk_container_add( GTK_CONTAINER(window), button );
2304 gtk_widget_show( button );
2306 gtk_signal_connect( GTK_OBJECT(button), "clicked",
2307 GTK_SIGNAL_FUNC(button_clicked), NULL );
2309 /* mostra la finestra */
2317 Per caricare una pixmap da un file XPM chiamato icon0.xpm che si trova
2318 nella direttorio corrente, avremmo creato la pixmap in questo modo:
2321 /* carica una pixmap da un file */
2322 pixmap = gdk_pixmap_create_from_xpm( window->window, &mask,
2323 &style->bg[GTK_STATE_NORMAL],
2325 pixmapwid = gtk_pixmap_new( pixmap, mask );
2326 gtk_widget_show( pixmapwid );
2327 gtk_container_add( GTK_CONTAINER(window), pixmapwid );
2333 Uno degli svantaggi di usare le pixmap è costituito dal fatto che l'oggetto
2334 mostrato è sempre rettangolare, a prescindere dall'immagine. Ci piacerebbe
2335 invece poter crare dei desktop e delle immagini con forme più naturali. Per
2336 esempio, per l'interfaccia di un gioco, potremmo volere avere dei pulsanti
2337 circolari. Il modo per ottenere questo effetto è di usare delle finestre
2340 Una finestra sagomata è semplicemente una pixmap in cui i pixel dello
2341 sfondo sono trasparenti. In questo modo, se l'immagine di sfondo è
2342 multicolore, possiamo evitare di sovrascriverla con un bordo rettangolare
2343 attorno all'icona. Il prossimo esempio mostra una carriola sul desktop.
2347 #include <gtk/gtk.h>
2352 static char * WheelbarrowFull_xpm[] = {
2355 ". c #DF7DCF3CC71B",
2356 "X c #965875D669A6",
2357 "o c #71C671C671C6",
2358 "O c #A699A289A699",
2359 "+ c #965892489658",
2360 "@ c #8E38410330C2",
2361 "# c #D75C7DF769A6",
2362 "$ c #F7DECF3CC71B",
2363 "% c #96588A288E38",
2364 "& c #A69992489E79",
2365 "* c #8E3886178E38",
2366 "= c #104008200820",
2367 "- c #596510401040",
2368 "; c #C71B30C230C2",
2369 ": c #C71B9A699658",
2370 "> c #618561856185",
2371 ", c #20811C712081",
2372 "< c #104000000000",
2373 "1 c #861720812081",
2374 "2 c #DF7D4D344103",
2375 "3 c #79E769A671C6",
2376 "4 c #861782078617",
2377 "5 c #41033CF34103",
2378 "6 c #000000000000",
2379 "7 c #49241C711040",
2380 "8 c #492445144924",
2381 "9 c #082008200820",
2382 "0 c #69A618611861",
2383 "q c #B6DA71C65144",
2384 "w c #410330C238E3",
2385 "e c #CF3CBAEAB6DA",
2386 "r c #71C6451430C2",
2387 "t c #EFBEDB6CD75C",
2388 "y c #28A208200820",
2389 "u c #186110401040",
2390 "i c #596528A21861",
2391 "p c #71C661855965",
2392 "a c #A69996589658",
2393 "s c #30C228A230C2",
2394 "d c #BEFBA289AEBA",
2395 "f c #596545145144",
2396 "g c #30C230C230C2",
2397 "h c #8E3882078617",
2398 "j c #208118612081",
2399 "k c #38E30C300820",
2400 "l c #30C2208128A2",
2401 "z c #38E328A238E3",
2402 "x c #514438E34924",
2403 "c c #618555555965",
2404 "v c #30C2208130C2",
2405 "b c #38E328A230C2",
2406 "n c #28A228A228A2",
2407 "m c #41032CB228A2",
2408 "M c #104010401040",
2409 "N c #492438E34103",
2410 "B c #28A2208128A2",
2411 "V c #A699596538E3",
2412 "C c #30C21C711040",
2413 "Z c #30C218611040",
2414 "A c #965865955965",
2415 "S c #618534D32081",
2416 "D c #38E31C711040",
2417 "F c #082000000820",
2426 "ty> 459@>+&& ",
2428 "%$;=* *3:.Xa.dfg> ",
2429 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
2430 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
2431 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
2432 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
2433 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
2434 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
2435 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
2436 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
2437 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
2438 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
2439 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
2440 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
2441 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
2442 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
2443 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
2444 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
2445 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
2446 " p;<69BvwwsszslllbBlllllllu<5+ ",
2447 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
2448 " c1-699Blvlllllu7k96MMMg4 ",
2449 " *10y8n6FjvllllB<166668 ",
2450 " S-kg+>666<M<996-y6n<8* ",
2451 " p71=4 m69996kD8Z-66698&& ",
2452 " &i0ycm6n4 ogk17,0<6666g ",
2453 " N-k-<> >=01-kuu666> ",
2454 " ,6ky& &46-10ul,66, ",
2455 " Ou0<> o66y<ulw<66& ",
2456 " *kk5 >66By7=xu664 ",
2457 " <<M4 466lj<Mxu66o ",
2458 " *>> +66uv,zN666* ",
2468 /* quando invocata (con il segnale delete_event), termina l'applicazione. */
2469 void close_application( GtkWidget *widget, gpointer *data ) {
2474 int main (int argc, char *argv[])
2476 /* il tipo di dato per i widget è GtkWidget */
2477 GtkWidget *window, *pixmap, *fixed;
2478 GdkPixmap *gdk_pixmap;
2483 /* crea la finestra principale e collega il segnale delete_event per
2484 terminare l'applicazione. Notare che non mettiamo un titolo
2486 gtk_init (&argc, &argv);
2487 window = gtk_window_new( GTK_WINDOW_POPUP );
2488 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
2489 GTK_SIGNAL_FUNC (close_application), NULL);
2490 gtk_widget_show (window);
2492 /* ora occupiamoci della pixmap e del widget pixmap */
2493 style = gtk_widget_get_default_style();
2494 gc = style->black_gc;
2495 gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &mask,
2496 &style->bg[GTK_STATE_NORMAL],
2497 WheelbarrowFull_xpm );
2498 pixmap = gtk_pixmap_new( gdk_pixmap, mask );
2499 gtk_widget_show( pixmap );
2501 /* Per mostrare la pixmap, usiamo un widget "fixed" in cui metterla */
2502 fixed = gtk_fixed_new();
2503 gtk_widget_set_usize( fixed, 200, 200 );
2504 gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
2505 gtk_container_add( GTK_CONTAINER(window), fixed );
2506 gtk_widget_show( fixed );
2508 /* Questa maschera tutto tranne l'immagine stessa */
2509 gtk_widget_shape_combine_mask( window, mask, 0, 0 );
2511 /* mostra la finestra */
2512 gtk_widget_set_uposition( window, 20, 400 );
2513 gtk_widget_show( window );
2520 Per rendere sensibile l'immagine della carriola, potremmo collegare
2521 il segnale di pressione del bottone in modo che venga compiuta una certa
2522 azione. Le prossime linee renderebbero l'immagine sensibile alla pressione
2523 di un bottone del mouse che fa sì che l'applicazione termini.
2526 gtk_widget_set_events( window,
2527 gtk_widget_get_events( window ) |
2528 GDK_BUTTON_PRESS_MASK );
2530 gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
2531 GTK_SIGNAL_FUNC(close_application), NULL );
2535 <sect> Widget Contenitore
2537 <sect1> Il widget Blocco Note (Notebook)
2539 Il widget Blocco note è un insieme di pagine sovrapposte l'una con l'altra,
2540 ognuna contente cose diverse. Questo widget è diventato molto comune nella
2541 programmazione delle interfacce utente ed è un buon metodo per mostrare informazioni
2542 tra loro correlate ma che debbano essere mostrate separatamente.
2545 La prima funzione da invocare che si deve conoscere, come si può intuire, è usata
2546 per creare un nuovo Blocco Note.
2549 GtkWidget* gtk_notebook_new (void);
2552 Una volta che il notebook è sato creato, ci sono 12 funzioni che possono
2553 operare sul widget notebook. Guardiamole individualmente.
2555 La prima che vediamo riguarda come posizionare l'indicatore di pagina.
2556 Questi inidicatori di pagina o ``linguette'' (come possono anche essere chiamati)
2557 possono essere posizionati in quattro posti: alto, basso, sinistra.destra.
2560 void gtk_notebook_set_tab_pos (GtkNotebook *notebook, GtkPositionType pos);
2563 GtkPositionType sarà uno dei seguenti valori (molto autoesplicativi)
2566 <item> GTK_POS_RIGHT
2568 <item> GTK_POS_BOTTOM
2571 GTK_POS_TOP e' il valore predefinito.
2573 Ora vediamo come aggiugere le pagine al Blocco Note. Ci sono 3 modi per farlo. Diamo
2574 un'occhiata ai primi due insieme, viste che sono molto simili.
2577 void gtk_notebook_append_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
2579 void gtk_notebook_prepend_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
2582 Queste funzioni aggiungono pagine al notebook inserendole rispettivamente alla fine
2583 (append) o all'inizio (prepend). *child è il widget che è posto nella pagina del
2584 notebook e *tab_label e la intestazione della pagina stessa.
2586 L'ultima funzione per aggiungere una pagina al notebook contiene tutte le proprietà
2587 delle precedenti due, ma permette di specificare dove posizionare la pagina che
2591 void gtk_notebook_insert_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, gint position);
2594 I parametri sono gli stessi di _append_ e _prepend_ tranne che per il parametro in
2595 più: ``position''.
2596 Questo parametro viene usato per specificare in che posizione ineserire la pagina.
2598 Ora che conosciamo come aggiungere le pagine, vediamo come poter toglierne una.
2601 void gtk_notebook_remove_page (GtkNotebook *notebook, gint page_num);
2604 Questa funzione prende il numero della pagina specificata dal campo page_num e
2605 rimuove la pagina corrispondente dal Blocco Note.
2607 Per trovare qual'è la pagina corrente nel notebook bisogna usare la funzione:
2610 gint gtk_notebook_current_page (GtkNotebook *notebook);
2613 Le prossime due funzioni sono semplicemente delle chiamate che muovono la pagina del
2614 notebook avanti o indietro. Semplicemente forniscono le chiamate alle rispettive
2615 funzioni del widget notebook su si può operare. NB: quando un notebook è
2616 correntemente sull'ultima pagina e viene invocata la funzione gtk_notebook_next_page,
2617 il notebook ritornerà automaticamente alla prima pagina. Logicamente succede anche
2618 il contrario quando invochi gtk_notebook_prev_page e ti trovi sulla prima pagina.
2621 void gtk_notebook_next_page (GtkNoteBook *notebook);
2622 void gtk_notebook_prev_page (GtkNoteBook *notebook);
2625 La prossima funzione stabilisce la pagina ``attiva''. Se si vuole che la pagina
2626 principale del notebook sia per esempio la 5 (ad esempio) si può usare questa
2628 Se non si usa questa funzione la pagina principale sarà la 1.
2631 void gtk_notebook_set_page (GtkNotebook *notebook, gint page_num);
2634 Le prossime due funzioni aggiungono o rimuovono, rispettivamente, le intestazioni e
2635 i bordi delle pagine.
2638 void gtk_notebook_set_show_tabs (GtkNotebook *notebook, gint show_tabs);
2639 void gtk_notebook_set_show_border (GtkNotebook *notebook, gint show_border);
2642 show_tabs e show_border posso avere come valore TRUE o FALSE (0 or 1).
2644 Diamo ora una occhiata ad un esempio. Si tratta di una espansione del codice preso
2645 dal file testgtk.c che è compreso in tutte le distribuzioni, e mostra
2646 tutte le 13 funzioni. Questo piccolo programma crea una finestra con un notebook
2647 e 6 bottoni. Il notebook contiene 11 pagine, aggiunte nei 3 modi differenti (alla
2648 fine, all'inizio o in qualsiasi posizione). I bottoni permettono di girare le
2649 intestazioni, aggiungere/rimuovere le intestazioni e i bordi, rimuovere una
2650 pagina, cambiare la pagina avanti e indietro e uscire dal programma.
2654 #include <gtk/gtk.h>
2656 /* Queta funzione ruota le posizione delle linguette delle pagine */
2657 void rotate_book (GtkButton *button, GtkNotebook *notebook)
2659 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
2662 /* Aggiunge e rimuove le linguette e i bordi */
2663 void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
2667 if (notebook->show_tabs == 0)
2669 if (notebook->show_border == 0)
2672 gtk_notebook_set_show_tabs (notebook, tval);
2673 gtk_notebook_set_show_border (notebook, bval);
2676 /* Rimuove una pagina */
2677 void remove_book (GtkButton *button, GtkNotebook *notebook)
2681 page = gtk_notebook_current_page(notebook);
2682 gtk_notebook_remove_page (notebook, page);
2683 /* E' necessario fare un refresh del widget --
2684 Questo forza il widget a ridisegnarsi. */
2685 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
2688 void delete (GtkWidget *widget, gpointer *data)
2693 int main (int argc, char *argv[])
2698 GtkWidget *notebook;
2701 GtkWidget *checkbutton;
2706 gtk_init (&argc, &argv);
2708 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2710 gtk_signal_connect (GTK_OBJECT (window), "destroy",
2711 GTK_SIGNAL_FUNC (destroy), NULL);
2713 gtk_container_border_width (GTK_CONTAINER (window), 10);
2715 table = gtk_table_new(2,6,TRUE);
2716 gtk_container_add (GTK_CONTAINER (window), table);
2718 /* Crea un nuovo notebook, e tabilisce la posizione delle linguette */
2719 notebook = gtk_notebook_new ();
2720 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
2721 gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
2722 gtk_widget_show(notebook);
2724 /* appende una parte delle pagine */
2725 for (i=0; i < 5; i++) {
2726 sprintf(bufferf, "Append Frame %d", i+1);
2727 sprintf(bufferl, "Page %d", i+1);
2729 frame = gtk_frame_new (bufferf);
2730 gtk_container_border_width (GTK_CONTAINER (frame), 10);
2731 gtk_widget_set_usize (frame, 100, 75);
2732 gtk_widget_show (frame);
2734 label = gtk_label_new (bufferf);
2735 gtk_container_add (GTK_CONTAINER (frame), label);
2736 gtk_widget_show (label);
2738 label = gtk_label_new (bufferl);
2739 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
2743 /* Ora aggiungiamo una pagina in una certa posizione */
2744 checkbutton = gtk_check_button_new_with_label ("Check me please!");
2745 gtk_widget_set_usize(checkbutton, 100, 75);
2746 gtk_widget_show (checkbutton);
2748 label = gtk_label_new ("Add spot");
2749 gtk_container_add (GTK_CONTAINER (checkbutton), label);
2750 gtk_widget_show (label);
2751 label = gtk_label_new ("Add page");
2752 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
2754 /* Ora finalmente aggiungiamo le pagine all'inizio */
2755 for (i=0; i < 5; i++) {
2756 sprintf(bufferf, "Prepend Frame %d", i+1);
2757 sprintf(bufferl, "PPage %d", i+1);
2759 frame = gtk_frame_new (bufferf);
2760 gtk_container_border_width (GTK_CONTAINER (frame), 10);
2761 gtk_widget_set_usize (frame, 100, 75);
2762 gtk_widget_show (frame);
2764 label = gtk_label_new (bufferf);
2765 gtk_container_add (GTK_CONTAINER (frame), label);
2766 gtk_widget_show (label);
2768 label = gtk_label_new (bufferl);
2769 gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
2772 /* Stabilisce quale sarà la prima pagina che sarà visualizzata. */
2773 gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
2776 /* Crea un set di bottoni */
2777 button = gtk_button_new_with_label ("close");
2778 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2779 GTK_SIGNAL_FUNC (destroy), NULL);
2780 gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
2781 gtk_widget_show(button);
2783 button = gtk_button_new_with_label ("next page");
2784 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2785 (GtkSignalFunc) gtk_notebook_next_page,
2786 GTK_OBJECT (notebook));
2787 gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
2788 gtk_widget_show(button);
2790 button = gtk_button_new_with_label ("prev page");
2791 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2792 (GtkSignalFunc) gtk_notebook_prev_page,
2793 GTK_OBJECT (notebook));
2794 gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
2795 gtk_widget_show(button);
2797 button = gtk_button_new_with_label ("tab position");
2798 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2799 (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
2800 gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
2801 gtk_widget_show(button);
2803 button = gtk_button_new_with_label ("tabs/border on/off");
2804 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2805 (GtkSignalFunc) tabsborder_book,
2806 GTK_OBJECT (notebook));
2807 gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
2808 gtk_widget_show(button);
2810 button = gtk_button_new_with_label ("remove page");
2811 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2812 (GtkSignalFunc) remove_book,
2813 GTK_OBJECT(notebook));
2814 gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
2815 gtk_widget_show(button);
2817 gtk_widget_show(table);
2818 gtk_widget_show(window);
2826 E speriamo che questo vi aiuti a creare i Blocco Note per le vostre applicazioni GTK!
2828 <sect1> Finestre Scorribili (Scrolled Windows)
2830 Le Finestre Scorribili sono usate per creare areee scorribili in una vera finestra.
2831 Si può inserire qualsiasi tipo di widget in questo tipo di finestra, e possono poi
2832 essere accessibili a prescindere dalle dimensioni usando le barre di scorrimento.
2834 La funzione seguente è usata per creare una nuova scrolled window.
2837 GtkWidget* gtk_scrolled_window_new (GtkAdjustment *hadjustment,
2838 GtkAdjustment *vadjustment);
2841 Il primo argomento è l'aggiustamento (di quanto scendere ogni
2842 volta) orizzontale e il secondo è quello verticale. A questi si assegna
2843 quasi sempre il valore NULL.
2846 void gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
2847 GtkPolicyType hscrollbar_policy,
2848 GtkPolicyType vscrollbar_policy);
2851 Questa funzione stabilisce la politica da usare nella barra di scorrimento. Il primo
2852 argomento è la finestra scorribile interessata. Il secondo stabilisce la politica
2853 per la barra di scorrimento orizzontale e il terzo è quello per la politca verticale.
2855 La politica può essere GTK_POLICY AUTOMATIC o GTK_POLICY_ALWAYS.
2856 GTK_POLICY_AUTOMATIC decide automaticamente se la barra di scorrimento deve essere
2857 visualizzata, mentre con GTK_POLICY_ALWAYS la barra verrà sempre mostrata.
2860 #include <gtk/gtk.h>
2862 void destroy(GtkWidget *widget, gpointer *data)
2867 int main (int argc, char *argv[])
2869 static GtkWidget *window;
2870 GtkWidget *scrolled_window;
2876 gtk_init (&argc, &argv);
2878 /* Crea una nuove finestra di dialogo in cui la scrolled window sarà
2879 inserita. Una finestra di dialogo è semplicemente come una
2880 finestra normale, ma ha anche un vbox e un separatore orizzontale
2881 già inseriti per difetto. E'un modo semplice per
2882 creare finestre di dialogo. */
2883 window = gtk_dialog_new ();
2884 gtk_signal_connect (GTK_OBJECT (window), "destroy",
2885 (GtkSignalFunc) destroy, NULL);
2886 gtk_window_set_title (GTK_WINDOW (window), "dialog");
2887 gtk_container_border_width (GTK_CONTAINER (window), 0);
2889 /* crea una nuova finestra scorribile. */
2890 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
2892 gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
2894 /* la politica è GTK_POLICY AUTOMATIC per lo scorrimento orizzontale e
2895 GTK_POLICY_ALWAYS per quello verticale. */
2896 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
2897 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
2899 /* La finestra di dialogo è creata con un vbox già inserito.*/
2900 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
2902 gtk_widget_show (scrolled_window);
2904 /* crea una tablella di10 x 10. */
2905 table = gtk_table_new (10, 10, FALSE);
2907 /* setta lo spazio tra ogni cella di 10 pixel sia verticale sia orizzontale*/
2908 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
2909 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
2911 /* inserisce la tabella nella finestra scorribile*/
2912 gtk_container_add (GTK_CONTAINER (scrolled_window), table);
2913 gtk_widget_show (table);
2915 /* questo semplicemente crea una griglia di bottoni nella tabelle per
2916 dimostrare il comportamento della finestra scorribile */
2917 for (i = 0; i < 10; i++)
2918 for (j = 0; j < 10; j++) {
2919 sprintf (buffer, "button (%d,%d)\n", i, j);
2920 button = gtk_toggle_button_new_with_label (buffer);
2921 gtk_table_attach_defaults (GTK_TABLE (table), button,
2923 gtk_widget_show (button);
2926 /* Aggiunge un bottone "close" alla fine della finestra */
2927 button = gtk_button_new_with_label ("close");
2928 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2929 (GtkSignalFunc) gtk_widget_destroy,
2930 GTK_OBJECT (window));
2932 /* questo fa sì che questo bottone sia quello predefinito */
2934 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2935 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
2937 /* Questo ottiene il bottone predefinito. Premendo semplicemente l'"enter" il
2938 bottone si avvierà */
2939 gtk_widget_grab_default (button);
2940 gtk_widget_show (button);
2942 gtk_widget_show (window);
2950 Prova a giocare con il ridemensionamento della finestra. Noterete la reazione della
2951 barra di scorrimento. Potete anche usare la funzione gtk_widget_set_usize() per
2952 assegnare la dimensione predefinita della finestra o di un widget.
2953 <!-- (ndMichel: questa chiamata non funziona per i bottoni!) -->
2956 <sect> Il Widgets Lista
2958 Il widget GtkList serve come contenitore verticale per altri widget che
2959 devono essere di tipo GtkListItem.
2961 Un widget GtkList possiede una sua propria finestra per ricevere eventi
2962 e un suo proprio colore di sfondo che di solito è bianco. Dal momento
2963 che è direttamente derivato dal widget GtkContainer, può essere trattato
2964 come tale usando la macro GTK_CONTAINER(List); si veda il widget GtkContainer
2965 per ulteriori dettagli.
2966 Per usare il widget GtkList in tutte le sue potenzialità, si dovrebbe essere
2967 già familiari con l'uso della GList e delle relative funzioni g_list_*().
2969 All'interno della definizione della struttura del widget GtkList c'è un
2970 campo che sarà per noi di grande interesse, cioè:
2977 guint selection_mode;
2982 Il campo ``selection'' in un GtkList punta a una lista collegata di tutti
2983 gli elementi che sono selezionati correntemente, oppure a NULL se la
2984 selezione è vuota. Quindi, per avere informazioni sulla selezione corrente,
2985 leggiamo il campo GTK_LIST()->selection, senza però modificarlo dal momento
2986 che i campi interni debbono essere gestiti dalle funzioni gtk_list_*().
2988 Le modalità di selezione in una GtkList, e quindi il contenuto di
2989 GTK_LIST()->selection, sono determinate dal campo selection_mode:
2991 selection_mode può assumere uno dei seguenti valori:
2993 <item> GTK_SELECTION_SINGLE - La selezione può essere o NULL oppure
2994 un puntatore GList* per un singolo elemento
2997 <item> GTK_SELECTION_BROWSE - La selezione è null se la lista non contiene
2998 alcun widget o se ha solo widget non sensibili,
2999 oppure può contenere un puntatore a una struttura
3000 GList, e quindi esattamente un elemento di lista.
3002 <item> GTK_SELECTION_MULTIPLE - La selezione è ``NULL'' se non è selezionato
3003 alcun elemento di lista, oppure un puntatore GList al
3004 primo elemento selezionato. Quello, a sua volta, punta
3005 a una struttura GList per il secondo elemento selezionato
3008 <item> GTK_SELECTION_EXTENDED - La selezione è sempre NULL.
3011 Il valore per difetto è GTK_SELECTION_MULTIPLE.
3016 void GtkList::selection_changed (GtkList *LIST)
3019 Questo segnale verrà invocato ogni volta che il campo di
3020 selezione di una GtkList è cambiato. Questo accade quando
3021 un figlio della GtkList viene selezionato o deselezionato.
3024 void GtkList::select_child (GtkList *LIST, GtkWidget *CHILD)
3027 Questo segnale viene invocato quando un fuglio di una GtkList
3028 sta per essere selezionato. Questo accade principalmente in
3029 occasione di chiamate a gtk_list_select_item() e gtk_list_select_child(),
3030 di pressioni di bottoni e a volte può venir fatto scattare indirettamente
3031 in altre occasioni, in cui vengono aggiunti o rimossi dei figli
3035 void GtkList::unselect_child (GtkList *LIST, GtkWidget *CHILD)
3038 Questo segnale viene invocato quando un figlio della GtkList sta
3039 per essere deselezionato. Ciò accade principalmente in occasione
3040 di chiamate a gtk_list_unselect_item() e gtk_list_unselect_child(),
3041 di pressioni di bottoni, e a volte può venir fatto scattare indirettamente
3042 in altre occasioni, in cui vengono aggiunti o rimossi dei figli
3048 guint gtk_list_get_type (void)
3051 Restituisce l'identificatore di tipo `GtkList'.
3054 GtkWidget* gtk_list_new (void)
3057 Crea un nuovo oggetto `GtkList'. Il nuovo widget viene
3058 restituito sotto forma di un puntoatore ad un oggetto
3059 `GtkWidgetì'. In caso di fallimento, viene ritornato NULL.
3062 void gtk_list_insert_items (GtkList *LIST, GList *ITEMS, gint POSITION)
3065 Inserisce degli elementi di lista nella LIST, a partire da
3066 POSITION. ITEMS ITEMS è una lista doppiamente collegata, in
3067 cui ci si aspetta che i puntatori di ogni nodo puntino a
3068 un GtkListItem appena creato. I nodi GList di ITEMS vengono
3072 void gtk_list_append_items (GtkList *LIST, GList *ITEMS)
3075 Inserisce elementi di lista proprio come gtk_list_insert_items(),
3076 ma alla fine della LIST. I nodi GList di ITEMS vengono
3080 void gtk_list_prepend_items (GtkList *LIST, GList *ITEMS)
3083 Inserisce elementi di lista proprio come gtk_list_insert_items(),
3084 ma al principio della LIST. I nodi GList di ITEMS vengono
3088 void gtk_list_remove_items (GtkList *LIST, GList *ITEMS)
3091 Rimuove degli elementi di lista dalla LIST. ITEMS è una lista
3092 doppiamente collegata in cui ci si aspetta che i puntatori di
3093 ogni nodo puntino a un figlio diretto di LIST. E' poi responsabilità
3094 del chiamante di fare una chiamata a g_list_free(ITEMS). E' anche
3095 necessario che il chiamante distrugga lui stesso gli elementi della
3099 void gtk_list_clear_items (GtkList *LIST, gint START, gint END)
3102 Rimuove e distrugge elementi di lista da LIST. Un widget ne è
3103 interessato se la sua posizione corrente all'interno di LIST è compreso
3107 void gtk_list_select_item (GtkList *LIST, gint ITEM)
3110 Invoca il segnale GtkList::select_child per un elemento di lista
3111 specificato dalla sua posizione corrente all'interno di LIST.
3114 void gtk_list_unselect_item (GtkList *LIST, gint ITEM)
3117 Invoca il segnale GtkList::unselect_child per un elemento di lista
3118 specificato dalla sua posizione corrente all'interno di LIST.
3121 void gtk_list_select_child (GtkList *LIST, GtkWidget *CHILD)
3124 Invoca il segnale GtkList::select_child per uno specifico CHILD.
3127 void gtk_list_unselect_child (GtkList *LIST, GtkWidget *CHILD)
3130 Invoca il segnale GtkList::unselect_child per uno specifico CHILD.
3133 gint gtk_list_child_position (GtkList *LIST, GtkWidget *CHILD)
3136 Restituisce la posizione di CHILD all'interno di LIST. In caso di fallimento,
3137 viene restituito `-1'.
3140 void gtk_list_set_selection_mode (GtkList *LIST, GtkSelectionMode MODE)
3143 Assegna a LIST il modo di selezione MODE, che può essere uno fra
3144 GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE o
3145 GTK_SELECTION_EXTENDED.
3148 GtkList* GTK_LIST (gpointer OBJ)
3151 Fa il cast di un generico puntatore a `GtkList*'. Per maggiori
3152 informazioni vedere Standard Macros::.
3155 GtkListClass* GTK_LIST_CLASS (gpointer CLASS)
3158 Fa il cast di un generico puntatore a `GtkListClass*'. Per maggiori
3159 informazioni vedere Standard Macros::.
3162 gint GTK_IS_LIST (gpointer OBJ)
3165 Determina se un generico puntatore si riferisce ad un oggetto `GtkList'.
3166 Per maggiori informazioni vedere Standard Macros::.
3171 Diamo di seguito un programma di esempio che stamperà i campbiamenti
3172 della selezione di una GtkList, e vi lascia ``imprigionare'' gli elementi
3173 di una lista selezionandoli con il pulsante destro del mouse:
3176 /* compilate questo programma con:
3177 * $ gcc -I/usr/local/include/ -lgtk -lgdk -lglib -lX11 -lm -Wall main.c
3180 /* includiamo i file header di gtk+
3181 * includiamo stdio.h, ne abbiamo bisogno per printf()
3183 #include <gtk/gtk.h>
3186 /* Questa e' la nostra stringa di identificazione dei dati per assegnarli
3187 * ad elementi di lista
3189 const gchar *list_item_data_key="list_item_data";
3192 /* prototipi per i gestori di segnale che connetteremo
3195 static void sigh_print_selection (GtkWidget *gtklist,
3196 gpointer func_data);
3197 static void sigh_button_event (GtkWidget *gtklist,
3198 GdkEventButton *event,
3202 /* funzione main per predisporre l'interfaccia utente */
3204 gint main (int argc, gchar *argv[])
3206 GtkWidget *separator;
3209 GtkWidget *scrolled_window;
3213 GtkWidget *list_item;
3219 /* inizializza gtk+ (e di conseguenza gdk) */
3221 gtk_init(&argc, &argv);
3224 /* crea una finestra in cui mettere tutti i widget
3225 * connette gtk_main_quit() al segnale "destroy" della finestra
3226 * per gestire le richieste di chiusura finestra del window manager
3228 window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
3229 gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
3230 gtk_signal_connect(GTK_OBJECT(window),
3232 GTK_SIGNAL_FUNC(gtk_main_quit),
3236 /* all'interno della finestra abbiamo bisogno di una scatola
3237 * in cui mettere i widget verticalmente */
3238 vbox=gtk_vbox_new(FALSE, 5);
3239 gtk_container_border_width(GTK_CONTAINER(vbox), 5);
3240 gtk_container_add(GTK_CONTAINER(window), vbox);
3241 gtk_widget_show(vbox);
3243 /* questa è la finestra scorribile in cui mettere il widget GtkList */
3244 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
3245 gtk_widget_set_usize(scrolled_window, 250, 150);
3246 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
3247 gtk_widget_show(scrolled_window);
3249 /* crea il widget GtkList
3250 * connette il gestore di segnale sigh_print_selection()
3251 * al segnale "selection_changed" della GtkList, per stampare
3252 * gli elementi selezionati ogni volta che la selezione cambia
3254 gtklist=gtk_list_new();
3255 gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
3256 gtk_widget_show(gtklist);
3257 gtk_signal_connect(GTK_OBJECT(gtklist),
3258 "selection_changed",
3259 GTK_SIGNAL_FUNC(sigh_print_selection),
3262 /* creiamo una "Prigione" (Prison) in cui mettere gli elementi di lista ;)
3264 frame=gtk_frame_new("Prison");
3265 gtk_widget_set_usize(frame, 200, 50);
3266 gtk_container_border_width(GTK_CONTAINER(frame), 5);
3267 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
3268 gtk_container_add(GTK_CONTAINER(vbox), frame);
3269 gtk_widget_show(frame);
3271 /* connette il gestore di segnale sigh_button_event() alla GtkList
3272 * il quale gestira' l'"imprigionamento" degli elementi di lista
3274 gtk_signal_connect(GTK_OBJECT(gtklist),
3275 "button_release_event",
3276 GTK_SIGNAL_FUNC(sigh_button_event),
3279 /* crea un separatore
3281 separator=gtk_hseparator_new();
3282 gtk_container_add(GTK_CONTAINER(vbox), separator);
3283 gtk_widget_show(separator);
3285 /* infine creiamo un bottone e connettiamone il segnale "clicked"
3286 * alla distruzione della finestra
3288 button=gtk_button_new_with_label("Close");
3289 gtk_container_add(GTK_CONTAINER(vbox), button);
3290 gtk_widget_show(button);
3291 gtk_signal_connect_object(GTK_OBJECT(button),
3293 GTK_SIGNAL_FUNC(gtk_widget_destroy),
3294 GTK_OBJECT(window));
3297 /* a questo punto creiamo 5 elementi di lista, ognuno con la
3298 * propria etichetta, e li aggiungiamo alla GtkList usando
3299 * gtk_container_add(). Inoltre, recuperiamo la stringa di testo
3300 * dall'etichetta e la associamo, per ogni elemento, a
3301 * list_item_data_key
3303 for (i=0; i<5; i++) {
3307 sprintf(buffer, "ListItemContainer with Label #%d", i);
3308 label=gtk_label_new(buffer);
3309 list_item=gtk_list_item_new();
3310 gtk_container_add(GTK_CONTAINER(list_item), label);
3311 gtk_widget_show(label);
3312 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
3313 gtk_widget_show(list_item);
3314 gtk_label_get(GTK_LABEL(label), &string);
3315 gtk_object_set_data(GTK_OBJECT(list_item),
3320 /* qui creiamo altre 5 etichette, questa volta usando
3321 * per la creazione gtk_list_item_new_with_label().
3322 * Non possiamo recuperare la stringa di testo dall'etichetta
3323 * dal momento che non disponiamo di puntatori alle etichette,
3324 * quindi associamo semplicemente il list_item_data_key di ogni
3325 * elemento di lista con la medesima stringa di testo.
3326 * Per aggiungere elementi di lista, li mettiamo tutti in una lista
3327 * doppiamente collegata (GList), e quindi li aggiungiamo con una
3328 * unica chiamata a gtk_list_append_items().
3329 * Dal momento che usiamo g_list_prepend() per mettere gli elementi
3330 * nella lista doppiamente collegata, il loro ordine sara' discendente
3331 * (invece che ascendente come sarebbe se usassimo g_list_append())
3335 sprintf(buffer, "List Item with Label %d", i);
3336 list_item=gtk_list_item_new_with_label(buffer);
3337 dlist=g_list_prepend(dlist, list_item);
3338 gtk_widget_show(list_item);
3339 gtk_object_set_data(GTK_OBJECT(list_item),
3341 "ListItem with integrated Label");
3343 gtk_list_append_items(GTK_LIST(gtklist), dlist);
3345 /* e finalmente vogliamo vedere la finestra, non e' vero? ;)
3347 gtk_widget_show(window);
3349 /* lancia il ciclo principale di gtk
3353 /* si arriva a questo punto dopo la chiamata di gtk_main_quit(),
3354 * il che accade quando viene distrutta la finestra principale
3359 /* questo e' il gestore di segnale che e' stato connesso all'evento di
3360 * pressione/rilascio del bottone della GtkList
3363 sigh_button_event (GtkWidget *gtklist,
3364 GdkEventButton *event,
3367 /* facciamo qualcosa solo nel caso di rilascio del terzo bottone
3368 * (quello piu' a destra)
3370 if (event->type==GDK_BUTTON_RELEASE &&
3372 GList *dlist, *free_list;
3373 GtkWidget *new_prisoner;
3375 /* recuperiamo l'elemento di lista selezionato correntemente,
3376 * che sara' il nostro prossimo prigioniero ;)
3378 dlist=GTK_LIST(gtklist)->selection;
3380 new_prisoner=GTK_WIDGET(dlist->data);
3384 /* cerchiamo elementi di lista gia' imprigionati,
3385 * li rimetteremo nella lista.
3386 * Ricordare di liberare la lista doppiamente collegata
3387 * che viene restituita da gtk_container_children()
3389 dlist=gtk_container_children(GTK_CONTAINER(frame));
3392 GtkWidget *list_item;
3394 list_item=dlist->data;
3396 gtk_widget_reparent(list_item, gtklist);
3400 g_list_free(free_list);
3402 /* se abbiamo un nuovo prigioniero, lo rimuoviamo
3403 * dalla GtkList e lo mettiamo nella cornice della
3404 * "Prigione". Dobbiamo prima deselezionare l'elemento
3409 static_dlist.data=new_prisoner;
3410 static_dlist.next=NULL;
3411 static_dlist.prev=NULL;
3413 gtk_list_unselect_child(GTK_LIST(gtklist),
3415 gtk_widget_reparent(new_prisoner, frame);
3420 /* questo e' il gestore di segnaleche viene chiamato de la
3421 * GtkList emette il segnale "selection_changed"
3424 sigh_print_selection (GtkWidget *gtklist,
3429 /* recuperiamo la lista doppiamente collegata degli
3430 * elementi selezionati della GtkList, ricordate di
3431 * trattarla come sola lettura
3433 dlist=GTK_LIST(gtklist)->selection;
3435 /* se non ci sono elementi selezionati non c'e' altro da
3436 * fare che dirlo all'utente
3439 g_print("Selection cleared\n");
3442 /* ok, abbiamo una selezione e quindi lo scriviamo
3444 g_print("The selection is a ");
3446 /* ottieniamo l'elemento di lista dalla lista doppiamente
3447 * collegata e poi richiediamo i dati associati con
3448 * list_item_data_key. Poi semplicemente li stampiamo
3451 GtkObject *list_item;
3452 gchar *item_data_string;
3454 list_item=GTK_OBJECT(dlist->data);
3455 item_data_string=gtk_object_get_data(list_item,
3456 list_item_data_key);
3457 g_print("%s ", item_data_string);
3465 <sect1> Il Widget Elemento di Lista (List Item)
3467 Il widget GtkListItem è progettato allo scopo di essere un contenitore
3468 collegato ad un figlio, per fornire le funzioni per la selezione e deselezione
3469 allo stesso modo in cui il widget GtkList ne ha bisogno per i propri figli.
3471 Un GtkListItem ha la sua propria finestra per ricevere eventi, e ha il suo
3472 proprio colore di sfondo, che di solito è bianco.
3474 Dal momento che questo widget deriva direttamente da GtkItem, può essere
3475 trattato come tale usando la macro GTK_ITEM(ListItem), vedere il widget
3476 GtkItem per ulteriori informazioni.
3477 Di solito un GtkListItem ha solo un'etichetta per identificare per esempio
3478 un nome di file all'interno di una GtkList -- per cui viene fornita la
3479 funzione appropriata gtk_list_item_new_with_label(). Si può ottenere lo
3480 stesso effetto creando una GtkLabel da sola, assegnando al suo allineamento
3481 i valori xalign=0 e yalign=0.5, aggiungendo successivamente un contenitore
3484 Dal momento che non si è obbligati a mettere una GtkLabel, si può anche
3485 aggiungere una GtkVBox una GtkArrow ecc. alla GtkListItem.
3489 Un GtkListItem non crea alcun nuovo segnale di per se, ma eredita
3490 i segnali di GtkItem. Per ulteriori informazioni, vedere GtkItem::.
3497 guint gtk_list_item_get_type (void)
3500 Restituisce l'identificatore di tipo `GtkListItem'.
3503 GtkWidget* gtk_list_item_new (void)
3506 Crea un nuovo oggetto `GtkListItem'. Il nuovo widget viene restituito
3507 sottoforma di un puntatore ad un oggetto `GtkWidget'. In caso di
3508 fallimento, viene restituito `NULL'.
3511 GtkWidget* gtk_list_item_new_with_label (gchar *LABEL)
3514 Cre un nuovo oggetto `GtkListItem', avente come unico figlio
3515 un GtkLabel. Il nuovo widget viene restituito
3516 sottoforma di un puntatore ad un oggetto `GtkWidget'. In caso di
3517 fallimento, viene restituito `NULL'.
3520 void gtk_list_item_select (GtkListItem *LIST_ITEM)
3523 Questa funzione è essenzialmente un wrapper per una chiamata a
3524 gtk_item_select (GTK_ITEM (list_item)) che emetterà il segnale
3526 Vedere GtkItem:: per maggiori informazioni.
3529 void gtk_list_item_deselect (GtkListItem *LIST_ITEM)
3532 Questa funzione è essenzialmente un wrapper per una chiamata a
3533 gtk_item_deselect (GTK_ITEM (list_item)) che emetterà il segnale
3535 Vedere GtkItem:: per maggiori informazioni.
3538 GtkListItem* GTK_LIST_ITEM (gpointer OBJ)
3541 Effettua il cast di un puntatore generico a `GtkListItem*'. Vedere
3542 Standard Macros:: per maggiorni informazioni.
3545 GtkListItemClass* GTK_LIST_ITEM_CLASS (gpointer CLASS)
3548 Effettua il cast di un puntatore generico a `GtkListItemClass*'. Vedere
3549 Standard Macros:: per maggiorni informazioni.
3552 gint GTK_IS_LIST_ITEM (gpointer OBJ)
3555 Determina se un puntatore generico si riferisce ad un oggetto
3556 `GtkListItem'. Vedere Standard Macros:: per maggiorni informazioni.
3560 Come esempio su questo argomento, si veda quello relativo alla GtkList,
3561 che riguarda anche l'uso del GtkListItem.
3563 <sect> Selezione di File (File Selections)
3566 Il widget Selezione di File è un modo rapido e semplice per mostrare una
3567 finestra di dialogo `File'. Questa si presenta completa di bottoni Ok,
3568 Cancel e Help, un buon modo per tagliare i tempi di programmazione.
3570 Per creare una nuova finestra di selezione file usate:
3573 GtkWidget* gtk_file_selection_new (gchar *title);
3576 Per assegnare il nome del file, ad esempio per predisporre una certa
3577 directory o per dare un certo nome di file per difetto, usate la seguente
3581 void gtk_file_selection_set_filename (GtkFileSelection *filesel, gchar *filename);
3584 Per recuperare il testo che l'utente ha inserito o che ha selezionato con
3585 il mouse, si usa la funzione:
3588 gchar* gtk_file_selection_get_filename (GtkFileSelection *filesel);
3591 Ci sono anche dei puntatori ai widget che sono contenuti all'interno
3592 del widget di selezione file. Si tratta di:
3597 <item>selection_entry
3598 <item>selection_text
3605 Molto probabilmente potreste voler usare i puntatori a ok_button,
3606 cancel_button e help_button per segnalarne l'uso.
3608 Ecco un esempio rubato da testgtk.c, nodificato per essere eseguito da
3609 solo. Come potrete vedere, non c'è molto più che la creazione di un
3610 widget di selezione file. In questo esempio, il bottone Help non fa nulla
3611 mentre è mostrato allo schermo, dal momento che non c'è alcun segnale
3615 #include <gtk/gtk.h>
3617 /* Recupera il nome di file selezionato e stampalo a console */
3618 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
3620 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
3623 void destroy (GtkWidget *widget, gpointer *data)
3628 int main (int argc, char *argv[])
3632 gtk_init (&argc, &argv);
3634 /* Crea un nuovo widget di selezione file */
3635 filew = gtk_file_selection_new ("File selection");
3637 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
3638 (GtkSignalFunc) destroy, &filew);
3639 /* Connette ok_button alla funzione file_ok_sel */
3640 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
3641 "clicked", (GtkSignalFunc) file_ok_sel, filew );
3643 /* Connette cancel_button alla funzione di distruzione del widget */
3644 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
3645 "clicked", (GtkSignalFunc) gtk_widget_destroy,
3646 GTK_OBJECT (filew));
3648 /* Preassegnamo un nome di file, come se stessimo dando un valore per difetto in
3649 dialogo di tipo `` salva con nome '' */
3650 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
3653 gtk_widget_show(filew);
3659 <sect>Il Widget Menù (Menu Widgets)
3661 Ci sono due modi per creare dei menù, quello facile e quello difficile.
3662 Ognuno è più adatto per certe circostanze, ma di solito si può usare il
3663 modo semplice, cioé menu_factory (la ``fabbrica dei menù''). Il modo
3664 ``difficile'' è di crearsi tutti i menù usando direttamente le chiamate.
3665 Quello semplice è di usare le chiamate di tipo gtk_menu_factory. Anche se
3666 è un modo molto più semplice, ci sono svantaggi e vantaggi per ciascuno
3669 La menufactory è molto più semplice da usare e per aggiungere dei nuovi
3670 menù, anche se scriversi un po' di funzioni per creare dei menù con il
3671 metodo manuale può dare risultati molto migliori dal punto di vista
3672 dell'usabilità. Con la menufactory, non è possibile mettere immagini o
3673 segni '/' nei menù.
3675 <sect1>Creazione Manuale di Menù
3677 Seguendo la tradizionale arte dell'insegnamento, partiamo dal modo
3678 difficile. <tt>:)</>
3680 Diamo un'occhiata alle funzioni usate per creare dei menù.
3681 Con questa prima funzione si crea un nuovo menù:
3684 GtkWidget *gtk_menu_bar_new()
3687 Questa funzione crea una nuova barra di menù. Per impacchettarla in una
3688 finestra o si usa la funzione gtk_container_add, oppure, per impacchettarla
3689 in una scatola, le funzioni box_pack - come con i bottoni.
3692 GtkWidget *gtk_menu_new();
3695 Questa funzione restituisce un puntatore ad un nuovo menù, non viene mai
3696 realmente mostrato (con gtk_widget_show), serve solo per contenere gli
3697 elementi del menù. Spero che il tutto risulti più chiaro quando dare
3698 un'occhiata all'esempio più sotto.
3700 Le prossime due chiamate sono usate per creare degli elementi che poi
3701 vengono impacchettati nel menù.
3704 GtkWidget *gtk_menu_item_new()
3710 GtkWidget *gtk_menu_item_new_with_label(const char *label)
3713 Queste chiamate sono usate per creare i menu che devono essere mostrati.
3714 Ricordate la differenza che esiste fra un ``menù'' come quelli creati con
3715 gtk_menu_new e un ``elemento di menù'' (menu item) come quelli creati con
3716 la funzione creata con gtk_menu_item_new. L'elemento di menù sarà un bottone
3717 vero e proprio con una azione associata, mentre un menù è solo un contenitore
3721 gtk_menu_item_append()
3723 gtk_menu_item_set_submenu()
3726 Le funzioni gtk_menu_item_new_with_label e gtk_menu_item_new si comportano esattamente come
3727 vi aspettereste dopo aver visto le funzioni che riguardano i bottoni. La prima
3728 crea un elemento di menù con un'etichetta già applicata, mentre la seconda crea
3729 un nuovo elemento di menù vuoto.
3731 Ecco i passi necessari per creare una barra di menù con i relativi menù collegati:
3733 <item> Create un nuovo menù con gtk_menu_new()
3734 <item> Create un elementoa di menù con using gtk_menu_item_new(). Questo rappresenta
3735 la base del menù, e il testo che appare qui sarà sulla barra stessa.
3736 <item> Usate delle chiamate multiple a gtk_menu_item_new() per ognuno degli
3737 elementi che volete mettere nel vostro menù. Usate inoltre gtk_menu_item_append()
3738 per mettere assieme ognuno di questi nuovo elementi. Si crea così una lista di
3739 elementi di menù.
3740 <item> Usate gtk_menu_item_set_submenu() per attaccare gli elementi di menù
3741 creati all'elemento di menù base (quello creato nel secondo passaggio).
3742 <item> Create una nuova barra di menù usando gtk_menu_bar_new. Questo passo
3743 necessita di essere effettuato una sola volta quando si crea una serie di
3744 menù su una serie di menù su una sola barra.
3745 <item> Usate gtk_menu_bar_append per mettere il menù base sulla barra dei menù.
3748 Creare un menù a comparsa è più o meno la stessa cosa. La differenza è che il
3749 il menù non viene attivato ``automaticamente'' da una barra, bensì esplicitamente
3750 con la chiamata alla funzione gtk_menu_popup() da un evento di pressione di
3752 Seguite questi passaggi:
3754 <item>Create una funzione di gestione di un evento. Essa deve seguire il prototipo
3756 static gint handler(GtkWidget *widget, GdkEvent *event);
3758 e usare l'evento per scoprire dove il menu deve essere fatto comparire.
3759 <item>Nel gestore di evento, se questo è la pressione di un bottone, trattate
3760 <tt>event</tt> come l'evento relativo ad un bottone (cosa che in effetti è)
3761 e usatelo come mostrato nel codice di esempio per passare informazioni a
3763 <item>Collegate il gestore di evento a un widget con
3765 gtk_signal_connect_object(GTK_OBJECT(widget), "event",
3766 GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
3768 in cui <tt>widget</tt> è il widget a cui state effettuando il collegamento, e
3769 <tt>handler</tt> è la funzione di gestione, mentre <tt>menu</tt> è un menù
3770 creato con gtk_menu_new(). Quest'ultimo può essere un menù che viene anche
3771 attivato da una barra di menù, come mostrato nel codice di esempio.
3774 <sect1>Esempio di Menù Manuale
3776 Per la teoria dovrebbe essere abbastanza. Diamo un'occhiata ad un esempio che
3777 ci aiuti a chiarire le cose.
3781 #include <gtk/gtk.h>
3783 static gint button_press (GtkWidget *, GdkEvent *);
3784 static void menuitem_response (gchar *);
3787 int main (int argc, char *argv[])
3792 GtkWidget *menu_bar;
3793 GtkWidget *root_menu;
3794 GtkWidget *menu_items;
3800 gtk_init (&argc, &argv);
3802 /* crea una nuova finestra */
3803 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
3804 gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
3805 gtk_signal_connect(GTK_OBJECT (window), "delete_event",
3806 (GtkSignalFunc) gtk_exit, NULL);
3808 /* Inizializziamo il menù, e ricordate: mai applicare
3809 * gtk_show_widget() al widget menù!!
3810 * Questo è il menù che contiene gli elementi, quello che
3811 * spunta quando si fa click sul "Menù radice" nell'applicazione */
3812 menu = gtk_menu_new();
3814 /* Questo è il menù radice, e l'etichetta sarà il nome del menù che
3815 * verrà mostrato sulla barra dei menù. Non ci sarà alcun gestore di
3816 * segnale collegato, dal momento che non fa altro che mostrare il resto
3817 * del menù quando viene premuto. */
3818 root_menu = gtk_menu_item_new_with_label("Root Menu");
3820 gtk_widget_show(root_menu);
3822 /* Ora creiamo un ciclo che crea tre elementi di menu per "test-menu".
3823 * Notete la chiamata a gtk_menu_append. In questo punto aggiungiamo una
3824 * lista di elementi al nostro menù. Normalmente, dovremmo poi catturare
3825 * il segnale di attivazione per ognuno degli elementi del menu, e creare
3826 * una funzione di ritorno per ciascuno di essi, ma qui non li mettiamo per
3827 * brevità. */
3829 for(i = 0; i < 3; i++)
3831 /* Copia i nomi in buf. */
3832 sprintf(buf, "Test-undermenu - %d", i);
3834 /* Crea un nuovo elemento di menù con un nome... */
3835 menu_items = gtk_menu_item_new_with_label(buf);
3837 /* ...e aggiungilo al menù. */
3838 gtk_menu_append(GTK_MENU (menu), menu_items);
3840 /* Fa qualcosa di interessante quando si seleziona l'elemento */
3841 gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
3842 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
3844 /* Mostra il widget */
3845 gtk_widget_show(menu_items);
3848 /* Ora specifichiamo che vogliamo che il menù che abbiamo appena creato
3849 * sia il menù radice *//
3850 gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
3852 /* Una vbox in cui mettere un menù ed un bottone: */
3853 vbox = gtk_vbox_new(FALSE, 0);
3854 gtk_container_add(GTK_CONTAINER(window), vbox);
3855 gtk_widget_show(vbox);
3857 /* Crea una barra dei menù per metterci i menù e l'aggiunge alla finestra principale */
3858 menu_bar = gtk_menu_bar_new();
3859 gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
3860 gtk_widget_show(menu_bar);
3862 /* Crea un bottone a cui collegare un menù */
3863 button = gtk_button_new_with_label("press me");
3864 gtk_signal_connect_object(GTK_OBJECT(button), "event",
3865 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
3866 gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
3867 gtk_widget_show(button);
3869 /* E finalmente attacchiamo l'elemento di menù alla barra dei menù -- questo
3870 * è l'elemento di menù "radice" di cui parlavo */
3871 gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
3873 /* La finestra va mostrata sempre come ultimo passo in modo che sia già
3874 * completa di tutti i suoi elementi. */
3875 gtk_widget_show(window);
3884 /* Risponde alla pressione di un bottone impostando un menù che
3885 * viene passato come widget.
3886 * Notate che l'argomento "widget" si riferisce al menù impostato
3887 * e NON al bottone premuto.
3890 static gint button_press (GtkWidget *widget, GdkEvent *event)
3893 if (event->type == GDK_BUTTON_PRESS) {
3894 GdkEventButton *bevent = (GdkEventButton *) event;
3895 gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
3896 bevent->button, bevent->time);
3897 /* Riferisce al codice chiamante che abbiamo trattato l'evento;
3898 * la faccenda finisce qui. */
3902 /* Riferisce al codice chiamante che abbiamo trattato l'evento; passa avanti. */
3907 /* Stampa una stringa quando viene selezionato un elemento di menù */
3909 static void menuitem_response (gchar *string)
3911 printf("%s\n", string);
3915 Si può anche fare in modo che un elemento di menù sia insensibile e, usando
3916 una tabella di acelleratori, collegare dei tasti a delle funzioni di menù.
3918 <sect1>Usare GtkMenuFactory
3920 Ora che vi abbiamo mostrato il modo difficile, ecco invece come si fa usando
3921 le chiamate di gtk_menu_factory.
3923 <sect1>Esempio di Menu Factory
3925 Ecco un esempio di utilizzo della ``Fabbrica'' di Menù di GTK (Menu Factory).
3926 Questo è il primo file, menus.h. Teniemo dei file menus.c e main.c separati
3927 a causa delle variabili globali usate nel file menus.c.
3935 #endif /* __cplusplus */
3937 void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
3938 void menus_create(GtkMenuEntry *entries, int nmenu_entries);
3942 #endif /* __cplusplus */
3944 #endif /* __MENUS_H__ */
3947 Ed ecco il file menus.c.
3951 #include <gtk/gtk.h>
3952 #include <strings.h>
3957 static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
3958 static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
3959 void menus_init(void);
3960 void menus_create(GtkMenuEntry * entries, int nmenu_entries);
3962 /* Questa è la struttuta GtkMenuEntry, che viene usata per creare dei nuovi
3963 * menù. Il primo membro à la stringa di definizione del menù. Il secondo
3964 * è il tasto acceleratore predefinito, usato per accedere a questa funzione
3965 * con la tastiera. Il terzo è la funzione di ritorno che viene chiamata
3966 * quando si seleziona con la tastiera o il mouse questo elemento di menù.
3967 * L'ultimo membro costituisce il dato che viene passato alla funzione di
3970 static GtkMenuEntry menu_items[] =
3972 {"<Main>/File/New", "<control>N", NULL, NULL},
3973 {"<Main>/File/Open", "<control>O", NULL, NULL},
3974 {"<Main>/File/Save", "<control>S", NULL, NULL},
3975 {"<Main>/File/Save as", NULL, NULL, NULL},
3976 {"<Main>/File/<separator>", NULL, NULL, NULL},
3977 {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
3978 {"<Main>/Options/Test", NULL, NULL, NULL}
3981 /* calculail numero di menu_item */
3982 static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
3984 static int initialize = TRUE;
3985 static GtkMenuFactory *factory = NULL;
3986 static GtkMenuFactory *subfactory[1];
3987 static GHashTable *entry_ht = NULL;
3989 void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
3995 *menubar = subfactory[0]->widget;
3997 *table = subfactory[0]->table;
4000 void menus_init(void)
4005 factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
4006 subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
4008 gtk_menu_factory_add_subfactory(factory, subfactory[0], "<Main>");
4009 menus_create(menu_items, nmenu_items);
4013 void menus_create(GtkMenuEntry * entries, int nmenu_entries)
4022 for (i = 0; i < nmenu_entries; i++) {
4023 accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
4025 if (accelerator[0] == '\0')
4026 entries[i].accelerator = NULL;
4028 entries[i].accelerator = accelerator;
4031 gtk_menu_factory_add_entries(factory, entries, nmenu_entries);
4033 for (i = 0; i < nmenu_entries; i++)
4034 if (entries[i].widget) {
4035 gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator",
4036 (GtkSignalFunc) menus_install_accel,
4038 gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator",
4039 (GtkSignalFunc) menus_remove_accel,
4044 static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
4050 if (modifiers & GDK_CONTROL_MASK)
4051 strcat(accel, "<control>");
4052 if (modifiers & GDK_SHIFT_MASK)
4053 strcat(accel, "<shift>");
4054 if (modifiers & GDK_MOD1_MASK)
4055 strcat(accel, "<alt>");
4062 t1 = g_hash_table_lookup(entry_ht, path);
4065 entry_ht = g_hash_table_new(g_string_hash, g_string_equal);
4067 g_hash_table_insert(entry_ht, path, g_strdup(accel));
4072 static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
4077 t = g_hash_table_lookup(entry_ht, path);
4080 g_hash_table_insert(entry_ht, path, g_strdup(""));
4084 void menus_set_sensitive(char *path, int sensitive)
4086 GtkMenuPath *menu_path;
4091 menu_path = gtk_menu_factory_find(factory, path);
4093 gtk_widget_set_sensitive(menu_path->widget, sensitive);
4095 g_warning("Impossibile assegnare sensibilità a menù inesistente: %s", path);
4109 #endif /* __cplusplus */
4111 void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
4115 #endif /* __cplusplus */
4117 #endif /* __MAIN_H__ */
4124 #include <gtk/gtk.h>
4130 int main(int argc, char *argv[])
4133 GtkWidget *main_vbox;
4136 GtkAcceleratorTable *accel;
4138 gtk_init(&argc, &argv);
4140 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4141 gtk_signal_connect(GTK_OBJECT(window), "destroy",
4142 GTK_SIGNAL_FUNC(file_quit_cmd_callback),
4144 gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
4145 gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
4147 main_vbox = gtk_vbox_new(FALSE, 1);
4148 gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
4149 gtk_container_add(GTK_CONTAINER(window), main_vbox);
4150 gtk_widget_show(main_vbox);
4152 get_main_menu(&menubar, &accel);
4153 gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
4154 gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
4155 gtk_widget_show(menubar);
4157 gtk_widget_show(window);
4163 /* Questo è per mostrare come si usano le funzioni di ritorno quando
4164 * si utilizza la MenuFactory. Spesso, si mettono tutte le funzioni di
4165 * callback in un file separato, e le si fanno chiamare le funzioni
4166 * appropriate da lì. Così le cose sono più organizzate. */
4167 void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
4169 g_print ("%s\n", (char *) data);
4174 Ed infine un bel makefile per semplificare la compilazione.
4179 C_FLAGS = -Wall $(PROF) -L/usr/local/include -DDEBUG
4180 L_FLAGS = $(PROF) -L/usr/X11R6/lib -L/usr/local/lib
4181 L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
4184 O_FILES = menus.o main.o
4186 $(PROGNAME): $(O_FILES)
4188 $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
4191 $(CC) -c $(C_FLAGS) $<
4194 rm -f core *.o $(PROGNAME) nohup.out
4199 Per il momento, accontentatevi di questo esempio. Più avanti aggiungeremo
4200 una spiegazione ed un bel po' di commenti.
4203 <sect> Widget non documentati
4205 Per questi sarebbe utile il contributo degli autori! :) Prendete in
4206 considerazione la possibilità di contribuire al nostro tutorial.
4208 Se dovete usare uno di questi widget non documentati, vi suggeriamo
4209 caldamente di dare un'occhiata ai loro rispettivi file header nella
4210 distribuzione di GTK. I nomi delle funzioni di GTK sono molto descrittivi.
4211 Non appena si capisce come funzionano le cose, non è
4212 difficile dedurre il modo d'uso di un widget semplicemente guardando la
4213 dichiarazione di funzione ad esso associata. Aggiungendo a questo qualche
4214 spunto tratto dal codice di altri non dovrebbero esserci problemi.
4216 Quando avrete raggiunto una comprensione globale di tutte le funzioni
4217 di un widget non documentato, considerate la possibilità di scrivere
4218 un tutorial su di esso, in modo che altri possano beneficiare del
4221 <sect1> Ingressi di testo (Text Entries)
4224 <sect1> Selezioni di colore (Color Selections)
4227 <sect1> Controlli di intervallo (Range Controls)
4230 <sect1> Righelli (Rulers)
4233 <sect1> Caselle di testo (Text Boxes)
4239 (Potrebbe essere necessario riscrivere questa parte per conformarsi allo stile
4240 del resto del tutorial)
4243 Le anteprime servono a un certo numero di cose in GIMP/GTK. La più
4244 importante è questa: a risoluzioni molto alte le immagini possono
4245 facilmente occupare diverse decine di megabyte di memoria; ogni operazione
4246 su immagini così grosse può richiedere molto tempo. Se per la
4247 scelta di una data modifica vi occorrono 5-10 tentativi (cioè 10-20
4248 passi, poiché è necessario ripristinare l'originale se si
4249 è commesso un errore), possono volerci letteralmente delle ore per
4250 fare quella giusta - se non si rimane a corto di memoria prima! Coloro che
4251 hanno passato ore in camera oscura conoscono la sensazione. In questi casi
4252 le anteprime sono utilissime!
4254 Ma la seccatura dell'attesa non è l'unico caso. Spesso è utile
4255 confrontare la versione precedente con la successiva affiancandole, o almeno
4256 alternandole. Se si sta lavorando con grandi immagini e ritardi di una decina
4257 di secondi un confronto efficace è quantomeno difficile da fare.
4258 Per immagini di 30 mega (4 pollici per 6 pollici, 600 punti per pollice, 24 bit)
4259 tale confronto risulta impraticabile per la maggior parte degli utenti. In
4260 questo caso le anteprime sono di grande aiuto!
4262 Ma c'è di più. Con le anteprime è possibile scrivere
4263 plug-in per ottenere addirittura anteprime di anteprime (per esempio, la
4264 simulazione del pacchetto di filtri). Questi plug-in possono così
4265 fornire un certo numero di anticipazioni di quel che si otterrebbe applicando
4266 certe opzioni. Un simile approccio funziona come una tavolozza di anteprime,
4267 ed è molto efficace per piccoli cambiamenti!
4269 Non è finita. Per alcuni plug-in può essere necessario un
4270 intervento umano in tempo reale specifico per ogni immagine. Nel plug-in
4271 SuperNova, ad esempio, vengono chieste le coordinate del centro della
4272 futura supernova. Il modo più semplice per fare questo è
4273 senza dubbio quello di mostrare un'anteprima all'utente chiedendogli di
4274 selezionare interattivamente il centro.
4276 Infine, un paio di applicazioni tipiche. Le anteprime possono essere usate
4277 anche quando non si sta lavorando con grandi immagini. Per esempio, sono
4278 utili quando si stanno calcolando dei pattern complicati (date un'occhiata
4279 al venerabile plug in ``Diffraction'' e a molti altri!). Altro esempio:
4280 date un'occhiata al plug-in di rotazione della mappa dei colori (in allestimento).
4281 Le anteprime possono anche essere usate per visualizzare in un plug-in
4282 piccoli logo o, addirittura, l'immagine dell'Autore!
4284 Quando non usare le anteprime
4286 Le anteprime non vanno usate per grafici, disegni ecc., poiché per
4287 queste cose GDK è molto più veloce. Le anteprime vanno usate
4288 solo per immagini derivate da un'elaborazione!
4290 Le anteprime possono essere inserite dappertutto. In un vbox, in un hbox,
4291 in una tabella, in un bottone, ecc. Sicuramente però hanno il loro
4292 look migliore se bordate con delle cornici (frame). Le anteprime non hanno
4293 bordi propri e appaiono piatte senza (naturalmente, se quel che si vuole
4294 è proprio un aspetto piatto...). I bordi possono essere creati con
4299 Le anteprime sono per molti aspetti simili agli altri widget in GTK (con
4300 tutto ciò che questo implica), con l'eccezione di avere una
4301 caratteristica in più: è necessario che siano riempite con
4302 qualche tipo di immagine! Inizialmente parleremo solo dell'aspetto GTK
4303 delle anteprime e successivamente discuteremo di come riempirle.
4308 /* Crea un widget di anteprima,
4309 inizializzane le dimensioni
4312 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
4313 /* Alternativamente:
4314 GTK_PREVIEW_GRAYSCALE);*/
4315 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
4316 gtk_widget_show(preview);
4317 my_preview_rendering_function(preview);
4320 Come già detto, le anteprime hanno un buon aspetto dentro le cornici,
4324 GtkWidget *create_a_preview(int Width,
4331 frame = gtk_frame_new(NULL);
4332 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
4333 gtk_container_border_width (GTK_CONTAINER(frame),0);
4334 gtk_widget_show(frame);
4336 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
4337 :GTK_PREVIEW_GRAYSCALE);
4338 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
4339 gtk_container_add(GTK_CONTAINER(frame),preview);
4340 gtk_widget_show(preview);
4342 my_preview_rendering_function(preview);
4348 Questa è una semplice anteprima. Questa funzione restituisce la cornice
4349 ``madre'', in modo che sia possibile metterla in qualche altro posto nella vostra
4350 interfaccia. Naturalmente è possibile passare alla routine la cornice
4351 madre come parametro. In molte situazioni, comunque, il contenuto di un'anteprima
4352 viene aggiornato continuamente dall'applicazione; in questi casi potreste
4353 preferire passare alla funzione ``create_a_preview()'' un puntatore
4354 all'anteprima, ottenendone così il controllo dopo.
4356 Un'avvertimento più importante che potrebbe un giorno risparmiarvi
4357 tanto tempo perso: a volte è preferibile etichettare le anteprime;
4358 ad esempio, è possibile etichettare l'anteprima contenente l'immagine
4359 originale come ``Originale'' e quella contenente l'immagine modificata come
4360 ``Modificata''. Potrebbe capitarvi di impacchettare in un vbox l'anteprima
4361 insieme con l'etichetta associata. L'insidia inattesa sta nel fatto che se
4362 l'etichetta è più ampia dell'anteprima (cosa che può
4363 accadere per una varietà di motivi da voi non prevedibili, come il
4364 fatto che la dimensione dell'anteprima viene decisa dinamicamente, o la
4365 dimensione del font), la cornice si espande e non risulta più
4366 perfettamente aderente all'anteprima. Questo stesso problema probabilmente
4367 può verificarsi anche in altre situazioni.
4371 La soluzione è quella di mettere l'anteprima e l'etichetta in una
4372 tabella 2x1 e di legarle insieme chiamando la funzione gtk_table_attach con
4373 i seguenti parametri (questa è una delle varianti possibili,
4374 naturalmente; l'importante è che non ci sia GTK_FILL nella seconda
4378 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
4380 GTK_EXPAND|GTK_FILL,
4382 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
4388 Ed ecco il risultato:
4394 La maniera più semplice per rendere cliccabile un'anteprima è
4395 quella di metterla dentro un bottone. Questo ha anche l'effetto di aggiungere
4396 un bel bordo attorno all'anteprima, il che rende superfluo metterla in una
4399 Questo è tutto per quel che riguarda GTK.
4402 Completare un'anteprima
4404 Per impratichirci con le basi del completamento delle anteprime, creiamo
4405 il seguente disegno (trovato per tentativi):
4411 my_preview_rendering_function(GtkWidget *preview)
4414 #define HALF (SIZE/2)
4416 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
4417 gint i, j; /* Coordinates */
4418 double r, alpha, x, y;
4420 if (preview==NULL) return; /* Di solito aggiungo questo per */
4421 /* evitare piantamenti stupidi. */
4422 /* Probabilmente bisognerebbe */
4423 /* assicurarsi che tutto sia stato*/
4424 /* inizializzato con successo */
4425 for (j=0; j < ABS(cos(2*alpha)) ) { /* Siamo dentro la sagoma? */
4426 /* glib.h contiene ABS(x). */
4427 row[i*3+0] = sqrt(1-r)*255; /* Definisce il Rosso */
4428 row[i*3+1] = 128; /* Definisce il Verde */
4429 row[i*3+2] = 224; /* Definisce il Blu */
4430 } /* "+0" è per allineamento */
4433 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
4434 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
4437 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
4438 /* Inserisce "row" in "preview" a partire del punto avente */
4439 /* coordinate (0,j) prima colonna, j-esima riga, per SIZE */
4440 /* pixel verso destra */
4443 free(row); /* libera un po' di memoria */
4444 gtk_widget_draw(preview,NULL); /* indovina cosa fa questo? */
4445 gdk_flush(); /* e questo? */
4448 Coloro che non usano GIMP probabilmente hanno già visto abbastanza
4449 per fare molte cose. Per gli utenti GIMP c'è ancora qualcosa da
4452 Anteprima dell'immagine
4454 Probabilmente è opportuno tenere pronta una versione ridotta dell'immagine,
4455 grande quanto basta per riempire l'anteprima. Questo può essere fatto
4456 selezionando un pixel ogni n, dove n è il rapporto tra la dimensione
4457 dell'immagine e la dimensione dell'anteprima. Tutte le operazioni successive
4458 (compreso il riempimento dell'anteprima) sono fatte solo sul ridotto numero
4459 di pixel selezionati. Di seguito è riportata un'implementazione della
4460 riduzione dell'immagine (si tenga presente che ho preso solo lezioni basilari
4464 (ATTENZIONE: CODICE NON VERIFICATO!!!)
4478 SELCTION_IN_CONTEXT,
4482 ReducedImage *Reduce_The_Image(GDrawable *drawable,
4487 /* Questa funzione riduce l'immagine alla dimens. scelta per l'anteprima */
4488 /* La dimensione dell'anteprima è determinata da LongerSize, cioè la più */
4489 /* grande delle dimensioni. Funziona solo per immagini RGB! */
4490 gint RH, RW; /* Altezza ridotta e larghezza ridotta */
4491 gint width, height; /* Larghezza e altezza dell'area da ridurre */
4492 gint bytes=drawable->bpp;
4493 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
4495 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
4496 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
4497 GPixelRgn srcPR, srcMask;
4498 gint NoSelectionMade=TRUE; /* Assumiamo di trattare l'intera immagine */
4500 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
4503 /* Se c'è una SELEZIONE, ne abbiamo avuto gli estremi! */
4505 if (width != drawable->width && height != drawable->height)
4506 NoSelectionMade=FALSE;
4507 /* Controlliamo se l'utente ha una selezione attiva. Questo */
4508 /* diventerà importante dopo, alla creazione di una maschera ridotta */
4510 /* Se si vuole l'anteprima dell'immagine intera, annulla quanto sopra */
4511 /* Naturalmente, in assenza di una selezione, questo non cambia nulla */
4512 if (Selection==ENTIRE_IMAGE) {
4516 y2=drawable->height;
4519 /* Se si vuole l'anteprima di una selezione con parte dell'area */
4520 /* circostante bisogna espanderla un po'. */
4521 if (Selection==SELECTION_IN_CONTEXT) {
4522 x1=MAX(0, x1-width/2.0);
4523 x2=MIN(drawable->width, x2+width/2.0);
4524 y1=MAX(0, y1-height/2.0);
4525 y2=MIN(drawable->height, y2+height/2.0);
4528 /* Così si determinano larghezza e altezza dell'area da ridurre. */
4532 /* Le linee seguenti determinano quale dimensione deve essere il */
4533 /* lato più lungo. L'idea è presa dal plug-in supernova. Ritengo */
4534 /* che avrei potuto pensarci da solo, ma la verità va detta. */
4535 /* Brutta cosa il plagio! */
4538 RH=(float) height * (float) LongerSize/ (float) width;
4542 RW=(float)width * (float) LongerSize/ (float) height;
4545 /* L'intera immagine viene "stirata" in una stringa! */
4546 tempRGB = (guchar *) malloc(RW*RH*bytes);
4547 tempmask = (guchar *) malloc(RW*RH);
4549 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
4550 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height, FALSE, FALSE);
4552 /* Prendine abbastanza da contenere una riga di immagine e una di maschera */
4553 src_row = (guchar *) malloc (width*bytes);
4554 src_mask_row = (guchar *) malloc (width);
4556 for (i=0; i < RH; i++) {
4557 whichrow=(float)i*(float)height/(float)RH;
4558 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
4559 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
4561 for (j=0; j < RW; j++) {
4562 whichcol=(float)j*(float)width/(float)RW;
4564 /* Nessuna selezione = tutti i punti sono completamente selezionati */
4565 if (NoSelectionMade)
4566 tempmask[i*RW+j]=255;
4568 tempmask[i*RW+j]=src_mask_row[whichcol];
4570 /* Aggiungi la riga alla lunga stringa che ora contiene l'immagine */
4571 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
4572 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
4573 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
4575 /* Mantieni anche la trasparenza (alpha) */
4577 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
4584 temp->mask=tempmask;
4590 La seguente è una funzione di anteprima che usa lo stesso tipo
4591 ReducedImage! Si noti che usa una finta trasparenza - se ne è presente
4592 una, tramite fake_transparency che è definita come segue:
4595 gint fake_transparency(gint i, gint j)
4597 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
4604 E adesso la funzione per l'anteprima:
4607 my_preview_render_function(GtkWidget *preview,
4611 gint Inten, bytes=drawable->bpp;
4614 gint RW=reduced->width;
4615 gint RH=reduced->height;
4616 guchar *row=malloc(bytes*RW);;
4619 for (i=0; i < RH; i++) {
4620 for (j=0; j < RW; j++) {
4622 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
4623 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
4624 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
4627 for (k=0; k<3; k++) {
4628 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
4629 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
4632 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
4636 gtk_widget_draw(preview,NULL);
4640 Funzioni Applicabili
4642 guint gtk_preview_get_type (void);
4644 void gtk_preview_uninit (void);
4646 GtkWidget* gtk_preview_new (GtkPreviewType type);
4647 /* Descritta precedentemente */
4648 void gtk_preview_size (GtkPreview *preview,
4651 /* Permette di ridimensionare un'anteprima esistente */
4652 /* Pare che un bug in GTK renda disordinato questo */
4653 /* processo. Un modo di rimettere le cose a posto */
4654 /* è quello di ridimensionare manualmente */
4655 /* la finestra contenente l'anteprima dopo aver */
4656 /* ridimensionato l'anteprima. */
4658 void gtk_preview_put (GtkPreview *preview,
4669 void gtk_preview_put_row (GtkPreview *preview,
4677 void gtk_preview_draw_row (GtkPreview *preview,
4682 /* Descritta nel testo */
4684 void gtk_preview_set_expand (GtkPreview *preview,
4688 /* Nessun indizio per le seguenti, ma dovrebbero */
4689 /* essere standard per la maggior parte dei widget */
4690 void gtk_preview_set_gamma (double gamma);
4691 void gtk_preview_set_color_cube (guint nred_shades,
4692 guint ngreen_shades,
4694 guint ngray_shades);
4695 void gtk_preview_set_install_cmap (gint install_cmap);
4696 void gtk_preview_set_reserved (gint nreserved);
4697 GdkVisual* gtk_preview_get_visual (void);
4698 GdkColormap* gtk_preview_get_cmap (void);
4699 GtkPreviewInfo* gtk_preview_get_info (void);
4710 <sect>Il Widget EventBox<label id="sec_The_EventBox_Widget">
4712 E' disponibile solo a partire dalla distribuzione gtk+970916.tar.gz.
4714 Alcuni widget gtk non sono associati a finestre X, sicché
4715 semplicemente disegnano sui loro genitori. Per questo motivo essi non possono
4716 ricevere eventi e se sono sovradimensionati non vengono troncati, ma rischiano
4717 di sovrapporsi, generando confusione. Se si vuole di più da questi
4718 widget si può ricorrere agli EventBox.
4720 A prima vista il widget EventBox potrebbe sembrare completamente inutile. Non
4721 disegna nulla sullo schermo e non risponde a nessun evento. Tuttavia ha
4722 una funzione: fornire una finestra X al suo widget figlio. Ciò
4723 è importante in quanto molti widget GTK non hanno una finestra X
4724 associata. Se questo da una parte risparmia memoria e migliora le prestazioni,
4725 dall'altra introduce degli svantaggi: un widget senza una finestra X non
4726 può ricevere eventi, e non taglia in alcun modo il suo contenuto.
4727 Sebbene il nome ``EventBox'' (casella di eventi) enfasizzi la funzione di
4728 gestione degli eventi, il widget può essere usato anche per
4729 limitare la dimensione dei widget figli (ma anche per altro: si veda
4730 l'esempio seguente).
4733 Per creare un widget di tipo EventBox:
4736 GtkWidget* gtk_event_box_new (void);
4740 All'EventBox si può aggiungere un widget figlio:
4743 gtk_container_add (GTK_CONTAINER(event_box), widget);
4747 The following example demonstrates both uses of an EventBox - a label
4748 is created that clipped to a small box, and set up so that a
4749 mouse-click on the label causes the program to exit.
4750 Il seguente esempio mostra entrambi gli usi di un EventBox - si crea
4751 un'etichetta limitata da un rettangolo piccolo, fatta in modo che
4752 cliccando con il mouse su di essa il programma termina.
4755 #include <gtk/gtk.h>
4758 main (int argc, char *argv[])
4761 GtkWidget *event_box;
4764 gtk_init (&argc, &argv);
4766 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4768 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
4770 gtk_signal_connect (GTK_OBJECT (window), "destroy",
4771 GTK_SIGNAL_FUNC (gtk_exit), NULL);
4773 gtk_container_border_width (GTK_CONTAINER (window), 10);
4775 /* Crea un EventBox e lo aggiunge alla finestra principale */
4777 event_box = gtk_event_box_new ();
4778 gtk_container_add (GTK_CONTAINER(window), event_box);
4779 gtk_widget_show (event_box);
4781 /* Crea una etichetta lunga */
4783 label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
4784 gtk_container_add (GTK_CONTAINER (event_box), label);
4785 gtk_widget_show (label);
4787 /* Limitane le dimensioni */
4788 gtk_widget_set_usize (label, 110, 20);
4790 /* E collega ad essa una azione */
4791 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
4792 gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
4793 GTK_SIGNAL_FUNC (gtk_exit), NULL);
4795 /* Un'altra cosa per cui si ha bisogno di una finestra X ... */
4797 gtk_widget_realize (event_box);
4798 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
4800 gtk_widget_show (window);
4808 <sect>Selezionare gli Attributi dei Widget<label id="sec_setting_widget_attributes">
4810 Qui si descrivono le funzioni per la gestione dei widget. Esse possono essere
4811 usate per impostarne lo stile, il padding, le dimensioni, ...
4813 (Forse andrebbe fatta un'intera sezione sugli acceleratori).
4816 void gtk_widget_install_accelerator (GtkWidget *widget,
4817 GtkAcceleratorTable *table,
4822 void gtk_widget_remove_accelerator (GtkWidget *widget,
4823 GtkAcceleratorTable *table,
4824 gchar *signal_name);
4826 void gtk_widget_activate (GtkWidget *widget);
4828 void gtk_widget_set_name (GtkWidget *widget,
4830 gchar* gtk_widget_get_name (GtkWidget *widget);
4832 void gtk_widget_set_sensitive (GtkWidget *widget,
4835 void gtk_widget_set_style (GtkWidget *widget,
4838 GtkStyle* gtk_widget_get_style (GtkWidget *widget);
4840 GtkStyle* gtk_widget_get_default_style (void);
4842 void gtk_widget_set_uposition (GtkWidget *widget,
4845 void gtk_widget_set_usize (GtkWidget *widget,
4849 void gtk_widget_grab_focus (GtkWidget *widget);
4851 void gtk_widget_show (GtkWidget *widget);
4853 void gtk_widget_hide (GtkWidget *widget);
4858 <sect>Funzioni periodiche, di I/O e di attesa<label id="sec_timeouts">
4860 <sect1>Funzioni periodiche
4862 Probabilmente vi sarete chiesti come far fare qualcosa di utile a GTK
4863 durante la chiamata alla gtk_main(). Ci sono diverse possibilità.
4864 Usando le seguenti funzioni si possono creare funzioni che vengono chiamate
4868 gint gtk_timeout_add (guint32 interval,
4869 GtkFunction function,
4873 Il primo argomento è il numero di millisecondi tra le chiamate alla
4874 funzione. Il secondo è la funzione periodica, mentre il terzo
4875 rappresenta i dati che vengono passati alla funzione. Il valore restituito
4876 è un'etichetta che può essere utilizzata per fermare la chiamata
4877 periodica, passandolo alla funzione:
4880 void gtk_timeout_remove (gint tag);
4883 La chiamata periodica si ferma anche se la funzione periodica ritorna zero
4884 o FALSE. Naturalmente questo vuol dire che se si vuole che la funzione periodica
4885 continui ad essere richiamata, essa deve restituire un valore non nullo,
4888 La dichiarazione della funzione periodica dovrebbe essere come questa:
4891 gint timeout_callback (gpointer data);
4894 <sect1>Controllo dell'I/O
4896 Un'altra utile caratteristica di GTK è la possibilità di fargli
4897 controllare che siano verificate certe condizioni su un descrittore di file
4898 (come quelli restituiti da open(2) o socket(2)). Questo è utile in
4899 particolar modo per le applicazioni di rete. La funzione è la seguente:
4902 gint gdk_input_add (gint source,
4903 GdkInputCondition condition,
4904 GdkInputFunction function,
4908 Il primo argomento è il descrittore che si desidera venga controllato,
4909 mentre il secondo specifica quale condizione si vuole che GDK controlli.
4910 Questa può essere una tra:
4912 GDK_INPUT_READ - Chiama la funzione quando ci sono dati pronti per la lettura
4913 nel descrittore di file.
4915 GDK_INPUT_WRITE - Chiama la funzione quando il descrittore di file è
4916 pronto per la scrittura.
4918 Come sicuramente avrete già intuito, il terzo parametro è la
4919 funzione da chiamare quando la condizione specificata è soddisfatta,
4920 mentre il quarto rappresenta i dati da passare a questa funzione.
4922 Il valore di ritorno è un etichetta che può essere usata per
4923 fermare il controllo di GDK sul descrittore di file, usando la seguente
4927 void gdk_input_remove (gint tag);
4930 La funzione da richiamare va dichiarata così:
4933 void input_callback (gpointer data, gint source,
4934 GdkInputCondition condition);
4938 <sect1>Funzioni di attesa (``Idle'')
4940 Cosa fare se si ha una funzione che si vuole venga chiamata quando non
4941 sta accadendo nient'altro?
4944 gint gtk_idle_add (GtkFunction function,
4948 Questa fa si che GDK chiami la funzione specificata quando non c'è
4949 nessuna altra operazione in corso.
4952 void gtk_idle_remove (gint tag);
4955 Non ci soffermeremo sul significato dei parametri in quanto del tutto analoghi
4956 ai precedenti. La funzione puntata dal primo argomento della gtk_idle_add
4957 viene chiamata non appena se ne presenta l'opportunità; come
4958 negli altri casi, se essa restituisce FALSE non viene più chiamata.
4961 <sect>La gestione delle selezioni
4967 Le <em>selezioni</em> sono un tipo di comunicazione tra processi
4968 supportato da GTK. Una selezione identifica un frammento di dati; per
4969 esempio, una porzione di testo selezionata dall'utente in qualche modo,
4970 magari con il mouse. Su un display solo un'applicazione alla volta
4971 (il <em>proprietario</em>) puó essere proprietaria di una
4972 particolare selezione, sicché quando un'applicazione richiede
4973 una selezione il precedente proprietario deve comunicare all'utente che
4974 la selezione è stata ceduta. Altre applicazioni possono richiedere
4975 il contenuto di una selezione in diverse forme, chiamate <em>obiettivi</em>.
4976 Ci può essere un numero qualsiasi di selezioni, ma la maggior parte
4977 delle applicazioni X può gestirne solo una, la <em>selezione
4981 Nella maggior parte dei casi per una applicazione GTK non è
4982 necessario gestire esplicitamente le selezioni. I widget standard,
4983 come quello di Ingresso, hanno già la capacità di
4984 chiedere la selezione se necessario (p. e., quando l'utente
4985 seleziona sul testo), e di recuperare il contenuto di una selezione
4986 di un altro widget o di un'altra applicazione (p. e., quando l'utente
4987 clicca il tasto centrale del mouse). Ci possono comunque essere dei
4988 casi nei quali si vuole dare ad altri widget la capacità di
4989 fornire la selezione, o si vogliono recuperare degli obiettivi non
4990 supportati direttamente.
4993 Un concetto fondamentale necessario per comprendere la gestione delle
4994 selezioni è quello di <em>atomo</em>. Un atomo è un intero
4995 che identifica univocamente una stringa (su un certo display).
4996 Certi atomi sono predefiniti dal server X, e in alcuni casi in <tt>gtk.h</tt>
4997 ci sono costanti corrispondenti a questi atomi. Per esempio, la costante
4998 <tt>GDK_PRIMARY_SELECTION</tt> corrisponde alla stringa ``PRIMARY''.
4999 Negli altri casi bisogna usare le funzioni <tt>gdk_atom_intern()</tt>
5000 per ottenere l'atomo corrispondente ad una stringa, e <tt>gdk_atom_name()</tt>
5001 per ottenere il nome di un atomo. Sia le selezioni sia gli obiettivi sono
5002 identificati da atomi.
5004 <sect1> Recuperare le selezioni
5008 Il recupero di una selezione è un processo asincrono. Per iniziare
5009 il processo, si chiama:
5011 gint gtk_selection_convert (GtkWidget *widget,
5017 Questo <em>converte</em> la selezione nella forma specificata
5018 dall'obiettivo <tt/target/. Se possibile, il campo <tt/time/
5019 dovrebbe essere il tempo dell'evento che ha attivato la selezione.
5020 Questo aiuta a far si che gli eventi avvengano nell'ordine in cui
5021 l'utente li ha richiesti. Se comunque non fosse disponibile (per
5022 esempio, se la conversione è stata attivata da un segnale di
5023 ``cliccato''), allora si può usare la costante
5024 <tt>GDK_CURRENT_TIME</tt>.
5027 Quando il proprietario di una selezione risponde ad una richiesta,
5028 un segnale ``selection_received'' (selezione ricevuta) viene inviato
5029 alla vostra applicazione. Il gestore di questo segnale riceve un
5030 puntatore ad una struttura <tt>GtkSelectionData</tt>, che è
5031 definita nel modo seguente:
5033 struct _GtkSelectionData
5043 <tt>selection</tt> e <tt>target</tt> sono i valori da voi specificati
5044 nella chiamata <tt>gtk_selection_convert()</tt>. <tt>type</tt> è
5045 un atomo che identifica il tipo di dati restituiti dal proprietario della
5046 selezione. Alcuni valori possibili sono ``STRING'', una stringa di
5047 caratteri latin-1, ``ATOM'', una serie di atomi, ``INTEGER'', un intero, ecc.
5048 La maggior parte degli obiettivi può restituire solo un tipo.
5049 <tt/format/ ci dà la lunghezza delle unità (per esempio caratteri)
5050 in bit. Di solito, quando si ricevono i dati non ci si cura di questo.
5051 <tt>data</tt> è un puntatore ai dati restituiti, e <tt>length</tt>
5052 è la lunghezza dei dati restituiti, in byte. Se <tt>length</tt>
5053 è negativo allora si è verificato un errore e non è
5054 stato possibile recuperare la selezione. Questo può avvenire se
5055 nessuna applicazione era proprietaria della selezione, o se si è
5056 richiesto un obiettivo non supportato dall'applicazione. Viene garantito
5057 che il buffer sia un byte più lungo di <tt>length</tt>; il byte
5058 in più sarà sempre zero, in modo che non sia necessario
5059 ricopiare le stringhe solo per farle terminare con zero.
5062 Nell'esempio che segue viene recuperato l'obiettivo speciale ``TARGETS'',
5063 che è una lista di tutti gli obiettivi in cui può essere
5064 convertita la selezione.
5066 #include <gtk/gtk.h>
5068 void selection_received (GtkWidget *widget,
5069 GtkSelectionData *selection_data,
5072 /* Gestore di segnale chiamato quando l'utente clicca nel bottone */
5075 get_targets (GtkWidget *widget, gpointer data)
5077 static GdkAtom targets_atom = GDK_NONE;
5079 /* Prende l'atomo corrispondente alla stringa "TARGETS" */
5080 if (targets_atom == GDK_NONE)
5081 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
5083 /* E richiede l'obiettivo "TARGETS" per la selezione primaria */
5084 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
5088 /* Gestore di segnale chiamato quando il proprietario della selezione */
5089 /* restituisce i dati */
5091 selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
5098 /* **** IMPORTANTE **** Controlla che il recupero sia riuscito */
5099 if (selection_data->length < 0)
5101 g_print ("Selection retrieval failed\n");
5104 /* Make sure we got the data in the expected form */
5105 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
5107 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
5111 /* Stampa gli atomi ricevuti */
5112 atoms = (GdkAtom *)selection_data->data;
5115 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
5118 name = gdk_atom_name (atoms[i]);
5120 g_print ("%s\n",name);
5122 g_print ("(bad atom)\n");
5129 main (int argc, char *argv[])
5134 gtk_init (&argc, &argv);
5136 /* Create the toplevel window */
5138 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5139 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
5140 gtk_container_border_width (GTK_CONTAINER (window), 10);
5142 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5143 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5145 /* Crea un bottone che l'utente può cliccare per ottenere gli obiettivi */
5147 button = gtk_button_new_with_label ("Get Targets");
5148 gtk_container_add (GTK_CONTAINER (window), button);
5150 gtk_signal_connect (GTK_OBJECT(button), "clicked",
5151 GTK_SIGNAL_FUNC (get_targets), NULL);
5152 gtk_signal_connect (GTK_OBJECT(button), "selection_received",
5153 GTK_SIGNAL_FUNC (selection_received), NULL);
5155 gtk_widget_show (button);
5156 gtk_widget_show (window);
5164 <sect1> Fornire una selezione
5167 Fornire la selezione è un po' più complicato. Bisogna
5168 registrare i gestori che verranno chiamati quando viene richiesta la
5169 propria selezione. Per ogni coppia selezione/obiettivo che si gestirà
5170 occorre una chiamata a:
5173 void gtk_selection_add_handler (GtkWidget *widget,
5176 GtkSelectionFunction function,
5177 GtkRemoveFunction remove_func,
5181 <tt/widget/, <tt/selection/, e <tt/target/ identificano le richieste
5182 che questo gestore soddisferà. <tt/remove_func/, se non è
5183 NULL, verrà chiamato quando il gestore di segnale viene rimosso.
5184 Questo è utile, per esempio, per linguaggi interpretati ai quali
5185 serve di tener traccia di un conteggio di riferimento per <tt/data/.
5188 La funzione di richiamo ha la forma:
5191 typedef void (*GtkSelectionFunction) (GtkWidget *widget,
5192 GtkSelectionData *selection_data,
5197 La GtkSelectionData è la stessa di prima, ma stavolta siamo
5198 responsabili di riempire i campi <tt/type/, <tt/format/, <tt/data/,
5199 e <tt/length/. (Il campo <tt/format/ qui è effettivamente
5200 importante - il server X lo usa per capire se occorre che i byte
5201 dei dati vengano scambiati o no. Di solito sarà 8 - cioè
5202 un carattere - o 32 - cioè un intero.) Questo viene fatto
5203 chiamando la funzione:
5206 void gtk_selection_data_set (GtkSelectionData *selection_data,
5212 Questa funzione si prende cura di fare propriamente una copia dei dati
5213 in modo che non ci si debba preoccupare di conservarli (è opportuno
5214 evitare di riempire a mano i campi della struttura GtkSelectionData).
5217 Quando richiesto dall'utente, richiederete la proprietà della selezione
5221 gint gtk_selection_owner_set (GtkWidget *widget,
5226 Se un'altra applicazione richiede la proprietà della selezione,
5227 riceverete un evento di azzeramento della selezione (``selection_clear_event'').
5229 Come esempio di fornitura della selezione, il programma seguente aggiunge
5230 la funzionalità di selezione a un bottone di attivazione. Quando il
5231 bottone viene premuto, il programma richiede la selezione primaria.
5232 L'unico obiettivo supportato (oltre a certi obiettivi come ``TARGETS''
5233 fornito dalla stessa GTK) è l'obiettivo ``STRING''. Quando viene
5234 richiesto questo obiettivo, viene restituita una rappresentazione stringa
5238 #include <gtk/gtk.h>
5241 /* Richiamata quando l'utente attiva la selezione */
5243 selection_toggled (GtkWidget *widget, gint *have_selection)
5245 if (GTK_TOGGLE_BUTTON(widget)->active)
5247 *have_selection = gtk_selection_owner_set (widget,
5248 GDK_SELECTION_PRIMARY,
5250 /* se il richiamo della selezione è fallito, si riporta il
5251 bottone nello stato non premuto */
5252 if (!*have_selection)
5253 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
5257 if (*have_selection)
5259 /* Prima di annullare la selezione mettendone a NULL il proprietario,
5260 controlliamo se siamo i veri proprietari */
5261 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
5262 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
5264 *have_selection = FALSE;
5269 /* Chiamata quando un'altra applicazione richiede la selezione */
5271 selection_clear (GtkWidget *widget, GdkEventSelection *event,
5272 gint *have_selection)
5274 *have_selection = FALSE;
5275 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
5280 /* Fornisce come selezione il tempo attuale */
5282 selection_handle (GtkWidget *widget,
5283 GtkSelectionData *selection_data,
5287 time_t current_time;
5289 current_time = time (NULL);
5290 timestr = asctime (localtime(&current_time));
5291 /* Quando si restituisce una singola stringa, non occorre che finisca
5292 con NULL. Questo verrà fatto automaticamente */
5294 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
5295 8, timestr, strlen(timestr));
5299 main (int argc, char *argv[])
5303 GtkWidget *selection_button;
5305 static int have_selection = FALSE;
5307 gtk_init (&argc, &argv);
5309 /* Crea la finestra di livello superiore */
5311 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5312 gtk_window_set_title (GTK_WINDOW (window), "Event Box");
5313 gtk_container_border_width (GTK_CONTAINER (window), 10);
5315 gtk_signal_connect (GTK_OBJECT (window), "destroy",
5316 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5318 /* Crea un bottone a commutazione che agisce come la selezione */
5320 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
5321 gtk_container_add (GTK_CONTAINER (window), selection_button);
5322 gtk_widget_show (selection_button);
5324 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
5325 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
5326 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
5327 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
5329 gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
5330 GDK_SELECTION_TYPE_STRING,
5331 selection_handle, NULL, NULL);
5333 gtk_widget_show (selection_button);
5334 gtk_widget_show (window);
5344 <sect>La glib<label id="sec_glib">
5346 La glib fornisce molte funzioni e definizioni utili pronte all'uso quando si
5347 creano applicazioni GDK e GTK. Qui verranno elencate tutte, con una
5348 breve spiegazione. Molte sono duplicati delle funzioni standard della libc,
5349 e quindi per queste non si scenderà nei dettagli. Questa vuole essere una
5350 lista di riferimento, in modo che si sappia cosa è possibile usare.
5354 Le definizioni per gli estremi di molti dei tipi standard sono:
5369 Ci sono anche le seguenti definizioni di tipo. Quelle rimaste non specificate
5370 sono dipendenti dall'architettura. Si ricordi di evitare di fare affidamento
5371 sulla dimensione di un puntatore se si vuole la portabilità! P.e., un puntatore
5372 su un Alpha è lungo 8 byte, ma 4 su un Intel.
5381 unsigned char guchar;
5382 unsigned short gushort;
5383 unsigned long gulong;
5388 long double gldouble;
5400 <sect1>Liste a doppio collegamento
5402 le seguenti funzioni sono usate per creare, gestire e distruggere liste a
5403 doppio collegamento. Si assume che il lettore sappia già cosa sono le liste
5404 collegate, poiché descriverle è fuori dagli scopi di questo documento.
5405 Naturalmente non è necessario conoscerle per l'uso generale di GTK, per
5406 quanto conoscerle sia comunque interessante.
5409 GList* g_list_alloc (void);
5411 void g_list_free (GList *list);
5413 void g_list_free_1 (GList *list);
5415 GList* g_list_append (GList *list,
5418 GList* g_list_prepend (GList *list,
5421 GList* g_list_insert (GList *list,
5425 GList* g_list_remove (GList *list,
5428 GList* g_list_remove_link (GList *list,
5431 GList* g_list_reverse (GList *list);
5433 GList* g_list_nth (GList *list,
5436 GList* g_list_find (GList *list,
5439 GList* g_list_last (GList *list);
5441 GList* g_list_first (GList *list);
5443 gint g_list_length (GList *list);
5445 void g_list_foreach (GList *list,
5447 gpointer user_data);
5451 <sect1>Liste a collegamento singolo
5453 Molte delle funzioni per le liste a collegamento singolo sono identiche alle
5454 precedenti. Eccone una lista completa:
5456 GSList* g_slist_alloc (void);
5458 void g_slist_free (GSList *list);
5460 void g_slist_free_1 (GSList *list);
5462 GSList* g_slist_append (GSList *list,
5465 GSList* g_slist_prepend (GSList *list,
5468 GSList* g_slist_insert (GSList *list,
5472 GSList* g_slist_remove (GSList *list,
5475 GSList* g_slist_remove_link (GSList *list,
5478 GSList* g_slist_reverse (GSList *list);
5480 GSList* g_slist_nth (GSList *list,
5483 GSList* g_slist_find (GSList *list,
5486 GSList* g_slist_last (GSList *list);
5488 gint g_slist_length (GSList *list);
5490 void g_slist_foreach (GSList *list,
5492 gpointer user_data);
5496 <sect1>Gestione della memoria
5499 gpointer g_malloc (gulong size);
5502 Questa è una sostituta di malloc(). Non occorre controllare il valore
5503 restituito, in quanto lo fa già questa funzione.
5506 gpointer g_malloc0 (gulong size);
5509 Come la precedente, ma la memoria viene azzerata prima di restituire un
5513 gpointer g_realloc (gpointer mem,
5517 Riloca ``size'' byte di memoria che inizia a ``mem''. Ovviamente, la memoria
5518 dovrebbe essere stata allocata precedentemente.
5521 void g_free (gpointer mem);
5524 Libera la memoria. Facile!
5527 void g_mem_profile (void);
5530 Emette un profilo della memoria usata, ma occorre ricompilare e reinstallare
5531 la libreria aggiungendo #define MEM_PROFILE all'inizio del file glib/gmem.c.
5534 void g_mem_check (gpointer mem);
5537 Controlla che una locazione di memoria sia valida. Occorre ricompilare e
5538 reinstallare la libreria aggiungendo #define MEM_CHECK all'inizio del file
5543 Funzioni legate ai timer...
5546 GTimer* g_timer_new (void);
5548 void g_timer_destroy (GTimer *timer);
5550 void g_timer_start (GTimer *timer);
5552 void g_timer_stop (GTimer *timer);
5554 void g_timer_reset (GTimer *timer);
5556 gdouble g_timer_elapsed (GTimer *timer,
5557 gulong *microseconds);
5560 <sect1>Gestione delle stringhe
5562 Un'accozzaglia di funzioni per la gestione delle stringhe. Sembrano tutte molto
5563 interessanti, e probabilmente migliori per molte caratteristiche delle funzioni
5564 standard del C per le stringhe, ma necessitano di documentazione.
5567 GString* g_string_new (gchar *init);
5568 void g_string_free (GString *string,
5571 GString* g_string_assign (GString *lval,
5574 GString* g_string_truncate (GString *string,
5577 GString* g_string_append (GString *string,
5580 GString* g_string_append_c (GString *string,
5583 GString* g_string_prepend (GString *string,
5586 GString* g_string_prepend_c (GString *string,
5589 void g_string_sprintf (GString *string,
5593 void g_string_sprintfa (GString *string,
5598 <sect1>Funzioni d'utilità e di errore
5601 gchar* g_strdup (const gchar *str);
5604 Funzione sostitutiva della strdup. Copia i contenuti originari delle stringhe
5605 in memoria appena allocata, restituendo un puntatore ad essa.
5608 gchar* g_strerror (gint errnum);
5610 Si raccomanda di usare questa gunzione per tutti i messaggi di errore. E' molto
5611 più graziosa, e più portabile di perror() o di altre. L'output di solito ha la
5615 nome programma:funzione fallita:file o altre descrizioni:strerror
5618 Di seguito un esempio di una chiamata di questo tipo usata nel nostro
5619 programma Hello World:
5622 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
5626 void g_error (gchar *format, ...);
5629 Visualizza un messaggio di errore. Il formato è come quello di printf,
5630 ma prepone ``** ERROR **: '' al messaggio e termina il programma. Da usare solo
5634 void g_warning (gchar *format, ...);
5637 Come la precedente, ma prepone ``** WARNING **: '' e non termina il programma.
5640 void g_message (gchar *format, ...);
5643 Visualizza ``message: '' e poi il messaggio.
5646 void g_print (gchar *format, ...);
5649 Sostituta di printf().
5654 gchar* g_strsignal (gint signum);
5657 Visualizza il nome del messaggio del sistema Unix associato al numero di
5658 segnale. Utile nelle funzioni generiche di gestione dei segnali.
5660 Tutte le funzioni elencate sono più o meno prese da glib.h. Se qualcuno volesse
5661 documentare qualche funzione, mandi una email all'autore!
5663 <sect>I file rc di GTK
5665 GTK ha un suo modo di trattare le preferenze delle applicazioni, usando
5666 i file rc. Questi possono essere usati per scegliere i colori di quasi tutti
5667 i widget, e possono anche essere usati per inserire delle pixmap nello sfondo
5670 <sect1>Funzioni per i file rc
5672 All'inizio della vostra applicazione dovrebbe esserci una chiamata a
5674 void gtk_rc_parse (char *filename);
5677 passando come parametro il nome del vostro file rc. Questo farà si che GTK
5678 analizzi tale file e usi le impostazioni di stile per i tipi di widget ivi
5681 Se si desidera avere un insieme speciale di widget che abbia uno stile diverso
5682 dagli altri, o qualsiasi altra divisione logica dei widget, si chiami
5684 void gtk_widget_set_name (GtkWidget *widget,
5688 passando un widget appena creato come primo argomento, e il nome che gli si
5689 vuole dare come secondo. Questo consentirà di cambiare gli attributi di
5690 questo widget per nome tramite il file rc.
5692 Effettuando una chiamata come questa:
5695 button = gtk_button_new_with_label ("Special Button");
5696 gtk_widget_set_name (button, "special button");
5699 allora a questo bottone viene dato il nome ``special button'' ed esso può essere
5700 riferito per nome nel file rc come ``special button.GtkButton''. [<--- Verificatemi!]
5702 Il seguente esempio di file rc imposta le proprietà della finestra principale,
5703 e fa si che tutti i figli di questa finestra ereditino lo stile descritto
5704 dallo stile ``main button''. Il codice usato nell'applicazione è:
5707 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5708 gtk_widget_set_name (window, "main window");
5711 Lo stile viene definito nel file rc usando:
5714 widget "main window.*GtkButton*" style "main_button"
5717 che assegna a tutti i widget GtkButton nella finestra principale lo stile
5718 ``main_buttons'' secondo la definizione data nel file rc.
5720 Come si può vedere, questo sistema è molto potente e flessibile. Usate la
5721 vostra immaginazione per trarre il massimo vantaggio da esso.
5723 <sect1>Il formato dei file rc di GTK
5725 Nell'esempio che segue viene illustrato il formato del file GTK. Si tratta
5726 del file testgkrc dalla distribuzione del GTK, a cui sono stati aggiunti
5727 vari commenti e varie cose. Potete includere questa spiegazione nella
5728 vostra applicazione per consentire all'utente di personalizzarla finemente.
5730 There are several directives to change the attributes of a widget.
5731 Ci sono diverse direttive per cambiare gli attributi di un widget.
5733 <item>fg - Assegna il colore di primo piano di un widget.
5734 <item>bg - Assegna il colore di sfondo di un widget.
5735 <item>bg_pixmap - Inserisce nello sfondo di un widget una pixmap.
5736 <item>font - Sceglie il font da usarsi con il dato widget.
5739 Inoltre ci sono diversi stati in cui può trovarsi un widget, e si possono
5740 assegnare diversi colori, pixmap e font per ogni stato. Essi sono:
5742 <item>NORMAL - Lo stato normale di un widget, quando il mouse non si trova su
5743 di esso, quando non è premuto, ecc.
5744 <item>PRELIGHT (evidenziato)- Quando il mouse si trova sopra al widget
5745 verranno usati i colori assegnati per questo stato.
5746 <item>ACTIVE (attivo) - Quando il widget è premuto o cliccato esso sarà attivo,
5747 e verranno usati gli attributi assegnati da questa etichetta.
5748 <item>INSENSITIVE (insensibile)- Quando un widget viene reso insensibile,
5749 e non può essere attivato, prenderà questi attributi.
5750 <item>SELECTED (selezionato) - Quando un oggetto viene selezionato, prende
5754 Quando si usano le parole chiave ``fg'' e ``bg'' per assegnare i colori dei
5755 widget il formato è:
5757 fg[<STATE>] = { Rosso, Verde, Blu }
5760 Dove STATE è uno degli stati visti prima (PRELIGHT, ACTIVE ecc.), e Rosso,
5761 Verde e Blu sono valori nell'intervallo 0 - 1.0; { 1.0, 1.0, 1.0 } rappresenta
5763 Devono essere in formato float, o verranno visti come 0, sicché un ``1'' diretto
5764 non funziona, deve essere ``1.0''. Uno ``0'' diretto va invece bene, poiché poco
5765 importa se non viene riconosciuto: valori non riconosciuti vengono considerati
5768 bg_pixmap è molto simile al precedente, tranne per i colori che vengono
5769 sostituiti dal nome di un file.
5771 pixmap_path è una lista di percorsi separati da ``:''. In questi percorsi vengono
5772 cercate le pixmap specificate.
5774 La direttiva font è semplicemente:
5776 font = "<font name>"
5779 dove l'unica parte complicata è immaginare la stringa del font. Allo scopo
5780 può servire usare xfontsel o una utilità analoga.
5782 ``widget_class'' assegna lo stile di una classe di widget. Queste classi sono
5783 elencate nell'introduzione ai widget sulla gerarchia delle classi.
5785 La direttiva ``widget'' assegna un insieme di widget dal nome specificato ad
5786 un dato stile, annullando qualsiasi stile assegnato per la data classe di widget.
5787 Questi widget vengono registrati nell'applicazione usando la chiamata
5788 gtk_widget_set_name(). Questo consente di specificare gli attributi di un
5789 widget singlarmente, piuttosto che assegnando gli attributi di un'intera classe
5790 di widget. E' opportuno documentare tutti questi widget speciali in modo che
5791 gli utenti possano personalizzarli.
5793 Quando la parola chiave ``<tt>parent</>'' viene usata come un attributo, il
5794 widget erediterà gli attributi del suo genitore nell'applicazione.
5796 Quando si definisce uno stile si possono assegnare gli attributi di uno
5797 stile definito precedentemente a quello nuovo.
5799 style "main_button" = "button"
5801 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
5802 bg[PRELIGHT] = { 0.75, 0, 0 }
5806 Questo esempio prende lo stile ``button'' e crea un nuovo stile
5807 semplicemente cambiando il font e il colore di sfondo dello stato ``prelight''
5808 nello stile ``button''.
5810 Naturalmente, molti di questi attributi non sono applicabili a tutti i widget.
5811 E' veramente un semplice problema di buon senso. Tutto quello che potrebbe
5812 applicarsi, dovrebbe.
5814 <sect1>Esempio di file rc
5818 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
5820 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
5822 # style <name> [= <name>]
5827 # widget <widget_set> style <style_name>
5828 # widget_class <widget_class_set> style <style_name>
5831 # Ecco una lista di tutti gli stati possibili. Si noti che alcuni non sono
5832 # applicabili a certi widget.
5834 # NORMAL - Lo stato normale di un widget, quando il mouse non si trova su
5835 # di esso, quando non è premuto, ecc.
5837 # PRELIGHT (evidenziato)- Quando il mouse si trova sopra al widget
5838 # verranno usati i colori assegnati per questo stato.
5840 # ACTIVE (attivo) - Quando il widget è premuto o cliccato esso sarà attivo,
5841 # e verranno usati gli attributi assegnati da questa etichetta.
5843 # INSENSITIVE (insensibile)- Quando un widget viene reso insensibile,
5844 # e non può essere attivato, prenderà questi attributi.
5846 # SELECTED (selezionato) - Quando un oggetto viene selezionato, prende
5849 # Dati questi stati, è possibile assegnare gli attributi dei widget in
5850 # ognuno di questi stati usando le seguenti direttive.
5852 # fg - Assegna il colore di primo piano di un widget.
5853 # bg - Assegna il colore di sfondo di un widget.
5854 # bg_pixmap - Inserisce nello sfondo di un widget una pixmap.
5855 # font - Sceglie il font da usarsi con il dato widget.
5858 # Questo è uno stile chiamato "button". Il nome non è veramente importante,
5859 # in quanto viene assegnato ai veri widget alla fine del file.
5863 # Questo inserisce nella spaziatura attorno alla finestra la pixmap
5865 #bg_pixmap[<STATE>] = "<pixmap filename>"
5866 bg_pixmap[NORMAL] = "warning.xpm"
5871 # Mette il colore di primo piano (il colore del font) a rosso nello
5874 fg[NORMAL] = { 1.0, 0, 0 }
5876 # Inserisce nello sfondo del gadget la stessa pixmap usata dal suo genitore.
5877 bg_pixmap[NORMAL] = "<parent>"
5882 # Questo mostra tutti i possibili stati per un bottone. L'unico che
5883 # non è applicabile è lo stato "SELECTED".
5885 fg[PRELIGHT] = { 0, 1.0, 1.0 }
5886 bg[PRELIGHT] = { 0, 0, 1.0 }
5887 bg[ACTIVE] = { 1.0, 0, 0 }
5888 fg[ACTIVE] = { 0, 1.0, 0 }
5889 bg[NORMAL] = { 1.0, 1.0, 0 }
5890 fg[NORMAL] = { .99, 0, .99 }
5891 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
5892 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
5895 # In questi esempio ereditiamo gli attributi dello stile "button" e poi
5896 # alteriamo il font e il colore di sfondo quando evidenziato per creare
5897 # un nuovo stile "main_button".
5899 style "main_button" = "button"
5901 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
5902 bg[PRELIGHT] = { 0.75, 0, 0 }
5905 style "toggle_button" = "button"
5907 fg[NORMAL] = { 1.0, 0, 0 }
5908 fg[ACTIVE] = { 1.0, 0, 0 }
5910 # Questo seleziona come pixmap di sfondo per il toggle_button quella del
5911 # suo widget genitore (definita nell'applicazione).
5912 bg_pixmap[NORMAL] = "<parent>"
5917 bg_pixmap[NORMAL] = "marble.xpm"
5918 fg[NORMAL] = { 1.0, 1.0, 1.0 }
5923 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
5926 # pixmap_path "~/.pixmaps"
5928 # Queste assegnano ai tipi di widget gli stili definiti prima.
5929 # I tipi di widget sono elencati nella gerarchia delle classi, ma probabilmente
5930 # dovrebbero essere elencati in questo documento come riferimento per l'utente.
5932 widget_class "GtkWindow" style "window"
5933 widget_class "GtkDialog" style "window"
5934 widget_class "GtkFileSelection" style "window"
5935 widget_class "*Gtk*Scale" style "scale"
5936 widget_class "*GtkCheckButton*" style "toggle_button"
5937 widget_class "*GtkRadioButton*" style "toggle_button"
5938 widget_class "*GtkButton*" style "button"
5939 widget_class "*Ruler" style "ruler"
5940 widget_class "*GtkText" style "text"
5942 # Questo assegna lo stile main_button a tutti i bottoni che sono figli della
5943 # "main window" (finestra principale). Questi devono essere documenati per
5944 # potersene avvantaggiare.
5945 widget "main window.*GtkButton*" style "main_button"
5950 <sect>Scrivere un proprio Widget
5955 Anche se la distribuzione GTK contiene molto tipi di widget che possono
5956 coprire molte necessità basilari, può essere necessario costruirsi
5957 un proprio widget. GTK usa molto l'ereditarietà tra i vari
5958 widget e, di solito, vi è un widget che si avvicina a quello che ti
5959 servirebbe, ed è spesso possibile creare un nuovo widget con poche linee
5960 di codice. Ma prima di iniziare il lavoro su un nuovo widget, vediamo
5961 se qualcuno non lo ha già creato. Questo eviterà un duplicazione
5962 di lavoro e farà sì che i widget non-GTK puri siano minimi, così da
5963 aiutare sia chi crea il codice che chi l'interfaccia per applicazioni GTK
5964 molto grosse. D'altra parte, quando hai finito di scrivere un widget,
5965 annuncialo a tutto il mondo così che le altre persone ne possano
5966 beneficiare. Il miglioro modo dove farlo è la <tt>gtk-list</tt>.
5968 <sect1> L'anatomia di un widget
5971 Per creare un nuovo widget è importante aver capito come gli ogetti
5972 di GTK lavorano. Questa sezione è solo una breve spiegazione. Guarda la
5973 documentazione di riferimento per maggiori dettagli.
5976 I widget GTK sono implementati in un modo orientato agli oggetti,
5977 anche se usando il C standard. Questo aumenta notevolmente la portabilità
5978 e la stabilità, specialmente per le correnti generazioni di compilatori C++;
5979 comunque questo significa che chi scrive un widget deve fare attenzione
5980 ad alcuni dettagli di implementazione. L'informazione comune a tutte le
5981 istanze di una classe di widget (ad esempio: a tutti i bottoni) è memorizzata
5982 <em>class structure</em>. C'e' solamente una copia di questo in cui
5983 sono memorizzate le informazioni riguardanti i segnali della classe
5984 (assomiglia ad una funzione virtuale in C). Per supportare l'ereditarietà
5985 il primo campo della struttura di una classe deve essere una copia della
5986 struttura della classe genitore. La dichiarazione della struttura della
5987 classe GtkButton è:
5990 struct _GtkButtonClass
5992 GtkContainerClass parent_class;
5994 void (* pressed) (GtkButton *button);
5995 void (* released) (GtkButton *button);
5996 void (* clicked) (GtkButton *button);
5997 void (* enter) (GtkButton *button);
5998 void (* leave) (GtkButton *button);
6003 Quando un bottone viene trattato come un contenitore (ad esempio quando viene
6004 ridimensionato) si può fare il cast della struttura della sua classe con la
6005 GtkContainerClass, e usare i campi rilevanti per gestire i segnali.
6008 C'è anche una struttura per ogni widget che viene creata
6009 ad ogni istanza. Questa struttura ha campi per
6010 memorizzare le informazioni che sono differenti per ogni volta che il widget
6011 viene istanziato. Chiameremo questa struttura la <em> struttura
6012 oggetto</em>. Per la classe Bottone, questa ha l'aspetto:
6017 GtkContainer container;
6021 guint in_button : 1;
6022 guint button_down : 1;
6027 Si noti che, similmente alla struttura della classe, il primo campo
6028 è la struttura dell'oggetto della classe madre, così che, se necessario, si può fare il
6029 cast di questa struttura con quella dell'oggetto della classe madre.
6031 <sect1> Creare un Widget composto
6033 <sect2> Introduzione
6036 Un tipo di widget a cui potreste essere interessati è un widget che
6037 è semplicemnte un aggregato di altri widget GTK. Questo tipo di
6038 widget non fa nulla che non possa essere fatto creando un nuovo
6039 widget, ma fornisce un modo conveniente per inscatolare elementi
6040 dell'interfaccia utente per poi riutilizzarli.
6041 I widget FileSelection e ColorSelection della ditribuzione standard
6042 sono esempi di questo tipo di widget.
6045 Il widget di esempio che creeremo in questo capitolo è il
6046 Tictactoe, un vettore 3x3 di bottoni a commutazione il quale emette
6047 un segnale quando tutti e 3 i bottoni di una riga, colonna o di una
6048 diagonale sono premuti.
6050 <sect2> Scegliere la classe madre
6053 La classe madre per un widget composto e' tipicamente la classe
6054 contenitrice che racchiude tutti gli elementi del widget composto.
6055 Per esempio, la classe madre del widget FileSelection è la classe
6056 Dialog. Visto che i nostri bottoni sono inseriti in una tabella, è
6057 naturale pensare che la nostra classe madre possa essere la GtkTable.
6058 Sfortunatamente, così non è. La creazione di un widget è diviso
6059 tra 2 funzioni : la funzione <tt/WIDGETNAME_new()/ che viene invocata
6060 dall'utente, e la funzione <tt/WIDGETNAME_init()/ che ha il compito
6061 principale di inizializzare il widget che è indipendente dai valori
6062 passati alla funzione <tt/_new()/. Widget figli o discendenti possono
6063 chiamare, solamente, la funzione del loro widget genitore.
6064 Ma questa divisione del lavoro non funziona bene per la tabella, la
6065 quale, quando creata, necessita di conoscere il numero di righe e
6066 colonne che la comporrà. A meno che non vogliamo duplicare molte delle
6067 fuinzionalità della <tt/gtk_table_new()/ nel nostro widget
6068 Tictactoe, faremmo meglio a evitare di derivarlo dalla GtkTable. Per questa
6069 ragione lo deriviamo invece da GtkVBox, e uniamo la nostra tabella
6072 <sect2> Il File Header
6075 Ogni classe di widget ha un file header il quale dichiara l'oggetto e la
6076 struttura della classe del widget, comprese le funzioni pubbliche.
6077 Per prevenire duplicati di definizioni, noi includiamo l'intero file header fra:
6080 #ifndef __TICTACTOE_H__
6081 #define __TICTACTOE_H__
6085 #endif /* __TICTACTOE_H__ */
6088 E per far felici i programmi in C++ che includono il nostro file header, in:
6093 #endif /* __cplusplus */
6099 #endif /* __cplusplus */
6102 Insieme alle funzioni e alle strutture, dichiariamo tre macro
6103 standard nel nostro file header, <tt/TICTACTOE(obj)/,
6104 <tt/TICTACTOE_CLASS(klass)/, e <tt/IS_TICTACTOE(obj)/, i quali rispettivamente
6105 fanno il cast di un puntatore ad un puntatore ad un ogetto od ad una struttura
6106 di classe, e guarda se un oggetto è un widget Tictactoe.
6109 Qui vi è il file header completo:
6113 #ifndef __TICTACTOE_H__
6114 #define __TICTACTOE_H__
6116 #include <gdk/gdk.h>
6117 #include <gtk/gtkvbox.h>
6121 #endif /* __cplusplus */
6123 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
6124 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
6125 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
6128 typedef struct _Tictactoe Tictactoe;
6129 typedef struct _TictactoeClass TictactoeClass;
6135 GtkWidget *buttons[3][3];
6138 struct _TictactoeClass
6140 GtkVBoxClass parent_class;
6142 void (* tictactoe) (Tictactoe *ttt);
6145 guint tictactoe_get_type (void);
6146 GtkWidget* tictactoe_new (void);
6147 void tictactoe_clear (Tictactoe *ttt);
6151 #endif /* __cplusplus */
6153 #endif /* __TICTACTOE_H__ */
6157 <sect2> La funzione <tt/_get_type()/
6160 Continuiamo ora con l'implementazione del nostro widget. Una funzione
6161 basilare di ogni widget è la funzione <tt/WIDGETNAME_get_type()/.
6162 Questa funzione, quando chiamata la prima volta, comunica a GTK la classe
6163 del widget, e ottiene un identificativo univoco per la classe del
6164 widget. Chiamate successive restituiscono semplicemente l'identificativo.
6168 tictactoe_get_type ()
6170 static guint ttt_type = 0;
6174 GtkTypeInfo ttt_info =
6178 sizeof (TictactoeClass),
6179 (GtkClassInitFunc) tictactoe_class_init,
6180 (GtkObjectInitFunc) tictactoe_init,
6184 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
6192 La struttura GtkTypeInfo ha la seguente definizione:
6200 GtkClassInitFunc class_init_func;
6201 GtkObjectInitFunc object_init_func;
6202 GtkArgFunc arg_func;
6207 I campi di questa struttura sono abbastanza auto-esplicativi.
6208 Ignoreremo, per ora, il campo <tt/arg_func/: ha un ruolo importante, ma
6209 non ancora largamente implementato, nel permettere ai linguaggi interpretati
6210 di settare convenientemente le opzioni del widget.
6211 Una volta che il GTK ha completato correttamente una copia di questa
6212 struttura, sa come creare un oggetto di un particolare widget.
6214 <sect2> La funzione <tt/_class_init()/
6216 La funzione <tt/WIDGETNAME_class_init()/ inizialiazza i campi della
6217 struttura della classe del widget, e setta ogni segnale della classe.
6218 Per il nostro widget Tictactoe ha il seguente aspetto:
6227 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
6230 tictactoe_class_init (TictactoeClass *class)
6232 GtkObjectClass *object_class;
6234 object_class = (GtkObjectClass*) class;
6236 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
6239 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
6240 gtk_signal_default_marshaller, GTK_ARG_NONE, 0);
6243 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
6245 class->tictactoe = NULL;
6250 Il nostro widget ha semplicemente il segnale ``tictactoe'' che è
6251 invocato quando una riga, colonna o diagonale è completamente premuta.
6252 Non tutti i widget composti necessitano di segnali, quindi se stai
6253 leggendo questo per la prima volta, puoi anche saltare alla prossima sezione,
6254 dal momento che a questo punto le cose diventano un po' complicate.
6258 gint gtk_signal_new (gchar *name,
6259 GtkSignalRunType run_type,
6261 gint function_offset,
6262 GtkSignalMarshaller marshaller,
6263 GtkArgType return_val,
6268 crea un nuovo segnale. I parametri sono:
6271 <item> <tt/name/: Il nome del segnale.
6272 <item> <tt/run_type/: Se il segstore predefinito viene eseguito prima o dopo
6273 di quello dell'utente. Di norma questo sarà <tt/GTK_RUN_FIRST/, o <tt/GTK_RUN_LAST/,
6274 anche se ci sono altre possibilità.
6275 <item> <tt/object_type/: l'identificativo dell'oggetto a cui questo segnale si
6276 riferisce. Esso sarà anche applicato agli oggetti discendenti.
6277 <item> <tt/function_offset/: L'offset nella struttura della classe di un
6278 puntatore al gestore predefinito.
6279 <item> <tt/marshaller/: una funzione che è usata per invocare il gestore
6280 del segnale. Per gestori di segnali che non hanno argomenti oltre
6281 all'oggetto che emette il segnale e i dati dell'utente, possiamo usare
6282 la funzione predefinita <tt/gtk_signal_default_marshaller/
6283 <item> <tt/return_val/: Il tipo del valore di ritorno.
6284 <item> <tt/nparams/: Il numero di parametri del gestore di segnali (oltre
6285 ai due predefiniti menzionati sopra)
6286 <item> <tt/.../: i tipi dei parametri
6289 Quando si specificano i tipi, si usa l'enumerazione <tt/GtkArgType/:
6308 <tt/gtk_signal_new()/ restituisce un identificatore unico intero per il segnale,
6309 che memorizziamo nel vettore <tt/tictactoe_signals/, che
6310 indicizzeremo usando una enumerazione. (Convenzionalmente, gli elementi dell'enumerazione
6311 sono i nomi dei segnali, in maiuscolo,
6312 ma qui ci potrebbe essere un conflitto con la macro <tt/TICTACTOE()/,
6313 quindi l'abbiamo chiamato <tt/TICTACTOE_SIGNAL/
6315 Dopo aver creato un nostro segnale, abbiamo bisogno di dire a GTK
6316 di associare il nostro segnale alla classe Tictactoe. Lo facciamo
6317 invocando <tt/gtk_object_class_add_signals()/. Settiamo quindi a NULL
6318 il puntatore che punta al gestore predefinito per il segnale
6319 ``tictactoe'' a NULL, indicando che non ci sono azioni predefinite.
6321 <sect2> La funzione <tt/_init()/
6325 Ogni classe di Widget necessita anche di una funzione per inizializzare
6326 la struttura dell'oggetto. Usualmente questa funzione ha il ruolo abbastanza
6327 limitato di assegnare ai campi della struttura i valori predefiniti.
6328 Per widget composti, comunque, questa funzione crea, anche,
6329 i widget componenti del widget composto.
6334 tictactoe_init (Tictactoe *ttt)
6339 table = gtk_table_new (3, 3, TRUE);
6340 gtk_container_add (GTK_CONTAINER(ttt), table);
6341 gtk_widget_show (table);
6346 ttt->buttons[i][j] = gtk_toggle_button_new ();
6347 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
6349 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
6350 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
6351 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
6352 gtk_widget_show (ttt->buttons[i][j]);
6357 <sect2> E il resto...
6361 C'è un'altra funzione che ogni widget (eccetto i Widget di base come
6362 GtkBin che non possono essere instanziati) deve avere : la funzione
6363 che l'utente invoca per creare un oggetto di quel tipo. Questa è
6364 convenzionalmente chiamata <tt/WIDGETNAME_new()/. In alcuni widget,
6365 non nel caso del nostro Tictactoe, questa funzione richiede degli
6366 argomenti, e fa alcune operazioni basandosi su di essi. Le altre
6367 due funzioni sono specifiche del widget Tictactoe.
6370 <tt/tictactoe_clear()/ è una funzione pubblica che resetta tutti i
6371 bottoni, nel widget, allo stato iniziale (non premuto). Notate l'uso
6372 di <tt/gtk_signal_handler_block_by_data()/ per impedire che il nostro
6373 gestore dei segnali venga attivato quando non ce n'è bisogno.
6376 <tt/tictactoe_toggle()/ è il gestore del segnale che viene invocato
6377 quando l'utente preme il bottone. Esso guarda se vi è
6378 qualche combinazione vincente che coinvolge i bottoni premuti, e nel
6379 caso ci fosse, emette il segnale ``tictactoe''.
6385 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
6389 tictactoe_clear (Tictactoe *ttt)
6396 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
6397 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
6399 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
6404 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
6408 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
6409 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
6410 { 0, 1, 2 }, { 0, 1, 2 } };
6411 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
6412 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
6413 { 0, 1, 2 }, { 2, 1, 0 } };
6424 success = success &&
6425 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
6427 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
6430 if (success && found)
6432 gtk_signal_emit (GTK_OBJECT (ttt),
6433 tictactoe_signals[TICTACTOE_SIGNAL]);
6442 E finalmente un programma di esempio che usa il nostro widget
6446 #include <gtk/gtk.h>
6447 #include "tictactoe.h"
6449 /* Invocato quando una riga, colonna o diagonale e' completata. */
6451 win (GtkWidget *widget, gpointer data)
6454 tictactoe_clear (TICTACTOE (widget));
6458 main (int argc, char *argv[])
6463 gtk_init (&argc, &argv);
6465 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6467 gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
6469 gtk_signal_connect (GTK_OBJECT (window), "destroy",
6470 GTK_SIGNAL_FUNC (gtk_exit), NULL);
6472 gtk_container_border_width (GTK_CONTAINER (window), 10);
6474 /* Crea un nuovo widget Tictactoe. */
6475 ttt = tictactoe_new ();
6476 gtk_container_add (GTK_CONTAINER (window), ttt);
6477 gtk_widget_show (ttt);
6479 /* E gli aggancia il segnale "tictactoe" */
6480 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
6481 GTK_SIGNAL_FUNC (win), NULL);
6483 gtk_widget_show (window);
6493 <sect1> Creare un widget a partire da zero
6495 <sect2> Introduzione
6499 In questa sezione impareremo meglio come i widget si mostrano sullo schermo
6500 e interagiscono con gli eventi. Come esempio, creeremo
6501 un widget di quadrante analogico con un puntatore che l'utente
6502 può trascinare per assegnare il valore.
6504 <sect2> Mostrare un widget sullo schermo
6507 Ci sono alcuni passi che sono necessari nella visualizzazione sullo
6508 schermo. Dopo che il widget è stato creato con una chiamata a
6509 <tt/WIDGETNAME_new()/, sono necessarie alcune altre funzioni:
6512 <item> <tt/WIDGETNAME_realize()/ è responsabile della creazione di
6513 una finestra X per il widget se ne ha una.
6514 <item> <tt/WIDGETNAME_map()/ è invocata dopo che l'utente ha
6515 chiamato <tt/gtk_widget_show()/. E' responsabile di vedere se il
6516 widget è attualmente disegnato sullo schermo (<em/mappato/). Per
6517 una classe contenitore, essa deve anche creare chiamate alle
6518 funzioni <tt/map()/> per ogni widget figlio.
6519 <item> <tt/WIDGETNAME_draw()/ è invocata quando
6520 <tt/gtk_widget_draw()/ viene chiamata per il widget o per uno dei suoi
6521 predecessori. Esso fa sì che l'attuale chiamata alla
6522 funzione di disegno del widget disegni il widget sullo schermo.
6523 Per la classe contenitore, questa funzione deve eseguire le
6524 chiamate alla funzioni <tt/gtk_widget_draw()/ di ogni suo widget
6526 <item> <tt/WIDGETNAME_expose()/ è un gestore per l'evento di esposizione
6527 per il widget. Esso crea le chiamate necessarie alle funzioni di disegno
6528 per disegnare la porzione che si è resa visibile. Per le classi
6529 contenitore, questa funzione deve generare gli eventi di ``expose'' per
6530 tutti i widget figli che non hanno una propria finestra (se essi hanno
6531 una loro finestra, sarà X che genererà i necessari eventi di expose).
6535 Potete notare che le ultime due funzioni sono molto simili, ognuna è
6536 responsabile per il disegno del widget sullo schermo. Infatti molti
6537 tipi di widget non sanno relamente la differenza tra le due.
6538 La funzione di predefinita <tt/draw()/ nella classe widget, semplicemente
6539 genera un sintetico evento di ``expose'' per l'area da ridisegnare.
6540 Comunque, alcuni tipi di widget possono risparmiare tempo distinguendo
6541 le due funzioni. Per esempio, se un widget ha piu' finestre X, allora
6542 visto che l'evento ``expose'' identifica solo la finestra esposta,
6543 esso può ridisegnare solo la finestra interessata, cosa che non è
6544 possibile per chiamate a <tt/draw()/.
6547 I widget contenitori, anche se essi non farebbero differenze,
6548 non possono semplicemente usare la funzione <tt/draw()/ perchè per i
6549 loro widget figli la differenza potrebbere essere importante. Comunque,
6550 sarebbe uno spreco duplicare il codice di disegno nelle due
6551 funzioni. La convenzione è che questi widget abbiano una funzione
6552 chiamata <tt/WIDGETNAME_paint()/ che disegna il widget, che è poi
6553 chiamata dalle funzioni <tt/draw()/ e <tt/expose()/
6556 Nell'approccio del nostro esempio, visto che il widget, ha
6557 una sola finestra, possiamo utilizzare il modo piu' semplice
6558 ed usare la funzione predefinita <tt/draw()/ e implementare
6559 solamente la funzione <tt/expose()/.
6561 <sect2> Le origini del widget Dial
6564 Come tutti gli animali terresti sono semplicemente varianti del primo
6565 amfibio, i widget Gtk tendono ad essere varianti di altri widget, precedentemente
6566 scritti. Così, anche se questa sezione è intitolata ``Creare
6567 un widget a partire da zero", il nostro widget inizia in realtà con il codice
6568 sorgente del widget Range. Questo è stato preso come punto d'inizio
6569 perche' sarebbe carino se il nostro widget avesse la
6570 stessa interfaccia del widget Scale il quale è semplicemente una
6571 specializzazione del widget Range. Così, sebbene il codice sorgente e'
6572 presentato sotto in forma definitiva, non si deve pensare che sia stato
6573 scritto <em>deus ex machina</em> in questo modo. Se poi non avete familiarità
6574 con il funzionamento del widget Scale dal punto di vista di chi scrive
6575 un'applicazione, potrebbe essere una buona idea guardare indietro prima
6581 Una parte del nostro widget potrebbe essere simile
6582 al widget Tictactoe. In primo luogo, abbiamo il file header:
6585 /* GTK - The GIMP Toolkit
6586 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
6588 * This library is free software; you can redistribute it and/or
6589 * modify it under the terms of the GNU Library General Public
6590 * License as published by the Free Software Foundation; either
6591 * version 2 of the License, or (at your option) any later version.
6593 * This library is distributed in the hope that it will be useful,
6594 * but WITHOUT ANY WARRANTY; without even the implied warranty of
6595 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6596 * Library General Public License for more details.
6598 * You should have received a copy of the GNU Library General Public
6599 * License along with this library; if not, write to the Free
6600 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
6603 #ifndef __GTK_DIAL_H__
6604 #define __GTK_DIAL_H__
6606 #include <gdk/gdk.h>
6607 #include <gtk/gtkadjustment.h>
6608 #include <gtk/gtkwidget.h>
6613 #endif /* __cplusplus */
6616 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
6617 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
6618 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
6621 typedef struct _GtkDial GtkDial;
6622 typedef struct _GtkDialClass GtkDialClass;
6628 /* Politica di update (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
6631 /* Bottone correntemente premuto o 0 altrimenti */
6634 /* Dimensione della componente Dial. */
6638 /* ID del timer di update, o 0 altrimenti */
6641 /* Angolo corrente. */
6644 /* Vecchi valori dell'aggiustamento così sappiamo quando
6645 * qualcosa cambia */
6650 /* L'oggetto adjustament che memorizza i dati per questo dial */
6651 GtkAdjustment *adjustment;
6654 struct _GtkDialClass
6656 GtkWidgetClass parent_class;
6660 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
6661 guint gtk_dial_get_type (void);
6662 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
6663 void gtk_dial_set_update_policy (GtkDial *dial,
6664 GtkUpdateType policy);
6666 void gtk_dial_set_adjustment (GtkDial *dial,
6667 GtkAdjustment *adjustment);
6670 #endif /* __cplusplus */
6673 #endif /* __GTK_DIAL_H__ */
6677 Essendoci più cose da fare con questo widget, rispetto al precedente,
6678 abbiamo più cambi nella struttura dati, ma le altre cose sono
6683 Dopo aver incluso i file di header e aver dichiarato alcune costanti,
6684 dobbiamo fornire alcune funzioni circa il widget e la sua
6690 #include <gtk/gtkmain.h>
6691 #include <gtk/gtksignal.h>
6693 #include "gtkdial.h"
6695 #define SCROLL_DELAY_LENGTH 300
6696 #define DIAL_DEFAULT_SIZE 100
6698 /* Dichiarazioni di funzioni successive */
6700 [ omesse per salvare spazio ]
6702 /* variabili locali. */
6704 static GtkWidgetClass *parent_class = NULL;
6707 gtk_dial_get_type ()
6709 static guint dial_type = 0;
6713 GtkTypeInfo dial_info =
6717 sizeof (GtkDialClass),
6718 (GtkClassInitFunc) gtk_dial_class_init,
6719 (GtkObjectInitFunc) gtk_dial_init,
6723 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
6730 gtk_dial_class_init (GtkDialClass *class)
6732 GtkObjectClass *object_class;
6733 GtkWidgetClass *widget_class;
6735 object_class = (GtkObjectClass*) class;
6736 widget_class = (GtkWidgetClass*) class;
6738 parent_class = gtk_type_class (gtk_widget_get_type ());
6740 object_class->destroy = gtk_dial_destroy;
6742 widget_class->realize = gtk_dial_realize;
6743 widget_class->expose_event = gtk_dial_expose;
6744 widget_class->size_request = gtk_dial_size_request;
6745 widget_class->size_allocate = gtk_dial_size_allocate;
6746 widget_class->button_press_event = gtk_dial_button_press;
6747 widget_class->button_release_event = gtk_dial_button_release;
6748 widget_class->motion_notify_event = gtk_dial_motion_notify;
6752 gtk_dial_init (GtkDial *dial)
6755 dial->policy = GTK_UPDATE_CONTINUOUS;
6758 dial->pointer_width = 0;
6760 dial->old_value = 0.0;
6761 dial->old_lower = 0.0;
6762 dial->old_upper = 0.0;
6763 dial->adjustment = NULL;
6767 gtk_dial_new (GtkAdjustment *adjustment)
6771 dial = gtk_type_new (gtk_dial_get_type ());
6774 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
6776 gtk_dial_set_adjustment (dial, adjustment);
6778 return GTK_WIDGET (dial);
6782 gtk_dial_destroy (GtkObject *object)
6786 g_return_if_fail (object != NULL);
6787 g_return_if_fail (GTK_IS_DIAL (object));
6789 dial = GTK_DIAL (object);
6791 if (dial->adjustment)
6792 gtk_object_unref (GTK_OBJECT (dial->adjustment));
6794 if (GTK_OBJECT_CLASS (parent_class)->destroy)
6795 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
6799 Notate che questa funzione <tt/init()/ fa meno rispetto all'analoga del
6800 widget Tictactoe, essendo questo un widget non composto, e la
6801 funzione <tt/new()/ fa di più, essendoci un argomento. Inoltre,
6802 notate che quando memorizziamo un puntatore all'oggetto Adjustment,
6803 incrementiamo il conteggio dei suoi riferimenti(e corrispondentemente
6804 lo decrementato quando non lo usiamo più) così che GTK può tener traccia di
6805 quando è possibile distruggerlo senza causare guai.
6808 Inoltre, ci sono alcune funzioni per manipolare le opzioni del widget:
6812 gtk_dial_get_adjustment (GtkDial *dial)
6814 g_return_val_if_fail (dial != NULL, NULL);
6815 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
6817 return dial->adjustment;
6821 gtk_dial_set_update_policy (GtkDial *dial,
6822 GtkUpdateType policy)
6824 g_return_if_fail (dial != NULL);
6825 g_return_if_fail (GTK_IS_DIAL (dial));
6827 dial->policy = policy;
6831 gtk_dial_set_adjustment (GtkDial *dial,
6832 GtkAdjustment *adjustment)
6834 g_return_if_fail (dial != NULL);
6835 g_return_if_fail (GTK_IS_DIAL (dial));
6837 if (dial->adjustment)
6839 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
6840 gtk_object_unref (GTK_OBJECT (dial->adjustment));
6843 dial->adjustment = adjustment;
6844 gtk_object_ref (GTK_OBJECT (dial->adjustment));
6846 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
6847 (GtkSignalFunc) gtk_dial_adjustment_changed,
6849 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
6850 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
6853 dial->old_value = adjustment->value;
6854 dial->old_lower = adjustment->lower;
6855 dial->old_upper = adjustment->upper;
6857 gtk_dial_update (dial);
6861 <sect2> <tt/gtk_dial_realize()/
6864 Abbiamo ora raggiunto alcuni nuovi tipi di funzione. In primo luogo,
6865 abbiamo una funzione che crea la finestra di X. Noterete che viene
6866 passata alla funzione <tt/gdk_window_new()/ una maschera che
6867 specifica quali campi della struttura GdkWindowAttr non sono vuoti
6868 (ai rimanenti campi può essere dato il valore predefinito). Anche
6869 il modo con cui la maschera degli eventi del widget creata non è
6870 complicato. Chiameremo <tt/gtk_widget_get_events()/ per sapere la
6871 maschera degli eventi che l'utente ha specificato per questo widget
6872 (con <tt/gtk_widget_set_events()/) e aggiungeremo gli eventi che ci possono
6876 Dopo aver creato la finestra, settiamo lo stile e lo sfondo,
6877 e creiamo un puntatore al widget nel campo dei dati utente (user data)
6878 del GdkWindow. Quest'ultimo passo permette a GTK di mandare gli
6879 eventi della finestra al widget corretto.
6883 gtk_dial_realize (GtkWidget *widget)
6886 GdkWindowAttr attributes;
6887 gint attributes_mask;
6889 g_return_if_fail (widget != NULL);
6890 g_return_if_fail (GTK_IS_DIAL (widget));
6892 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
6893 dial = GTK_DIAL (widget);
6895 attributes.x = widget->allocation.x;
6896 attributes.y = widget->allocation.y;
6897 attributes.width = widget->allocation.width;
6898 attributes.height = widget->allocation.height;
6899 attributes.wclass = GDK_INPUT_OUTPUT;
6900 attributes.window_type = GDK_WINDOW_CHILD;
6901 attributes.event_mask = gtk_widget_get_events (widget) |
6902 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
6903 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
6904 GDK_POINTER_MOTION_HINT_MASK;
6905 attributes.visual = gtk_widget_get_visual (widget);
6906 attributes.colormap = gtk_widget_get_colormap (widget);
6908 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
6909 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
6911 widget->style = gtk_style_attach (widget->style, widget->window);
6913 gdk_window_set_user_data (widget->window, widget);
6915 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
6919 <sect2> Negoziazione della dimensione
6922 Prima di visualizzare per la prima volta la finestra, e se il
6923 layout della finestra cambia, GTK chiede ad ogni widget, incluso nella
6924 finestra, la propria dimensione. Questa richiesta è fatta dalla
6925 funzione <tt/gtk_dial_size_request()/. Non essendo il nostro widget
6926 un contenitore, e non avendo dei veri limiti per la propria
6927 dimensione, restituiamo semplicemnte un valore ragionevole.
6931 gtk_dial_size_request (GtkWidget *widget,
6932 GtkRequisition *requisition)
6934 requisition->width = DIAL_DEFAULT_SIZE;
6935 requisition->height = DIAL_DEFAULT_SIZE;
6940 Dopo che tutti i widget hanno restituito una dimensione ideale, viene
6941 calcolata la disposizione della finestra e ad ogni widget figlio è
6942 notificata la propria dimensione attuale <!--ndMichel : che può essere diversa
6943 da quella restitutita con la funzione sopra -->. Usualmente, questo sarà
6944 almeno quanto richiesto, ma occasionalmente può essere più piccolo.
6945 La notifica della dimensione viene fatta dalla funzione
6946 <tt/gtk_dial_size_allocate()/. Notate che questa funzione è utilizzata
6947 anche quando la finestra X del widget è spostata o modificata come
6952 gtk_dial_size_allocate (GtkWidget *widget,
6953 GtkAllocation *allocation)
6957 g_return_if_fail (widget != NULL);
6958 g_return_if_fail (GTK_IS_DIAL (widget));
6959 g_return_if_fail (allocation != NULL);
6961 widget->allocation = *allocation;
6962 if (GTK_WIDGET_REALIZED (widget))
6964 dial = GTK_DIAL (widget);
6966 gdk_window_move_resize (widget->window,
6967 allocation->x, allocation->y,
6968 allocation->width, allocation->height);
6970 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
6971 dial->pointer_width = dial->radius / 5;
6976 <sect2> <tt/gtk_dial_expose()/
6979 Come menzionato sopra, tutto il lavoro di questo widget viene fatto nella
6980 gestione dell'evento ``expose''. Non c'è molto da notare su questo eccetto
6981 l'uso della funzione <tt/gtk_draw_polygon/ per disegnare il
6982 puntatore con un'ombreggiatura a tre dimensioni in accordo con il colore
6983 memorizzato nello stile del wiget.
6987 gtk_dial_expose (GtkWidget *widget,
6988 GdkEventExpose *event)
6998 g_return_val_if_fail (widget != NULL, FALSE);
6999 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
7000 g_return_val_if_fail (event != NULL, FALSE);
7002 if (event->count > 0)
7005 dial = GTK_DIAL (widget);
7007 gdk_window_clear_area (widget->window,
7009 widget->allocation.width,
7010 widget->allocation.height);
7012 xc = widget->allocation.width/2;
7013 yc = widget->allocation.height/2;
7017 for (i=0; i<25; i++)
7019 theta = (i*M_PI/18. - M_PI/6.);
7023 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
7025 gdk_draw_line (widget->window,
7026 widget->style->fg_gc[widget->state],
7027 xc + c*(dial->radius - tick_length),
7028 yc - s*(dial->radius - tick_length),
7029 xc + c*dial->radius,
7030 yc - s*dial->radius);
7035 s = sin(dial->angle);
7036 c = cos(dial->angle);
7039 points[0].x = xc + s*dial->pointer_width/2;
7040 points[0].y = yc + c*dial->pointer_width/2;
7041 points[1].x = xc + c*dial->radius;
7042 points[1].y = yc - s*dial->radius;
7043 points[2].x = xc - s*dial->pointer_width/2;
7044 points[2].y = yc - c*dial->pointer_width/2;
7046 gtk_draw_polygon (widget->style,
7057 <sect2> Gestore degli eventi
7061 Il resto del codice del widget manipola vari tipi di eventi, e non
7062 è differente da quello che può essere trovato in molte applicazione
7063 GTK. Due tipi di eventi possono verificarsi: l'utente può
7064 clickare sul widget con il mouse e trascinare per muovere il puntatore,
7065 o il valore dell'oggetto Adjustmente può cambiare a causa di alcune
7066 circostanze esterne.
7069 Quando l'utente clicka sul widget, noi vediamo se la pressione
7070 era veramente vicina al puntatore, e se così, memorizziamo il bottone
7071 premuto dall'utente con il campo <tt/button/ della struttura del
7072 widget, e prendiamo tutti gli eventi del mouse con una chiamata alla
7073 funzione <tt/gtk_grab_add()/. Successivi movimenti del mouse causano il
7074 ricalcolo dei valori di controllo (fatto dalla funzione
7075 <tt/gtk_dial_update_mouse/). Dipendentemente dalla politica che abbiamo
7076 stabilito, gli eventi ``value_changed'' possono essere generati
7077 istantaneamente (<tt/GTK_UPDATE_CONTINUOUS/), dopo un certo tempo aggiunto
7078 con la funzione <tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), o
7079 solamente quando il bottone del mouse e' rilasciato
7080 (<tt/GTK_UPDATE_DISCONTINUOUS/).
7084 gtk_dial_button_press (GtkWidget *widget,
7085 GdkEventButton *event)
7091 double d_perpendicular;
7093 g_return_val_if_fail (widget != NULL, FALSE);
7094 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
7095 g_return_val_if_fail (event != NULL, FALSE);
7097 dial = GTK_DIAL (widget);
7099 /* Determina se il bottone premuto era dentro la regione del puntatore:
7100 lo facciamo calcolando la distanza parallela e
7101 perpendicolare dal punto dove il bottone del mouse e' stato premuto
7102 alla linea passante per il puntatore. */
7104 dx = event->x - widget->allocation.width / 2;
7105 dy = widget->allocation.height / 2 - event->y;
7107 s = sin(dial->angle);
7108 c = cos(dial->angle);
7110 d_parallel = s*dy + c*dx;
7111 d_perpendicular = fabs(s*dx - c*dy);
7113 if (!dial->button &&
7114 (d_perpendicular < dial->pointer_width/2) &&
7115 (d_parallel > - dial->pointer_width))
7117 gtk_grab_add (widget);
7119 dial->button = event->button;
7121 gtk_dial_update_mouse (dial, event->x, event->y);
7128 gtk_dial_button_release (GtkWidget *widget,
7129 GdkEventButton *event)
7133 g_return_val_if_fail (widget != NULL, FALSE);
7134 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
7135 g_return_val_if_fail (event != NULL, FALSE);
7137 dial = GTK_DIAL (widget);
7139 if (dial->button == event->button)
7141 gtk_grab_remove (widget);
7145 if (dial->policy == GTK_UPDATE_DELAYED)
7146 gtk_timeout_remove (dial->timer);
7148 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
7149 (dial->old_value != dial->adjustment->value))
7150 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
7157 gtk_dial_motion_notify (GtkWidget *widget,
7158 GdkEventMotion *event)
7161 GdkModifierType mods;
7164 g_return_val_if_fail (widget != NULL, FALSE);
7165 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
7166 g_return_val_if_fail (event != NULL, FALSE);
7168 dial = GTK_DIAL (widget);
7170 if (dial->button != 0)
7175 if (event->is_hint || (event->window != widget->window))
7176 gdk_window_get_pointer (widget->window, &x, &y, &mods);
7178 switch (dial->button)
7181 mask = GDK_BUTTON1_MASK;
7184 mask = GDK_BUTTON2_MASK;
7187 mask = GDK_BUTTON3_MASK;
7195 gtk_dial_update_mouse (dial, x,y);
7202 gtk_dial_timer (GtkDial *dial)
7204 g_return_val_if_fail (dial != NULL, FALSE);
7205 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
7207 if (dial->policy == GTK_UPDATE_DELAYED)
7208 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
7214 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
7219 g_return_if_fail (dial != NULL);
7220 g_return_if_fail (GTK_IS_DIAL (dial));
7222 xc = GTK_WIDGET(dial)->allocation.width / 2;
7223 yc = GTK_WIDGET(dial)->allocation.height / 2;
7225 old_value = dial->adjustment->value;
7226 dial->angle = atan2(yc-y, x-xc);
7228 if (dial->angle < -M_PI/2.)
7229 dial->angle += 2*M_PI;
7231 if (dial->angle < -M_PI/6)
7232 dial->angle = -M_PI/6;
7234 if (dial->angle > 7.*M_PI/6.)
7235 dial->angle = 7.*M_PI/6.;
7237 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
7238 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
7240 if (dial->adjustment->value != old_value)
7242 if (dial->policy == GTK_UPDATE_CONTINUOUS)
7244 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
7248 gtk_widget_draw (GTK_WIDGET(dial), NULL);
7250 if (dial->policy == GTK_UPDATE_DELAYED)
7253 gtk_timeout_remove (dial->timer);
7255 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
7256 (GtkFunction) gtk_dial_timer,
7265 Cambiamenti esterni all'Adjustment sono comunicati al nostro widget
7266 dai segnali ``changed'' e ``value_changed''. Il gestore per
7267 queste funzioni chiama <tt/gtk_dial_update()/ per validare gli
7268 argomenti, calcolare il nuovo angolo del puntatore e ridisegnare il
7269 widget (chiamando <tt/gtk_widget_draw()/).
7273 gtk_dial_update (GtkDial *dial)
7277 g_return_if_fail (dial != NULL);
7278 g_return_if_fail (GTK_IS_DIAL (dial));
7280 new_value = dial->adjustment->value;
7282 if (new_value < dial->adjustment->lower)
7283 new_value = dial->adjustment->lower;
7285 if (new_value > dial->adjustment->upper)
7286 new_value = dial->adjustment->upper;
7288 if (new_value != dial->adjustment->value)
7290 dial->adjustment->value = new_value;
7291 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
7294 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
7295 (dial->adjustment->upper - dial->adjustment->lower);
7297 gtk_widget_draw (GTK_WIDGET(dial), NULL);
7301 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
7306 g_return_if_fail (adjustment != NULL);
7307 g_return_if_fail (data != NULL);
7309 dial = GTK_DIAL (data);
7311 if ((dial->old_value != adjustment->value) ||
7312 (dial->old_lower != adjustment->lower) ||
7313 (dial->old_upper != adjustment->upper))
7315 gtk_dial_update (dial);
7317 dial->old_value = adjustment->value;
7318 dial->old_lower = adjustment->lower;
7319 dial->old_upper = adjustment->upper;
7324 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
7329 g_return_if_fail (adjustment != NULL);
7330 g_return_if_fail (data != NULL);
7332 dial = GTK_DIAL (data);
7334 if (dial->old_value != adjustment->value)
7336 gtk_dial_update (dial);
7338 dial->old_value = adjustment->value;
7343 <sect2> Possibili Miglioramenti
7347 Il widget Dial, da come l'abbiamo costruito, è lungo circa 670 linee
7348 di codice C. Anche se questo potrebbe sembrare un po' troppo, abbiamo
7349 realmente fatto un bel po' con quel tanto di codice, specialmente
7350 considerando che molta della lunghezza è costituita da file header e
7351 commmenti. Comunque ci sono alcuni miglioramenti che potrebbero essere
7352 fatti a questo widget:
7355 <item> Se tu provate questo widget, troverete che ci sono alcuni lampeggiamenti
7356 quando il puntatore viene trascinato in giro. Questo
7357 perchè l'intero widget è cancellato ogni volta che il
7358 puntatore viene mosso, prima di essere ridisegnato. Spesso, il modo migliore
7359 per gestire questo tipo di problema è il disegnare il tutto su una
7360 pixmap non visibile, poi copiare il risultato finale sullo schermo
7361 in una passata sola (il widget ProgressBar viene disegnato in questo
7364 <item> L'utente potrebbe essere abilitato ad usare le frecce su e giu per
7365 incrementare e diminuire il valore.
7367 <item> Potrebbe essere carino se il widget avesse i bottoni per
7368 incrementare e decrementare il valore di step. Anche se potrebbe essere
7369 possibile usare dei widget Bottone incorporati per questo, possiamo anche
7370 far sì che il bottone sia auto-ripentente quando premuto, come le frecce
7371 in una barra di scorrimento. Molto del codice per implementare questo tipo di
7372 comportamento può essere trovato nel widget GtkRange.
7374 <item> il widget Dial potrebbe essere fatto/creato dentro un widget
7375 contenitore con un singolo widget figlio posizionato all'inizio tra i
7376 2 bottoni menzionati prima. L'utente potrebbe poi aggiungere o una etichetta
7377 o un widget ``entry'' per mostrare il valore corrente del dial.
7381 <sect1> Impararne di più
7384 Fin qui abbiamo esposto solo una piccola parte di tutto quello che serve
7385 per creare un widget. Se volete davvero scrivere un vostro widget, la
7386 miglior risorsa di esempi è lo stesso codice sorgente GTK. Chiedete a voi
7387 stessi alcune cose su come deve essere il widget che volete scrivere: è
7388 un widget contenitore? dovrà avere una propria finestra? è una modifica di
7389 un widget precedente? Trovate poi un widget simile e iniziate a fargli
7394 <sect>Scribble, Un semplice esempio di Programma di Disegno
7399 In questa sezione, creeremo un semplice programma di disegno. Durante
7400 questo processo, esamineremo come gestire gli eventi generati dal mouse,
7401 come disegnare all'interno di una finestra e come disegnare in modo migliore
7402 usando una pixmap di supporto. Dopo averlo creato, lo amplieremo aggiungendo
7403 il supporto per i dispositivi XInput, per esempio le tavolette grafiche.
7404 Il GTK fornisce delle routine di supporto grazie alle quali risulta piuttosto
7405 semplice ottenere informazioni estese, come la pressione o l'inclinazione.
7407 <sect1> Gestione degli Eventi
7410 I segnali di GTK che abbiamo discusso finora si riferivano ad azioni di
7411 alto livello, ad esempio la selezione di un elemento di un menù. Però, a volte
7412 è utile sapere qualcosa su cose che si svolgono a livello più basso livello,
7413 come possono essere il movimento del mouse o la pressione di un tasto.
7414 Ci sono segnali di GTK anche per questi <em>eventi</em> di basso livello.
7415 I gestori di questo tipo di segnali hanno un parametro caratteristico in più,
7416 che è il puntatore ad una struttura che contiene informazioni riguardo
7417 all'evento. Per esempio, ai gestori di eventi che riguardano dei movimenti,
7418 si passa un puntatore ad una struttura GdkEventMotion, che è fatta (in parte)
7422 struct _GdkEventMotion
7435 <tt/type/ avrà il valore del tipo di evento, in questo caso
7436 <tt/GDK_MOTION_NOTIFY/, <tt/window/ rappresenta la finestra in cui l'evento
7437 si è verificato. <tt/x/ e <tt/y/ forniscono le coordinate dell'evento e
7438 <tt/state/ specifica lo stato dei modificatori nel momento in cui l'evento
7439 si è verificato (cioè, specifica quali tasti modificatori e tasti del mouse
7440 erano premuti in quel momento). E' un OR bit per bit dei seguenti valori:
7459 Come succede per gli altri segnali, per determinare cosa deve accadere in
7460 corrispondenza di un evento, si chiama <tt>gtk_signal_connect()</tt>. Ma
7461 è anche necessario far sì che GTK sappia di quali eventi vogliamo essere
7462 informati. A questo fine, chiamiamo la funzione:
7465 void gtk_widget_set_events (GtkWidget *widget, gint events);
7468 Il secondo campo specifica gli eventi che ci interessano. Si tratta dell'OR
7469 bit per bit delle costanti che identificano i diversi tipi di eventi. La lista
7470 dei tipi di eventi è la seguente:
7474 GDK_POINTER_MOTION_MASK
7475 GDK_POINTER_MOTION_HINT_MASK
7476 GDK_BUTTON_MOTION_MASK
7477 GDK_BUTTON1_MOTION_MASK
7478 GDK_BUTTON2_MOTION_MASK
7479 GDK_BUTTON3_MOTION_MASK
7480 GDK_BUTTON_PRESS_MASK
7481 GDK_BUTTON_RELEASE_MASK
7483 GDK_KEY_RELEASE_MASK
7484 GDK_ENTER_NOTIFY_MASK
7485 GDK_LEAVE_NOTIFY_MASK
7486 GDK_FOCUS_CHANGE_MASK
7488 GDK_PROPERTY_CHANGE_MASK
7489 GDK_PROXIMITY_IN_MASK
7490 GDK_PROXIMITY_OUT_MASK
7493 Per chiamare <tt/gtk_widget_set_events()/, si devono fare alcune osservazioni
7494 sottili. In primo luogo, la si deve chiamare prima che sia stata creata la
7495 finestra X per il widget GTK. In pratica, ciò significa che la si deve
7496 chiamare subito dopo aver creato il widget. In secondo luogo, il widget
7497 deve avere una finestra X associata. Molti widget, per ragioni di
7498 efficienza, non hanno una propria finetra, e vengono mostrati nella
7499 finestra madre. Questi widget sono:
7525 Per catturare degli eventi per questo tipo di widget, si deve fare uso
7526 del widget EventBox. Si veda a questo proposito la sezione su
7527 <ref id="sec_The_EventBox_Widget" name="The EventBox Widget">.
7530 Per il nostro programma di disegno, vogliamo sapere quando il pulsante del
7531 mouse è premuto e quando viene mosso, quindi specificheremo
7532 <tt/GDK_POINTER_MOTION_MASK/ e <tt/GDK_BUTTON_PRESS_MASK/. Vogliamo anche
7533 essere informati su quando è necessario ridisegnare la nostra finestra,
7534 quindi specifichiamo <tt/GDK_EXPOSURE_MASK/. Anche se vogliamo essere
7535 avvertiti con un evento ``Configure'' se la dimensione della nostra finestra
7536 cambia, non è necessario specificare il flag <tt/GDK_STRUCTURE_MASK/, dal
7537 momento che questo viene specificato automaticamente per tutte le finestre.
7540 Risulta, conunque, che specificando semplicemente <tt/GDK_POINTER_MOTION_MASK/
7541 si crea un problema. Ciò infatti fa sì che il server aggiunga nella coda un
7542 un nuovo evento di movimento ogni volta che l'utente muovoe il mouse. Immaginate
7543 che ci vogliano 0.1 secondi per gestire uno di questi eventi, e che il server
7544 X metta in coda un nuovo evento ogni 0.05 secondi. Rimarremo ben presto indietro
7545 rispetto al disegno dell'utente. Se l'utente disegna per 5 secondi, ci metteremmo
7546 altri 5 secondi prima di finire dopo che l'utente ha rilasciato il pulsante del
7547 mouse! Vorremmo quindi che venga notificato un solo evento di movimento per
7548 ogni evento che processiamo. Il modo per farlo è di specificare
7549 <tt/GDK_POINTER_MOTION_HINT_MASK/.
7552 Quando specifichiamo <tt/GDK_POINTER_MOTION_HINT_MASK/, il server ci notifica
7553 un evento di movimento la prima volta che il puntatore si muove dopo essere
7554 entrato nella nostra finestra, oppure dopo ogni rilascio di un pulsante del
7555 mouse. Gli altri eventi di movimento verranno soppressi finché non richiediamo
7556 esplicitamente la posizione del puntatore con la funzione:
7559 GdkWindow* gdk_window_get_pointer (GdkWindow *window,
7562 GdkModifierType *mask);
7565 (c'è anche un'altra funzione, <tt>gtk_widget_get_pointer()</tt>, che ha
7566 un'interfaccia più semplice, ma che non risulta molto utile dal momento
7567 che restituisce solo la posizione del puntatore, senza dettagli sullo
7571 Quindi, il codice per assegnare gli eventi per la nostra finestra, avrà l'aspetto:
7574 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
7575 (GtkSignalFunc) expose_event, NULL);
7576 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
7577 (GtkSignalFunc) configure_event, NULL);
7578 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
7579 (GtkSignalFunc) motion_notify_event, NULL);
7580 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
7581 (GtkSignalFunc) button_press_event, NULL);
7583 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
7584 | GDK_LEAVE_NOTIFY_MASK
7585 | GDK_BUTTON_PRESS_MASK
7586 | GDK_POINTER_MOTION_MASK
7587 | GDK_POINTER_MOTION_HINT_MASK);
7590 Teniamo per dopo i gestori di ``expose_event'' e ``configure_event''. Quelli di
7591 ``motion_notify_event'' e ``button_press_event'' sono piuttosto semplici:
7595 button_press_event (GtkWidget *widget, GdkEventButton *event)
7597 if (event->button == 1 && pixmap != NULL)
7598 draw_brush (widget, event->x, event->y);
7604 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
7607 GdkModifierType state;
7610 gdk_window_get_pointer (event->window, &x, &y, &state);
7615 state = event->state;
7618 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
7619 draw_brush (widget, x, y);
7626 <sect1> Il widget Area di Disegno (DrawingArea) e il procedimento per Disegnare
7629 Vediamo ora il procedimento per disegnare sullo schermo. Il
7630 widget da usare è l'Area di Disegno (DrawingArea). Essenzialmente si
7631 tratta di una finestra X e nient'altro. E' una tela bianca su cui possimo
7632 disegnare tutto quello che vogliamo. Per crearne una usiamo la chiamata:
7635 GtkWidget* gtk_drawing_area_new (void);
7638 Per specificare una dimensione predefinita, si puo fare:
7641 void gtk_drawing_area_size (GtkDrawingArea *darea,
7646 Come è vero per tutti i widget, si può modificare questa dimensione
7647 predefinita, tramite la chamata a <tt>gtk_widget_set_usize()</tt>, e
7648 questa a sua volta può essere modificata dall'utente ridimensionando
7649 manualmente la finestra che contiene l'area di disegno.
7652 Si deve notare che nel momento in cui creiamo un widget DrawingArea, siamo
7653 <em>completamente</em> responsabili di disegnarne il contenuto. Se ad
7654 esempio la nostra finestra viene prima nascosta e poi dinuovo portata in
7655 primo piano, otteniamo un evento di ``esposizione'' e doppiamo ridisegnare
7656 ciò che era stato precedente nascosto.
7659 Dover ricordare tutto quello che era disegnato sulla finestra in modo da
7660 poterlo ridisegnare successivamente, può essere, come minimo, noioso.
7661 In più, può essere spiacevole dal punto di vista visivo, se delle porzioni
7662 dello schermo vengono prima cancellate e poi ridisegnate passo per passo.
7663 La soluzione per questo problema è di usare una <em>pixmap di supporto</em>.
7664 Invece di disegnare direttamente sullo schermo, disegnamo su un'iimagine
7665 conservata nella memoria del server ma che non viene mostrata; quindi, quando
7666 l'immagine cambia o ne vengono mostrate nuove porzioni, copiamo sullo schermo
7667 le parti corrispondenti.
7670 Per creare una ppixmap fuori dallo schermo, usiamo la funzione:
7673 GdkPixmap* gdk_pixmap_new (GdkWindow *window,
7679 Il parametro <tt>window</tt>specifica una finestra GDK dalla quale questa
7680 pixmap prende alcune delle sue proprietà. <tt>width</tt> e <tt>height</tt>
7681 specificano le dimensioni della pixmap. <tt>depth</tt> specifica la
7682 <em>profondità di colore</em>, cioè il numero di bit per ogni pixel, per
7683 la nuova pixmap. Se alla profondità è assegnato il valore <tt>-1</tt>, questa
7684 verrà posta identica a quella di <tt>window</tt>.
7687 Creiamo la pixmap all'interno del gestore di ``configure_event''. Questo evento
7688 è generato ogni volta che la finestra cambia di dimensione, compreso il
7689 momento in cui viene creata per la prima volta.
7692 /* Pixmap di supporto per l'area di disegno */
7693 static GdkPixmap *pixmap = NULL;
7695 /* Creare una pixmap della dimensione appropriata */
7697 configure_event (GtkWidget *widget, GdkEventConfigure *event)
7701 gdk_pixmap_destroy(pixmap);
7703 pixmap = gdk_pixmap_new(widget->window,
7704 widget->allocation.width,
7705 widget->allocation.height,
7707 gdk_draw_rectangle (pixmap,
7708 widget->style->white_gc,
7711 widget->allocation.width,
7712 widget->allocation.height);
7718 La chiamata a <tt>gdk_draw_rectangle()</tt> inizialmente rende bianca l'intera
7719 pixmap. Fra un momento ne riparleremo.
7722 Il gestore dell'evento ``esposizione'', copia quindi la porzione appropriata
7723 della pixmap sullo schermo (determiniamo qual è l'area da ridisegnare usando
7724 il campo event->area dell'evento di esposizione):
7727 /* Ridisegna sullo schermo a partire dalla pixmap di supporto */
7729 expose_event (GtkWidget *widget, GdkEventExpose *event)
7731 gdk_draw_pixmap(widget->window,
7732 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
7734 event->area.x, event->area.y,
7735 event->area.x, event->area.y,
7736 event->area.width, event->area.height);
7742 Abbiamo quindi visto come tenete aggiornato lo schermo con la nostra
7743 pixmap, ma come facciamo per disegnare delle cose interessanti sulla
7744 pixmap? Ci sono un bel po' di funzioni nella libreria GDK di GTK che
7745 servono per disegnare su superfici <em>disegnabili</em>. Una superficie
7746 disegnabile è semplicemente qualcosa su cui si può disegnare un'immagine.
7747 Può essere una finestra, una pixmap o una bitmap (un'immagine in bianco e
7748 nero). Abbiamo già visto sopra due di chiamate,
7749 <tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. La lista
7750 completa è la seguente:
7754 gdk_draw_rectangle ()
7763 gdk_draw_segments ()
7766 Per ulteriori dettagli su queste funzioni, vedete la documentazione di
7767 riferimento nei file header <tt><gdk/gdk.h></tt>.
7768 Tutte queste funzioni hanno i medesimi primi due argomenti. Il primo
7769 è la superficie disegnabili su cui disegnare, il secondo è un
7770 <em>contesto grafico</em> (GC).
7773 Un contesto grafico incapsula delle informazioni riguardo a cose come
7774 il colore di sfondo e di primo piano e lo spessore della linea.
7775 GDK ha un ampio insieme di funzioni per crare e modificare contesti grafici,
7776 ma per tenere le cose semplici useremo solo dei contesti grafici predefiniti.
7777 Ogni widget ha uno stile associato (che può essere modificato agendo su un
7778 file gtkrc). Questo, fra le altre cose, contiene un certo numero di contesti
7779 grafici. Alcuni esempi di come accedere a questi contesti grafici sono
7783 widget->style->white_gc
7784 widget->style->black_gc
7785 widget->style->fg_gc[GTK_STATE_NORMAL]
7786 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
7789 I campi <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, e
7790 <tt>light_gc</tt> sono indicizzati tramite un parametri di tipo
7791 <tt>GtkStateType</tt>, che può assumere i valori:
7798 GTK_STATE_INSENSITIVE
7801 Per esempio, per <tt/GTK_STATE_SELECTED/ il colore di sfondo predefinito
7802 è blu scuro e quello di primo piano bianco.
7805 La nostra funzione <tt>draw_brush()</tt>, che efettivamente disegna sullo
7806 schermo, diventa quindi:
7809 /* Disegna un rettangolo sullo schermo */
7811 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
7813 GdkRectangle update_rect;
7815 update_rect.x = x - 5;
7816 update_rect.y = y - 5;
7817 update_rect.width = 10;
7818 update_rect.height = 10;
7819 gdk_draw_rectangle (pixmap,
7820 widget->style->black_gc,
7822 update_rect.x, update_rect.y,
7823 update_rect.width, update_rect.height);
7824 gtk_widget_draw (widget, &update_rect);
7828 Dopo aver disegnato il rettangolo sulla pixmap, chiamiamo la funzione:
7831 void gtk_widget_draw (GtkWidget *widget,
7832 GdkRectangle *area);
7835 che notifica a X che l'area data dal parametro <tt>area</tt> deve essere
7836 aggiornata. X poi genererà un evento di esposizione (che può essere combinato
7837 con le aree passate da diverse chiamate a <tt>gtk_widget_draw()</tt>) che
7838 farà sì che il nostro gestore dell'evento di esposizione, copi le porzioni
7839 rilevanti sullo schermo.
7842 Abbiamo a questo punto creato tutto il programma di disegno, tranne che
7843 per qualche dettaglio irrilevante come la creazione della finestra principale.
7844 Il codice sorgente completo è reperibile dove avete ottenuto questo tutorial.
7846 <sect1> Aggiungere il supporto per XInput
7849 Al giorno d'oggi è possibile acquistare dei dispositivi abbastanza a buon
7850 mercato, come tavolette grafice, che permettono di disegnare con una
7851 espressività artistica molto semplificata rispetto ad un mouse.
7852 Il modo più semplice per usare questi dispositivi è di sostituirli
7853 semplicemente al mouse, ma in questo modo si perdono molti dei loro
7857 <item> Sensibilità alla pressione
7858 <item> Sensibilità all'inclinazione
7859 <item> Posizionamento infra-pixel
7860 <item> Ingressi multipli (per esempio, uno stilo che contiene sia una ``matita''
7864 Per ulteriori informazioni sulle estensioni XInput, vedere l'<url
7865 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
7866 name="XInput-HOWTO">.
7869 Se esaminiamo, per esempio, la definizione completa della struttura
7870 GdkEventMotion, possiamo vedere che contiene dei campi per il supporto
7871 delle informazioni estese dai dispositivi.
7874 struct _GdkEventMotion
7886 GdkInputSource source;
7891 <tt/pressure/ fornisce la pressione sotto forma di un numero decimale
7892 compreso fra 0 e 1. <tt/xtilt/ e <tt/ytilt/ possono assumere valori
7893 compresi fra -1 e 1, corrispondenti al grado di inclinazione in ciascuna
7894 direzione. <tt/source/ e <tt/deviceid/ specificano il dispositivo per il
7895 quale si è verificato l'evento in due modi distinti. <tt/source/ da alcune
7896 semplici informazioni sul tipo di dispositivo, e può assumere i valori:
7905 <tt/deviceid/ specifica invece un identificativo numerico univoco per il
7906 dispositivo. Questo può essere a sua volta utilizzato per avere ulteriori
7907 informazioni sul dispositivo tramite la chiamata a <tt/gdk_input_list_devices()/
7908 (vedi sotto). Il valore speciale <tt/GDK_CORE_POINTER/ viene usato per identificare
7909 il dispositivo di puntamento principale (di solito il mouse).
7911 <sect2> Abilitare le informazioni estese
7914 Per far sì che GTK sappia che ci interessano le informazioni estese dai
7915 dispositivi, basta aggiungere un'unica linea al nostro programma:
7918 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
7921 Dando il valore <tt/GDK_EXTENSION_EVENTS_CURSOR/, diciamo che ci interessano
7922 gli eventi relativi alle estensioni, ma solo se non dobbiamo disegnare da noi
7923 il nostro cursore. Si veda più sotto alla sezione <ref
7924 id="sec_Further_Sophistications" name="Ulteriori Sofisticazioni"> per ulteriori
7925 informazioni sul modo si disegnare i cursori. Potremmo anche dare i valori
7926 <tt/GDK_EXTENSION_EVENTS_ALL/ se vogliamo disegnare il nostro cursore o
7927 <tt/GDK_EXTENSION_EVENTS_NONE/ se vogliamo tornare alle condizioni predefinite.
7930 Comunque, non finisce tutto qui. Non ci sono estensioni abilitate per difetto.
7931 Abbiamo bisogno di un meccanismo per permettere agli utenti l'abilitazione e
7932 la configurazione delle estensioni dei loro dispositivi, GTK fornisce il
7933 widget InputDialog per automatizzare questo processo. La seguente procedura
7934 mostra come gestire un widget InputDialog. Crea la finestra di dialogo nel
7935 caso non sia presente, mentre la porta in primo piano in caso contrario.
7939 input_dialog_destroy (GtkWidget *w, gpointer data)
7941 *((GtkWidget **)data) = NULL;
7945 create_input_dialog ()
7947 static GtkWidget *inputd = NULL;
7951 inputd = gtk_input_dialog_new();
7953 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
7954 (GtkSignalFunc)input_dialog_destroy, &inputd);
7955 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
7957 (GtkSignalFunc)gtk_widget_hide,
7958 GTK_OBJECT(inputd));
7959 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
7961 gtk_widget_show (inputd);
7965 if (!GTK_WIDGET_MAPPED(inputd))
7966 gtk_widget_show(inputd);
7968 gdk_window_raise(inputd->window);
7973 (Notate come gestiamo questo dialogo. Con la connessione del segnale
7974 ``destroy'' ci assicuriamo di non tenerci in giro il puntatore al dialogo
7975 dopo che lo abbiamo distrutto, cosa che potrebbe portare ad un errore di
7979 L'InputDialog ha due pulsanti, ``Close'' e ``Save'', i quali non hanno alcuna
7980 azione predefinita assegnata ad essi. Nella funzione precedente, abbiamo
7981 fatto in modo che ``Close'' nasconda la finestra di dialogo, e abbiamo nascosto
7982 il pulsante ``Save'' dal momento che in questo programma non implementiamo il
7983 salvataggio delle opzioni di XInput.
7985 <sect2> Usare le informazioni estese
7988 Una volta abilitato il dipositivo, possiamo usare le informazioni estese
7989 che si trovano nei corrispondenti campi delle strutture che descrivono gli
7990 eventi. A dire il vero, l'utilizzo di questi campi è sempre sicuro, perché
7991 sono tutti posti per difetto a valori ragionevoli ancje quando la gestione
7992 degli eventi estesi non è abilitata.
7995 Un cambiamento che dobbiamo fare è di chiamare <tt/gdk_input_window_get_pointer()/
7996 invece di <tt/gdk_window_get_pointer/. Ciò si rende necessario perché
7997 <tt/gdk_window_get_pointer/ non restituisce le informazioni esetese.
8000 void gdk_input_window_get_pointer (GdkWindow *window,
8007 GdkModifierType *mask);
8010 Quando chiamiamo questa funzione, dobbiamo specificare l'identificativo
8011 del dispositivo e la finestra. Normalmente questo identificativo lo si
8012 ottiene dal campo <tt/deviceid/ della struttura dell'evento.
8013 Questa funzione restituirà valori ragionevoli nel caso che la gestione
8014 degli eventi estesi non sia attivata (in questo caso, <tt/event->deviceid/
8015 avrà il valore <tt/GDK_CORE_POINTER/).
8017 Quindi, la struttura di base dei gestori degli eventi relativi alla
8018 pressione di bottoni e ai movomenti non cambia molto - abbiamo solo
8019 bisogno di aggiungere il codice necessario per tenere conto delle
8020 informazioni estese.
8024 button_press_event (GtkWidget *widget, GdkEventButton *event)
8026 print_button_press (event->deviceid);
8028 if (event->button == 1 && pixmap != NULL)
8029 draw_brush (widget, event->source, event->x, event->y, event->pressure);
8035 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
8039 GdkModifierType state;
8042 gdk_input_window_get_pointer (event->window, event->deviceid,
8043 &x, &y, &pressure, NULL, NULL, &state);
8048 pressure = event->pressure;
8049 state = event->state;
8052 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
8053 draw_brush (widget, event->source, x, y, pressure);
8059 Avremo anche bisogno di fare qualcosa con queste nuove informazioni. La
8060 nostra nuova funzione <tt/draw_brush/ disegna con un colore diverso per
8061 ogni <tt/event->source/ e cambia la dimensione della linea in funzione
8065 /* Disegna un rettangolo sullo schermo, con la dimensione dipendente
8066 dalla pressione e il colore dipendente dal tipo di dispositivo */
8068 draw_brush (GtkWidget *widget, GdkInputSource source,
8069 gdouble x, gdouble y, gdouble pressure)
8072 GdkRectangle update_rect;
8076 case GDK_SOURCE_MOUSE:
8077 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
8079 case GDK_SOURCE_PEN:
8080 gc = widget->style->black_gc;
8082 case GDK_SOURCE_ERASER:
8083 gc = widget->style->white_gc;
8086 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
8089 update_rect.x = x - 10 * pressure;
8090 update_rect.y = y - 10 * pressure;
8091 update_rect.width = 20 * pressure;
8092 update_rect.height = 20 * pressure;
8093 gdk_draw_rectangle (pixmap, gc, TRUE,
8094 update_rect.x, update_rect.y,
8095 update_rect.width, update_rect.height);
8096 gtk_widget_draw (widget, &update_rect);
8100 <sect2> Trovare ulteriori informazioni su di un dispositivo
8103 Come esempio del modo di trovare altre informazioni su di un dispositivo,
8104 il nostro programma stamperà il nome di ogni dispositivo che genera un
8105 evento di pressione di un pulsante. Per avere il nome di un dispositivo,
8106 chiamiamo la funzione
8109 GList *gdk_input_list_devices (void);
8112 che restituisce una GList (un tipo di lista collegata che si trova nella
8113 libreria glib) di strutture di tipo GdkDeviceInfo. La definizione di
8114 GdkDeviceInfo è la seguente:
8117 struct _GdkDeviceInfo
8121 GdkInputSource source;
8131 La maggior parte di questi campi rappresentano informazioni di configurazione
8132 che potete ignorare a meno che non implementiate il salvataggio della
8133 configurazione di un XInput. Quelle che ci interessano sono <tt/name/, che
8134 è semplicemente il nome che X assegna al dispositivo, e <tt/has_cursor/. Anche
8135 <tt/has_cursor/ non è informazione di configurazione, e indica, nel caso
8136 abbia valore ``falso'', che dobbiamo disegnare da soli il nostro cursore. Ma
8137 dal momento che abbiamo specificato <tt/GDK_EXTENSION_EVENTS_CURSOR/,
8138 possiamo anche non preoccuparcene.
8142 La nostra funzione <tt/print_button_press()/ scorre semplicemente la lista
8143 che è stata restituita finché non trova il valore corretto, e poi stampa
8144 il nome del dispositivo.
8148 print_button_press (guint32 deviceid)
8152 /* gdk_input_list_devices restituisce una lista interna, così poi
8153 non dobbiamo liberarla */
8154 tmp_list = gdk_input_list_devices();
8158 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
8160 if (info->deviceid == deviceid)
8162 printf("Button press on device '%s'\n", info->name);
8166 tmp_list = tmp_list->next;
8170 Questo completa i cambiamenti necessari per usare gli XInput nel nostro
8171 programma. Come per la prima versione, i sorgenti completi sono prelevabili
8172 da dove avete prelevato questo tutorial.
8174 <sect2> Ulteriori sofisticazioni <label id="sec_Further_Sophistications">
8177 Anche se ora il nostro programma supporta XInput pittosto bene, gli mancano
8178 alcune caratteristiche che probabilmente vorremmo mettere in una applicazione
8179 completa. In primo luogo, probabilmente all'utente non farà piacere dover
8180 configurare i propri dispositivi ogni volta che lanciano il programma, per
8181 cui dovremmo dare la possibilità di salvare la configurazione dei dispositivi.
8182 Ciò può essere fatto scorrendo la lista restituita da <tt/gdk_input_list_devices()/
8183 e scrivendo la configurazione su di un file.
8186 Per tornare allo stato salvato la prossima volta che il programma viene
8187 eseguito, GDK mette a disposizione delle funzioni per cambiare la configurazione
8191 gdk_input_set_extension_events()
8192 gdk_input_set_source()
8193 gdk_input_set_mode()
8194 gdk_input_set_axes()
8198 (La lista restituita da <tt/gdk_input_list_devices()/ non dovrebbe
8199 essere modificata direttamente.) Un esempio di come fare può essere
8200 trovato nel programma di disegno gsumi (disponibile da <htmlurl
8201 url="http://www.msc.cornell.edu/~otaylor/gsumi/"
8202 name="http://www.msc.cornell.edu/~otaylor/gsumi/">). Sarebbe bello
8203 avere alla fine un modo standard di recuperare le informazioni per tutte
8204 le applicazioni. Questo probabilmente appartiene ad un livello un po'
8205 più elevato ripetto a GTK, forse alla libreria GNOME.
8208 Un'altra notevole omissione a cui abbiamo accennato precedentemente è il
8209 fatto di non disegnare il cursore direttamente. Piattaforme diverse da
8210 XFree86 non permettono in questo momento di usare contemporaneamente un
8211 dispositivo sia come puntatore principale sia direttamente da una
8212 applicazione. Vedere <url url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
8213 name="XInput-HOWTO"> per ulteriori informazioni. Ciò significa che le
8214 applicazioni che vogliono rivolgersi al pubblico più ampio dovranno prevedere
8215 di disegnare esse stesse il proprio cursore.
8218 Un'applicazione che voglia disegnare il proprio cursore dovrà fare due cose:
8219 determinare se il dispositivo corrente necessita che venga disegnato un
8220 cursore, e determinare se il dispositivo corrente è in prossimità. (Se il
8221 dispositivo è una tavoletta grafica, un tocco di finezza è fare sparire
8222 il puntatore quando lo stilo viene sollevato dalla tavoletta. Quando c'è
8223 contatto fra lo stilo e la tavoletta, si dice che il dispositivo è ``in
8224 prossimità".) La prima cosa viene fatta scorrendo la lista dei dispositivi,
8225 come abbiamo fatto per trovare il nome del dispositivo. La seconda cosa
8226 viene ottenuta selezionando gli eventi ``proximity_out''. Un esempio di
8227 disegno del proprio cursore si trova nel programma 'testinput' incluso nella
8228 distribuzione di GTK.
8230 <sect>Consigli per scrivere Applicazioni GTK
8234 Questa sezione è semplicemente una raccolta di saggezza, una
8235 guida di stile e un aiuto per creare buone applicazioni GTK. E' totalmente
8236 inutile per ora perché è solamente un appunto.
8238 Usa autoconf e automake! Sono tuoi amici :) Ho intenzione di fare una
8239 piccola introduzione su di loro qui.
8244 Questo documento, come molti altri grandi software fuori di qui, è stato
8245 creato da volontari. Se sai tutto quello che c'è da sapere su GTK e non
8246 lo hai trovato qui allora considera la possibilità di contribuire a questo
8250 Se decidi di contribuire, per favore trasmettimi il tuo testo a
8251 <tt><htmlurl url="mailto:slow@intergate.bc.ca"
8252 name="slow@intergate.bc.ca"></tt>. Inoltre, Si consapevole che l'intero
8253 documento è ``free'', e ogni tua aggiunta sarà considerata allo stesso modo.
8254 Per questo motivo le persone possono usare porzioni dei tuoi esempi nei loro
8255 programmi, copie di questo documento possono essere distribuite all'infinito,
8265 Voglio qui ringraziare le persone che seguono, per il loro contributo
8266 alla stesura di questo testo.
8269 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
8270 name="chamele0n@geocities.com"></tt> per il tutorial sui menù.
8272 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
8273 name="raph@acm.org"></tt>
8274 per il "hello world" alla GTK, l'immpacchettamento del widget, e in generale
8275 per tutta la sua saggezza.
8276 Lui ha anche donato una casa per questo tutorial.
8278 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
8279 name="petm@xcf.berkeley.edu"></tt> Per il più semplice programma GTK e l'abilità
8282 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
8283 name="werner.koch@guug.de"></tt> per la conversione da testo semplice a SGML
8284 e la gerarchia delle classi di widget.
8286 <item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
8287 name="crichton@expert.cc.purdue.edu"></tt> per il codice della "MenuFactory"
8288 e per la parte sull'impacchettamento nelle tabelle del tutorial.
8290 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
8291 name="mailto:owt1@cornell.edu"></tt> per la sezione del widget EventBox
8292 (e il patch alla distribuzione). Lui è anche responsabile per il codice
8293 e il tutorial delle selezioni, come per la sezione sulla scrittura di un
8294 proprio widget, e l'applicazione d'esempio. Grazie di tutto Owen.
8296 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
8297 name="mailto:mailto:mvboom42@calvin.edu"></tt> per il suo meraviglioso lavoro
8298 sul Notebook, Progres Bar, Dialogs e File selection. Grazie molto Mark. Sei
8299 stato di grande aiuto.
8301 <item>Tim Janik <tt><htmlurl url="mailto:timj@psynet.net"
8302 name="mailto:timj@psynet.net"></tt> per il suo grande lavoro sul widget List.
8305 <item> Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
8306 name="johnsonm@redhat.com"> </tt> per le informazioni e il codice dei menu
8311 E a tutti voi che avete fatto commenti e avete aiutato a raffinare questo documento.
8318 This tutorial is Copyright (c) 1997 Ian Main
8320 La traduzione italiana è sotto Copyright (c) 1997-1998 di Michel Morelli,
8321 Daniele Canazza e Antonio Schifano.
8325 This program is free software; you can redistribute it and/or
8326 modify it under the terms of the GNU General Public License
8327 as published by the Free Software Foundation; either version 2
8328 of the License, or (at your option) any later version.
8330 This program is distributed in the hope that it will be useful,
8331 but WITHOUT ANY WARRANTY; without even the implied warranty of
8332 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8333 GNU General Public License for more details.
8335 You should have received a copy of the GNU General Public License
8336 along with this program; if not, write to the Free Software
8337 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.