1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
4
<META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9">
5
<TITLE>GTK Tutorial: Il Widget Menù (Menu Widgets)</TITLE>
6
<LINK HREF="gtk_tut_it-11.html" REL=next>
7
<LINK HREF="gtk_tut_it-9.html" REL=previous>
8
<LINK HREF="gtk_tut_it.html#toc10" REL=contents>
10
<BODY BGCOLOR="#FFFFFF">
11
<A HREF="gtk_tut_it-11.html">Avanti</A>
12
<A HREF="gtk_tut_it-9.html">Indietro</A>
13
<A HREF="gtk_tut_it.html#toc10">Indice</A>
15
<H2><A NAME="s10">10. Il Widget Menù (Menu Widgets)</A></H2>
17
<P>Ci sono due modi per creare dei menù, quello facile e quello difficile.
18
Ognuno è più adatto per certe circostanze, ma di solito si può usare il
19
modo semplice, cioé menu_factory (la ``fabbrica dei menù''). Il modo
20
``difficile'' è di crearsi tutti i menù usando direttamente le chiamate.
21
Quello semplice è di usare le chiamate di tipo gtk_menu_factory. Anche se
22
è un modo molto più semplice, ci sono svantaggi e vantaggi per ciascuno
24
<P>La menu_factory è molto più semplice da usare e per aggiungere dei nuovi
25
menù, anche se scriversi un po' di funzioni per creare dei menù con il
26
metodo manuale può dare risultati molto migliori dal punto di vista
27
dell'usabilità. Con la menufactory, non è possibile mettere immagini o
28
caratteri '/' nei menù.
30
<H2><A NAME="ss10.1">10.1 Creazione Manuale di Menù</A>
33
<P>Seguendo la tradizionale arte dell'insegnamento, partiamo dal modo
34
difficile. <CODE>:)</CODE>
35
<P>I widget che hanno a che fare con la creazione di una barra di menù e di sottomenù sono tre:
37
<LI>un elemento di menù, che \ quello che l'utente poi selezionerà, per esempio 'Salva'</LI>
38
<LI>un menù, che fa la parte di contenitore per gli elementi di menù, e</LI>
39
<LI>una barra dei menù, che è un contenitore per ciascuno dei menù</LI>
42
<P>La cosa viene un po' complicata dal fatto che i widget elemento di menù vngono usati per
43
<P>due scopi diversi. Essi sono sia i widget che vengono impacchettati nei menù, che
44
<P>quelli che vengono impacchettati nella barra dei menù che, quando selezonati, attivano i menù.
45
<P>Diamo un'occhiata alle funzioni usate per creare i menù e le barre di menù.
46
Con questa prima funzione si crea un nuova barra di menù:
51
GtkWidget *gtk_menu_bar_new(void);
54
<P>Questa funzione crea una nuova barra di menù. Per impacchettarla in una
55
finestra o si usa la funzione gtk_container_add, oppure, per impacchettarla
56
in una scatola, le funzioni box_pack - come con i bottoni.
60
GtkWidget *gtk_menu_new();
63
<P>Questa funzione restituisce un puntatore ad un nuovo menù, non viene mai
64
realmente mostrato (con gtk_widget_show), serve solo per contenere gli
65
elementi del menù. Spero che il tutto risulti più chiaro quando daremo
66
un'occhiata all'esempio più sotto.
67
<P>Le prossime due chiamate sono usate per creare degli elementi che poi
68
vengono impacchettati nei menù e nelle barre dei menù..
72
GtkWidget *gtk_menu_item_new();
79
GtkWidget *gtk_menu_item_new_with_label(const char *label);
82
<P>Queste chiamate sono usate per creare gli elementi di menù che devono poi essere mostrati.
83
Ricordate la differenza che esiste fra un ``menù'' come quelli creati con
84
gtk_menu_new e un ``elemento di menù'' (menu item) come quelli creati con
85
la funzione gtk_menu_item_new. L'elemento di menù sarà un bottone
86
vero e proprio con una azione associata, mentre un menù è solo un contenitore che li raccoglie.
87
Le funzioni gtk_menu_new_with_label e gtk_menu_new sono esattamente come vi aspettereste che siano dopo
88
<P>aver conosciuto i bottoni. Una crea un nuovo elemento di menù con un'etichetta già impacchettata,
89
<P>mentre l'altra crea un elemento di menù vuoto.
91
<P>Una volta che si \ creato un elemento di menù, è necessario piazzarlo su di un menù.
92
<P>Per fare ciò si usa la funzione gtk_menu_append. Per determinare quando l'utente ha selezionato un elemento, abbiamo bisogno di connettere il segnale <CODE>activate</CODE> nel solito modo.
93
<P>Quindi, se volessimo creare un normale menù <CODE>File</CODE>, con le opzioni <CODE>Open</CODE>, <CODE>Save</CODE> e <CODE>Quit</CODE>, il codice avrebbe più o meno il seguente aspetto:
97
file_menu = gtk_menu_new(); /* Non e' necessario mostrare i menu' */
99
/* Creiamo gli elementi del menu' */
100
open_item = gtk_menu_item_new_with_label("Open");
101
save_item = gtk_menu_item_new_with_label("Save");
102
quit_item = gtk_menu_item_new_with_label("Quit");
104
/* Aggiungiamoli al menu' */
105
gtk_menu_append( GTK_MENU(file_menu), open_item);
106
gtk_menu_append( GTK_MENU(file_menu), save_item);
107
gtk_menu_append( GTK_MENU(file_menu), quit_item);
110
/* Colleghiamo le funzioni di callback al segnale activate */
111
gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
112
GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
113
gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
114
GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
116
/* Possiamo collegare l'elemento Quit alla nostra funzione di uscita */
117
gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
118
GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
120
/* Abbiamo bisogno di mostrare gli elementi di menu' */
121
gtk_widget_show( open_item );
122
gtk_widget_show( save_item );
123
gtk_widget_show( quit_item );
128
<P>A questo punto abbiamo il nostro menù Adesso abbiamo bisogno di creare una barra dei menù
129
<P>e un elemento di menù per <CODE>File</CODE>, a cui aggiungeremo il nostro menù. Il codice è questo:
134
menu_bar = gtk_menu_bar_new();
135
gtk_container_add( GTK_CONTAINER(window), menu_bar);
136
gtk_widget_show( menu_bar );
138
file_item = gtk_menu_item_new_with_label("File");
139
gtk_widget_show(file_item);
143
<P>Ora dobbiamo associare il menù con <CODE>file_item</CODE>. Lo si può fare con la funzione
146
void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
150
<P>Quindi, il nostro esempio continuerebbe con
154
gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu);
158
<P>Ciò che manca a questo punto è di collegare il menù alla barra, cosa che si può ottenere tramite la funzione
161
void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
163
<P>che nel nostro caso è:
167
gtk_menu_bar_append( GTK_MENU_BAR(menu_bar), file_item );
171
<P>Se volessimo il menù giustificato a dstra, come sono spesso i menù di aiuto, potremm
172
<P>usare la seguente funzioe (di nuovo su <CODE>file_item</CODE> in questo esempio) prima di fare il collegamento alla barra.
177
void gtk_menu_item_right_justify (GtkMenuItem *menu_item);
181
Ecco un riassunto dei passi necessari per creare una barra con i relativi menù collegati:
184
<LI> Create un nuovo menù con gtk_menu_new()</LI>
185
<LI> Usate delle chiamate multiple a gtk_menu_item_new() per ognuno degli
186
elementi che volete mettere nel vostro menù. Usate inoltre gtk_menu_item_append()
187
per mettere ciascuno di questi nuovi elementi sul menù..</LI>
188
<LI> Create un elemento di menù usando gtk_menu_item_new(). Questo rappresenta l'elemento di base
190
delmenù, e il testo relativo sarà il testo mostrato sulla barra dei menù stessa.
192
<LI> Usate gtk_menu_item_set_submenu() per collegare i menù all'elemento base del menù (cioè quello creato al passaggio precedente).
194
<LI> Create una nuova barra di menù usando gtk_menu_bar_new. Questo passo
195
necessita di essere effettuato una sola volta quando si crea una serie di
196
menù su una sola barra.</LI>
197
<LI> Usate gtk_menu_bar_append per mettere il menù base sulla barra dei menù.</LI>
199
<P>Creare un menù a comparsa è più o meno la stessa cosa. La differenza è che il
200
il menù non viene attivato ``automaticamente'' da una barra, bensì per esempio
201
con la chiamata espicita alla funzione gtk_menu_popup() da parte di un evento di pressione di un pulsante.
202
Seguite questi passaggi:
204
<LI>Create una funzione di gestione di un evento. Essa deve seguire il prototipo
206
static gint handler(GtkWidget *widget, GdkEvent *event);
209
e usare l'evento per scoprire dove il menu deve essere fatto comparire.</LI>
210
<LI>Nel gestore di evento, se questo è la pressione di un bottone, trattate
211
<CODE>event</CODE> come l'evento relativo ad un bottone (cosa che in effetti è)
212
e usatelo come mostrato nel codice di esempio per passare informazioni a
213
gtk_menu_popup().</LI>
214
<LI>Collegate il gestore di evento a un widget con
216
gtk_signal_connect_object(GTK_OBJECT(widget), "event",
217
GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
220
in cui <CODE>widget</CODE> è il widget a cui state effettuando il collegamento, e
221
<CODE>handler</CODE> è la funzione di gestione, mentre <CODE>menu</CODE> è un menù
222
creato con gtk_menu_new(). Quest'ultimo può essere un menù che viene anche
223
attivato da una barra di menù, come mostrato nel codice di esempio.</LI>
227
<H2><A NAME="ss10.2">10.2 Esempio di Menù Manuale</A>
230
<P>Per la teoria dovrebbe essere abbastanza. Diamo un'occhiata ad un esempio che
231
ci aiuti a chiarire le cose.
236
#include <gtk/gtk.h>
238
static gint button_press (GtkWidget *, GdkEvent *);
239
static void menuitem_response (gchar *);
241
int main (int argc, char *argv[])
247
GtkWidget *root_menu;
248
GtkWidget *menu_items;
254
gtk_init (&argc, &argv);
256
/* crea una nuova finestra */
257
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
258
gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
260
gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
261
gtk_signal_connect(GTK_OBJECT (window), "delete_event",
262
(GtkSignalFunc) gtk_main_quit, NULL);
264
/* Inizializziamo il menù, e ricordate: mai applicare
265
* gtk_show_widget() al widget menù!!
266
* Questo è il menù che contiene gli elementi, quello che
267
* spunta quando si fa click sul "Menù radice" nell'applicazione */
268
menu = gtk_menu_new();
270
/* Ora creiamo un ciclo che crea tre elementi di menu per "test-menu".
271
* Notete la chiamata a gtk_menu_append. In questo punto aggiungiamo una
272
* lista di elementi al nostro menù. Normalmente, dovremmo poi catturare
273
* il segnale di attivazione per ognuno degli elementi del menu, e creare
274
* una funzione di ritorno per ciascuno di essi, ma qui non li mettiamo per
277
for(i = 0; i < 3; i++)
279
/* Copia i nomi in buf. */
280
sprintf(buf, "Test-undermenu - %d", i);
282
/* Crea un nuovo elemento di menù con un nome... */
283
menu_items = gtk_menu_item_new_with_label(buf);
285
/* ...e aggiungilo al menù. */
286
gtk_menu_append(GTK_MENU (menu), menu_items);
288
/* Fa qualcosa di interessante quando si seleziona l'elemento */
289
gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
290
GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
292
/* Mostra il widget */
293
gtk_widget_show(menu_items);
296
/* Questo è il menù radice, e l'etichetta sarà il nome del menù che
297
* verrà mostrato sulla barra dei menù. Non ci sarà alcun gestore di
298
* segnale collegato, dal momento che non fa altro che mostrare il resto
299
* del menù quando viene premuto. */
300
root_menu = gtk_menu_item_new_with_label("Root Menu");
302
gtk_widget_show(root_menu);
307
/* Ora specifichiamo che vogliamo che il menù che abbiamo appena creato
308
* sia il menù radice *//
309
gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
311
/* Una vbox in cui mettere un menù ed un bottone: */
312
vbox = gtk_vbox_new(FALSE, 0);
313
gtk_container_add(GTK_CONTAINER(window), vbox);
314
gtk_widget_show(vbox);
316
/* Crea una barra dei menù per metterci i menù e l'aggiunge alla finestra principale */
317
menu_bar = gtk_menu_bar_new();
318
gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
319
gtk_widget_show(menu_bar);
321
/* Crea un bottone a cui collegare un menù */
322
button = gtk_button_new_with_label("press me");
323
gtk_signal_connect_object(GTK_OBJECT(button), "event",
324
GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
325
gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
326
gtk_widget_show(button);
328
/* E finalmente attacchiamo l'elemento di menù alla barra dei menù -- questo
329
* è l'elemento di menù "radice" di cui parlavo */
330
gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
332
/* La finestra va mostrata sempre come ultimo passo in modo che sia già
333
* completa di tutti i suoi elementi. */
334
gtk_widget_show(window);
343
/* Risponde alla pressione di un bottone impostando un menù che
344
* viene passato come widget.
345
* Notate che l'argomento "widget" si riferisce al menù impostato
346
* e NON al bottone premuto.
349
static gint button_press (GtkWidget *widget, GdkEvent *event)
352
if (event->type == GDK_BUTTON_PRESS) {
353
GdkEventButton *bevent = (GdkEventButton *) event;
354
gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
355
bevent->button, bevent->time);
356
/* Riferisce al codice chiamante che abbiamo trattato l'evento;
357
* la faccenda finisce qui. */
361
/* Riferisce al codice chiamante che abbiamo trattato l'evento; passa avanti. */
366
/* Stampa una stringa quando viene selezionato un elemento di menù */
368
static void menuitem_response (gchar *string)
370
printf("%s\n", string);
374
<P>Si può anche fare in modo che un elemento di menù sia insensibile e, usando
375
una tabella di acelleratori, collegare dei tasti a delle funzioni di menù.
378
<H2><A NAME="ss10.3">10.3 Usare GtkMenuFactory</A>
381
<P>Ora che vi abbiamo mostrato il modo difficile, ecco invece come si fa usando
382
le chiamate di gtk_menu_factory.
385
<H2><A NAME="ss10.4">10.4 Esempio di Menu Factory</A>
388
<P>Ecco un esempio di utilizzo della ``Fabbrica'' di Menù di GTK (Menu Factory).
389
Questo è il primo file, menufactoy.h. Teniemo dei file menufactory.c e main.c separati
390
a causa delle variabili globali usate nel file menufactory.c.
397
#ifndef __MENUFACTORY_H__
398
#define __MENUFACTORY_H__
402
#endif /* __cplusplus */
404
void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
405
void menus_create(GtkMenuEntry *entries, int nmenu_entries);
409
#endif /* __cplusplus */
411
#endif /* __MENUFACTORY_H__ */
414
<P>Ed ecco il file menufactory.c.
419
#include <gtk/gtk.h>
420
#include <strings.h>
424
static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
425
static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
426
void menus_init(void);
427
void menus_create(GtkMenuEntry * entries, int nmenu_entries);
429
/* Questa è la struttuta GtkMenuEntry, che viene usata per creare dei nuovi
430
* menù. Il primo membro à la stringa di definizione del menù. Il secondo
431
* è il tasto acceleratore predefinito, usato per accedere a questa funzione
432
* con la tastiera. Il terzo è la funzione di ritorno che viene chiamata
433
* quando si seleziona con la tastiera o il mouse questo elemento di menù.
434
* L'ultimo membro costituisce il dato che viene passato alla funzione di
437
static GtkMenuEntry menu_items[] =
439
{"<Main>/File/New", "<control>N", NULL, NULL},
440
{"<Main>/File/Open", "<control>O", NULL, NULL},
441
{"<Main>/File/Save", "<control>S", NULL, NULL},
442
{"<Main>/File/Save as", NULL, NULL, NULL},
443
{"<Main>/File/<separator>", NULL, NULL, NULL},
444
{"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
445
{"<Main>/Options/Test", NULL, NULL, NULL}
448
/* calcola il numero di menu_item */
449
static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
451
static int initialize = TRUE;
452
static GtkMenuFactory *factory = NULL;
453
static GtkMenuFactory *subfactory[1];
454
static GHashTable *entry_ht = NULL;
456
void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
462
*menubar = subfactory[0]->widget;
464
*table = subfactory[0]->table;
467
void menus_init(void)
472
factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
473
subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
475
gtk_menu_factory_add_subfactory(factory, subfactory[0], "<Main>");
476
menus_create(menu_items, nmenu_items);
480
void menus_create(GtkMenuEntry * entries, int nmenu_entries)
489
for (i = 0; i < nmenu_entries; i++) {
490
accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
492
if (accelerator[0] == '\0')
493
entries[i].accelerator = NULL;
495
entries[i].accelerator = accelerator;
498
gtk_menu_factory_add_entries(factory, entries, nmenu_entries);
500
for (i = 0; i < nmenu_entries; i++)
501
if (entries[i].widget) {
502
gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator",
503
(GtkSignalFunc) menus_install_accel,
505
gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator",
506
(GtkSignalFunc) menus_remove_accel,
511
static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
517
if (modifiers & GDK_CONTROL_MASK)
518
strcat(accel, "<control>");
519
if (modifiers & GDK_SHIFT_MASK)
520
strcat(accel, "<shift>");
521
if (modifiers & GDK_MOD1_MASK)
522
strcat(accel, "<alt>");
529
t1 = g_hash_table_lookup(entry_ht, path);
532
entry_ht = g_hash_table_new(g_str_hash, g_str_equal);
534
g_hash_table_insert(entry_ht, path, g_strdup(accel));
539
static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
544
t = g_hash_table_lookup(entry_ht, path);
547
g_hash_table_insert(entry_ht, path, g_strdup(""));
551
void menus_set_sensitive(char *path, int sensitive)
553
GtkMenuPath *menu_path;
558
menu_path = gtk_menu_factory_find(factory, path);
560
gtk_widget_set_sensitive(menu_path->widget, sensitive);
562
g_warning("Impossibile assegnare sensibilità a menù inesistente: %s", path);
579
#endif /* __cplusplus */
581
void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
585
#endif /* __cplusplus */
587
#endif /* __MFMAIN_H__ */
598
#include <gtk/gtk.h>
601
#include "menufactory.h"
604
int main(int argc, char *argv[])
607
GtkWidget *main_vbox;
610
GtkAcceleratorTable *accel;
612
gtk_init(&argc, &argv);
614
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
615
gtk_signal_connect(GTK_OBJECT(window), "destroy",
616
GTK_SIGNAL_FUNC(file_quit_cmd_callback),
618
gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
619
gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
621
main_vbox = gtk_vbox_new(FALSE, 1);
622
gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
623
gtk_container_add(GTK_CONTAINER(window), main_vbox);
624
gtk_widget_show(main_vbox);
626
get_main_menu(&menubar, &accel);
627
gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
628
gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
629
gtk_widget_show(menubar);
631
gtk_widget_show(window);
637
/* Questo è per mostrare come si usano le funzioni di ritorno quando
638
* si utilizza la MenuFactory. Spesso, si mettono tutte le funzioni di
639
* callback in un file separato, e le si fanno chiamare le funzioni
640
* appropriate da lì. Così le cose sono più organizzate. */
641
void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
643
g_print ("%s\n", (char *) data);
648
<P>Ed infine un bel makefile per semplificare la compilazione.
658
C_FLAGS = -Wall $(PROF) -L/usr/local/include -DDEBUG
659
L_FLAGS = $(PROF) -L/usr/X11R6/lib -L/usr/local/lib
660
L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
661
PROGNAME = menufactory
663
O_FILES = menufactory.o mfmain.o
665
$(PROGNAME): $(O_FILES)
667
$(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
670
$(CC) -c $(C_FLAGS) $<
673
rm -f core *.o $(PROGNAME) nohup.out
678
<P>Per il momento, accontentatevi di questo esempio. Più avanti aggiungeremo
679
una spiegazione ed un bel po' di commenti.
683
<A HREF="gtk_tut_it-11.html">Avanti</A>
684
<A HREF="gtk_tut_it-9.html">Indietro</A>
685
<A HREF="gtk_tut_it.html#toc10">Indice</A>