Chapitre 9
Les menus

Nous allons cette fois voir quelles sont les solutions que Gtk2-Perl met à notre disposition pour ajouter un menu à une fenêtre. Nous parlons de “solutions” au pluriel car il existe en fait deux méthodes possibles à la création d’un menu, l’une étant plus rapide que l’autre.

Ce chapitre est composé de trois parties distinctes :

Le menu - Méthode longue.

Pour construire un tel menu, nous allons utiliser pas moins de trois widgets différents qui serviront tous à différentes étapes de la création. Ces widgets sont MenuBar, Menu, MenuItem.

Les éléments d’un menu.

Dans un premier temps, le plus simple est de voir comment seront disposés ces trois widgets dans notre futur menu.

menusdescription
Nous avons tout d’abord le widget MenuBar (en rouge) qui est l’élément principal de notre menu. Il contient des éléments de type GtkMenuItem (en bleu) qui peuvent ouvrir des éléments GtkMenu (en vert) contenant aussi des GtkMenuItem.

Du point de vue du fonctionnement, les éléments GtkMenuItem peuvent soit ouvrir un sous-menu (élément GtkMenu) soit exécuter l’action qui lui est associée par l’intermédiaire d’une fonction de rappel. Il ne reste maintenant plus qu’à créer notre menu.

Création d’un menu

La création d’un menu doit passer par au moins six étapes différentes :

  1. Création de l’élément MenuBar qui sera la barre de menu ;
  2. Création d’un élément Menu qui sera un menu ;
  3. Création des éléments MenuItem à insérer dans le menu ;
  4. Création de l’élément MenuItem qui ira dans l’élément MenuBar ;
  5. Association de cet élément avec le menu créé précédemment ;
  6. Ajout de l’élément MenuItem dans la barre MenuBar.

Si, par la suite, vous souhaitez ajouter d’autres menus, il suffit de recommencer à partir de la seconde étape. Etudions maintenant les fonctions qui vont nous permettre de coder le menu.

Création de l’élément MenuBar

Cette étape, rapide et simple, se résume en l’utilisation d’une seule fonction :

$menubar = Gtk2::MenuBar->new ();

Création d’un élément Menu qui sera un menu

Cette fois aussi, une seule fonction est utilisée :

$menu = Gtk2::Menu->new ();

création des éléments MenuItem à insérer dans le menu

Dans un premier temps, il faut créer le MenuItem grâce à l’une de ces trois fonctions :

$menuitem = Gtk2::MenuItem->new ();  
$menuitem = Gtk2::MenuItem->new_with_label ($label);  
$menuitem = Gtk2::MenuItem->new_with_mnemonic ($label);

Nous reconnaissons la syntaxe de ces constructeurs qui est semblable à celles des boutons. La première fonction créer un élément vide, la deuxième un élément avec un texte (label), et la troisième un élément avec un texte associé à un raccourci.

Maintenant que l’élément est créé, il faut l’insérer dans le menu. Pour cela, il existe plusieurs fonctions possibles, mais nous n’allons en voir que deux :

$menu->append($menuitem);  
$menu->prepend($menuitem);

Ces fonctions ne font pas partie du widget Menu mais de MenuShell qui est le widget dont Menu dérive. La première fonction ajoute les éléments de haut en bas alors que la seconde les ajoute de bas en haut. Cette étape peut s’avérer longue à coder, car il faudra la répéter pour chaque élément que nous voulons ajouter au menu.

Création de l’élément MenuItem qui ira dans l’élément MenuBar

Il suffit d’utiliser une des trois fonctions de création du widget MenuItem.

Association de cet élément avec le menu créer précédemment

Il faut maintenant que lorsque l’utilisateur clique sur le MenuItem qui est dans MenuBar, le menu s’ouvre. C’est pourquoi il ne faut oublier :

$menuitem_avec_sous_menu->set_submenu($menu);
Cette fonction va donc associer le MenuItem $menuitem_avec_sous_menu au Menu $menu.

Ajout de l’élément MenuItem dans la barre MenuBar

MenuBar dérivant aussi de MenuShell, on utilise la même méthode que pour ajouter le MenuItem au Menu.

Exemple

Notre exemple comportera deux menu. Le premier “Fichier”, proposera des fonctions inactives (“Nouveau”, “Ouvrir”, “Enregistrer”, “Fermer”) et une fonction active (“Quitter”), alors que le second “ ?” proposera la fonction “A propos de...”.

menus1

# !/usr/bin/perl -w

use strict ;
use Gtk2 ’-init’ ;
use constant TRUE => 1 ;
use constant FALSE => 0 ;

# Creation de la fenêtre
my $window = Gtk2::Window->new(”toplevel” ) ;
$window->set_title (”Les menus (1)” ) ;
$window->signal_connect (destroy => sub { Gtk2->main_quit }) ;
$window->set_default_size(320 ,200 ) ;

# Création de la GtkVBox
my $vbox = Gtk2::VBox->new(FALSE, 0 ) ;
$window->add($vbox) ;

###### réation du menu #####

### Etape 1
my $menubar = Gtk2::MenuBar->new() ;

### Premier sous-menu
### Etape 2
my $menu1= Gtk2::Menu->new() ;

### Etape 3
my $menuitem1 = Gtk2::MenuItem->new_with_label(”Nouveau” ) ;
$menu1->append($menuitem1) ;

my $menuitem2 = Gtk2::MenuItem->new_with_label(”Ouvrir” ) ;
$menu1->append($menuitem2) ;

my $menuitem3 = Gtk2::MenuItem->new_with_label(”Enregistrer” ) ;
$menu1->append($menuitem3) ;

my $menuitem4 = Gtk2::MenuItem->new_with_label(”Fermer” ) ;
$menu1->append($menuitem4) ;

my $menuitem5 = Gtk2::MenuItem->new_with_label(”Quitter” ) ;
$menu1->append($menuitem5) ;
$menuitem5->signal_connect(”activate” ,\&on_quitter,$window) ;

### Etape 4
my $menuitem6 = Gtk2::MenuItem->new_with_label(”Fichier” ) ;

### Etape 5
$menuitem6->set_submenu($menu1) ;

### Etape 6
$menubar->append($menuitem6) ;

### Second sous-menu **/
### Etape 2
my $menu2 = Gtk2::Menu->new() ;

### Etape 3
my $menuitem7 = Gtk2::MenuItem->new_with_label(”A propos de ...” ) ;
$menu2->append($menuitem7) ;
$menuitem7->signal_connect(”activate” ,\&on_about,$window) ;

### Etape 4
my $menuitem8 = Gtk2::MenuItem->new_with_label( ?” ) ;

### Etape 5
$menuitem8->set_submenu($menu2) ;

### Etape 6
$menubar->append($menuitem8) ;

### Ajout du menu a la fenetre
$vbox->pack_start($menubar,FALSE,FALSE,0 ) ;

$window->show_all() ;
Gtk2->main() ;

### Les fonctions de rappels
### Ici on demande une consfirmation pour quitter l’application
sub on_quitter{
my ($widget,$window) = @_ ;
my $dialog = Gtk2::MessageDialog->new ($window,
[qw/modal destroy-with-parent/],
’question’ ,
’yes_no’ ,
”Voulez-vous vraiment \n quitter le programme ?” ) ;
my $reponse = $dialog->run ;
if ($reponse eq ”yes” ) {
Gtk2->main_quit ;
}
else {
$dialog->destroy() ;
}
}

sub on_about {
my ($widget,$window) = @_ ;

my $dialog = Gtk2::MessageDialog->new ($window,
[qw/modal destroy-with-parent/],
’info’ ,
’ok’ ,
”Gtk2 Perl tutoriel” ) ;
$dialog->run ;
$dialog->destroy() ;
}

Éléments “avancés” de menu.

En plus des MenuItem, GTK+ offre cinq éléments de menu additionnels prêts à l’emploi : ImageMenuItem, RadioMenuItem, CheckMenuItem, SeparatorMenuItem et TearoffMenuItem. Bien entendu toutes les fonctions s’appliquant sur des MenuItems s’appliquent aussi à ces items (héritage oblige).

Les ImageMenuItems

Pour créer un ImageMenuItem, on a à disposition quatre fonctions :

$menuitem = Gtk2::ImageMenuItem->new();  
$menuitem = Gtk2::ImageMenuItem->new_from_stock($stock_id,$accel);  
$menuitem = Gtk2::ImageMenuItem->new_with_label($label);  
$menuitem = Gtk2::ImageMenuItem->new_with_mnemonic($label);

On retrouve encore les mêmes types de fonctions de création, aussi je passe sur l’explication des paramètres. La seule nouveauté est peut-être $accel de Gtk2::ImageMenuItem->new_from_stock, qui sert à ajouter l’entrée à un AccelGroup précédemment créé en utilisant le raccourci par défaut de l’icône stock.

Maintenant, il s’agit de définir une icône pour notre entrée, pour cela, on a :

$menuitem->set_image($image);
Cette fonction permet de définir l’icône (généralement on utilisera un GtkImage) qui sera affichée par l’entrée passée en paramètre. Cette fonction peut aussi servir à remplacer l’icône que Gtk2::ImageMenuItem->new_from_stock définit pour l’entrée lors de sa création.

La dernière fonction spécifique des ImageMenuItems est :

$image = $menuitem->get_image();
Elle sert, comme vous l’aurez deviné, à récupérer ce qui sert d’icône à l’entrée.

Les CheckMenuItems

Les CheckMenuItems émettent un signal lorsqu’on les (dé)coche, il s’agit du signal “toggled”. Les fonctions de création d’un CheckMenuItem sont :

$menuitem = Gtk2::CheckMenuItem->new();  
$menuitem = Gtk2::CheckMenuItem->new_with_label($label);  
$menuitem = Gtk2::CheckMenuItem->new_with_mnemonic($label);
Rien de nouveau à l’horizon, alors nous continuons.

Nous avons plusieurs fonctions qui permettent de changer l’état de notre CheckMenuItem par programme :

$menuitem->set_active($is_active);  
$menuitem->set_inconsistent($setting);  
$menuitem->toggled();
La première fonction permet de passer le CheckMenuItem dans l’état “coché” si le paramètre $is_active est TRUE ou dans l’état “non coché” si $is_active est FALSE. Cette fonction ne permet pas de mettre notre CheckMenuItem dans le troisième état “demi coché”, pour cela, il faut utiliser la deuxième fonction, et grâce au paramètre $setting, on active ou non cet état. La troisième fonction, elle, permet d’alterner entre état “coché” et “non coché” car elle émet en fait le signal “toggled”, ce qui a pour effet d’inverser l’état du CheckMenuItem.

Nous disposons également des fonctions associées pour récupérer l’état d’un CheckMenuItem :

$etat = $menuitem->get_active();  
$etat = $menuitem->get_inconsistent();
La première permet de connaître l’état d’un CheckMenuItem, elle renvoie TRUE si il est “coché” ou FALSE sinon. La deuxième permet juste de savoir si le CheckMenuItem est dans le troisième état “demi coché”.

Les RadioMenuItems

Les RadioMenuItems héritent des CheckMenuItems, donc tout ce qui a été dit juste avant s’applique aussi ici. Pour créer un RadioMenuItem, nous pouvons nous servir de :

$menuitem = Gtk2::RadioMenuItem->new($group);  
$menuitem = Gtk2::RadioMenuItem->new_with_label($group,$label);  
$menuitem = Gtk2::RadioMenuItem->new_with_mnemonic($group,$label);

Ce widget fonctionne de la même manière que le widget RadioButton, et donc le paramètre group de ces fonctions, sert à dire au RadioMenuItem à quel groupe il va appartenir. Le premier RadioMenuItem d’un groupe prendra toujours undef comme paramètre $group, de cette façon il va en créer un nouveau. Ensuite, il suffira de récupérer ce paramètre $group grâce à la fonction suivante et de le passer à un autre RadioMenuItem pour que celui ci fasse partie du même groupe que le premier.

$menuitem->get_group();
Tout comme pour le widget RadioButton, quand on crée un groupe de RadioMenuItem, il faut toujours récupérer le groupe du RadioMenuItem précédemment créé (sauf pour le premier bien entendu).

On peut aussi définir ou remplacer le groupe d’un RadioMenuItem aprés coup grâce à :

$menuitem->set_group($group);

Les SeparatorMenuItems

Ahh, en voilà un widget qu’il est bien ! Une seule fonction pour sa création, et c’est tout :

$menuitem = Gtk2::SeparatorMenuItem->new();

Les TearoffMenuItems

Pour le créer, faites :

$menuitem = Gtk2::TearoffMenuItem->new();
Et c’est tout ! Ensuite, un premier clic sur l’élément TearoffMenuItem créera une copie du menu dans une fenêtre, et un second clic sur l’élément (que cela soit dans le menu ou dans la fenêtre) supprimera la fenêtre créée.

Pour savoir si le menu est attaché ou détaché, il faut utiliser la fonction :

$etat = $menu->get_tearoff_state();
Cette dernière renverra TRUE si le menu est détaché et FALSE sinon. Lorsque nous fermons la fenêtre du menu détaché à la main (c’est à dire lorsque nous cliquons sur la croix), le menu est automatiquement réattaché, $menu->get_tearoff_state renverra tout de même TRUE.

Programme exemple

Nous avons repris l’exemple précédent en modifiant le menu pour y mettre nos nouveaux items et en y ajoutant trois labels pour indiquer l’état des différents items. Il y a aussi trois fonctions de rappels supplémentaires pour la mise à jour de nos labels.

menus2

# !/usr/bin/perl -w

use strict ;
use Gtk2 ’-init’ ;
use constant TRUE => 1 ;
use constant FALSE => 0 ;

# Creation de la fenêtre
my $window = Gtk2::Window->new(”toplevel” ) ;
$window->set_title (”Les menus (2)” ) ;
$window->signal_connect (destroy => sub { Gtk2->main_quit }) ;
$window->set_default_size(320 ,200 ) ;

# Création de la GtkVBox
my $vbox = Gtk2::VBox->new(FALSE, 0 ) ;
$window->add($vbox) ;

my $accel = Gtk2::AccelGroup->new() ;

###### réation du menu #####
### Etape 1
my $menubar = Gtk2::MenuBar->new() ;
### Premier sous-menu
### Etape 2
my $menu1= Gtk2::Menu->new() ;
### Etape 3
my $menuitem1 = Gtk2::TearoffMenuItem->new() ;
$menu1->append($menuitem1) ;
$menuitem1->signal_connect(”activate” ,\&on_tearoff,$menu1) ;

my $menuitem2 = Gtk2::ImageMenuItem->new_from_stock(”gtk-new” ,$accel) ;
$menu1->append($menuitem2) ;

my $menuitem3 = Gtk2::ImageMenuItem->new_from_stock(”gtk-open” ,$accel) ;
$menu1->append($menuitem3) ;

my $menuitem4 = Gtk2::ImageMenuItem->new_from_stock(”gtk-save” ,$accel) ;
$menu1->append($menuitem4) ;

my $menuitem5 = Gtk2::ImageMenuItem->new_from_stock(”gtk-close” ,$accel) ;
$menu1->append($menuitem5) ;

my $menuitem6 = Gtk2::SeparatorMenuItem->new() ;
$menu1->append($menuitem6) ;

my $menuitem7 = Gtk2::RadioMenuItem->new_with_label(undef,”Radio1” ) ;
$menu1->append($menuitem7) ;

my $group = $menuitem7->get_group() ;

### Il est inutile ici d’utiliser le signal ”toggled”
$menuitem7->signal_connect(”activate” ,\&on_radio) ;


##### Les boutons radio dans le menu !
my $menuitem8 = Gtk2::RadioMenuItem->new_with_label($group,”Radio2” ) ;
$menu1->append($menuitem8) ;
$menuitem8->signal_connect(”activate” ,\&on_radio) ;

my $menuitem9 = Gtk2::RadioMenuItem->new_with_label($group,”Radio3” ) ;
$menu1->append($menuitem9) ;
$menuitem9->signal_connect(”activate” ,\&on_radio) ;

my $menuitem10 = Gtk2::SeparatorMenuItem->new() ;
$menu1->append($menuitem10) ;

#### Les cases à cocher aussi !
my $menuitem11 = Gtk2::CheckMenuItem->new_with_label(”Check” ) ;
$menu1->append($menuitem11) ;
$menuitem11->signal_connect(”toggled” ,\&on_check) ;

my $menuitem12 = Gtk2::SeparatorMenuItem->new() ;
$menu1->append($menuitem12) ;

my $menuitem13 = Gtk2::MenuItem->new_with_label(”Quitter” ) ;
$menu1->append($menuitem13) ;
$menuitem13->signal_connect(”activate” ,\&on_quitter,$window) ;

### Etape 4
my $menuitem14 = Gtk2::MenuItem->new_with_label(”Fichier” ) ;

### Etape 5
$menuitem14->set_submenu($menu1) ;

### Etape 6
$menubar->append($menuitem14) ;

### Second sous-menu **/
### Etape 2
my $menu2 = Gtk2::Menu->new() ;

### Etape 3
my $menuitem15 = Gtk2::MenuItem->new_with_label(”A propos de ...” ) ;
$menu2->append($menuitem15) ;
$menuitem15->signal_connect(”activate” ,\&on_about,$window) ;

### Etape 4
my $menuitem16 = Gtk2::MenuItem->new_with_label( ?” ) ;

### Etape 5
$menuitem16->set_submenu($menu2) ;

### Etape 6
$menubar->append($menuitem16) ;

### Creation de la deuxieme GtkVBox (pour les labels) */
my $vbox2 = Gtk2::VBox->new(FALSE, 0 ) ;

my $RadioLabel = Gtk2::Label->new(”Radio 1 est actif” ) ;
$vbox2->pack_start($RadioLabel, TRUE, TRUE, 0 ) ;

my $CheckLabel = Gtk2::Label->new(”Check est décoché” ) ;
$vbox2->pack_start($CheckLabel, TRUE, TRUE, 0 ) ;

my $TearoffLabel = Gtk2::Label->new(”Menu attaché” ) ;
$vbox2->pack_start($TearoffLabel, TRUE, TRUE, 0 ) ;

### Ajout du menu à la fenetre
$vbox->pack_start($menubar, FALSE, FALSE, 0 ) ;
### Ajout des labels à la fenêtre
$vbox->pack_start($vbox2, TRUE, TRUE, 0 ) ;

$window->show_all() ;
Gtk2->main() ;

#### Les fonstions de rappels

sub on_radio {
my $widget = shift ;

### Récupérer le label du bouton radio actif
my $RadioName = $widget->child->get_label() ;
$RadioLabel->set_label(sprintf”%s est actif” ,$RadioName) ;
}

sub on_check{
my $widget = shift ;
my $Label ;
### Savoir si le GtkCheckMenuItem est coché ou non
my $Coche = $widget->get_active() ;
if ($Coche) {
$Label = ”Check est coché” ;
}
else {
$Label =”Check est décoché” ;
}
$CheckLabel->set_label($Label) ;
}

sub on_tearoff {

my ($widget,$menu) = @_ ;
my $Label ;
### Savoir si le menu est détaché ou non */
my $Detache = $menu->get_tearoff_state() ;
if ($Detache) {
$Label = ”Menu détaché” ;
}
else {
$Label = ”Menu attaché” ;
}
$TearoffLabel->set_label($Label) ;
}

sub on_quitter{
my ($widget,$window) = @_ ;
my $dialog = Gtk2::MessageDialog->new ($window,
[qw/modal destroy-with-parent/],
’question’ ,
’yes_no’ ,
”Voulez-vous vraiment \n quitter le programme ?” ) ;
my $reponse = $dialog->run ;
if ($reponse eq ”yes” ) {
Gtk2->main_quit ;
}
else {
$dialog->destroy() ;
}
}

sub on_about {
my ($widget,$window) = @_ ;

my $dialog = Gtk2::MessageDialog->new ($window,
[qw/modal destroy-with-parent/],
’info’ ,
’ok’ ,
”Gtk2 Perl tutoriel” ) ;
$dialog->run ;
$dialog->destroy() ;
}

Le menu - Méthode rapide

Grâce aux deux premières parties du chapitre, nous avons appris à créer un menu. Vous avez pu remarquer que cette méthode peut s’avérer très fastidieuse si le menu comporte beaucoup d’éléments. Nous allons maintenant voir comment simplifier tout cela pour le biais de l’objet ItemFactory.

Fonctionnement de ItemFactory

L’objet ItemFactory n’est en fait qu’une grosse machine nous fournissant les fonctions nécessaires à la création d’un menu. Pour cela, ItemFactory utilise la structure ItemFactoryEntry qui elle nous permet de définir les différents éléments qui composent le menu ainsi que les actions qui leurs sont associés. En Perl, on utilise un tableau :

[$path,$accelerator,$callback,$callback_action,$item_type,$extra_data]

Création des éléments du menu

Pour cela, la seule à faire est de déclarer et de remplir un tableau de ItemFactoryEntry. Nous allons donc maintenant étudier comment remplir ce tableau d’après la définition de la structure ItemFactoryEntry.

Le paramètre $path correspond au chemin de l’élément dans l’arborescence du menu. Il faut pour cela, voir l’arborescence d’un menu comme celle des fichiers, c’est-à-dire organisée en répertoire (les branches du menu) et en fichier (les éléments du menu). Ce paramètre permet aussi de définir le texte de l’élément. Par exemple, nous avons un menu “Fichier” qui possède un élément “Nouveau”, alors le path de la branche “Fichier” sera “/Fichier” et celui de l’élément “Nouveau” sera “/Fichier/Nouveau”. Pour souligner une lettre (pour indiquer un raccourci clavier), il faut précéder cette lettre de _ comme pour les mnémonics. Cependant, cela ne crée pas un raccourci, il s’agit juste d’une indication.

Le second paramètre $accelerator définit la combinaison de touche qui activera l’élément du menu, et cela, même si le menu n’est pas ouvert. La combinaison de touche allouée à l’élément est affichée après le label de l’élément du menu. La syntaxe de ce paramètre est <touche-speciale>Lettre, touche-spéciale pouvant être Ctrl, Alt ou Shift. Il est bien sûr possible d’utiliser une combinaison de ces touches (exemple : <CTRL><SHIFT>O).

Le paramètre $callback est la fonction de rappel qui sera appelée lorsque l’élément sera activé à l’aide de la souris ou d’un raccourci clavier.

Le quatrième paramètre, $callback_action est un entier qui sera passé en paramètre à la fonction de rappel car celle-ci doit avoir le prototype suivant :

sub fonction_callback  
my ($window,$callback_action, $widget)=@_;  
...  
}

Dans ce cas, $window est la fenêtre contenant le menu, $callback_action est identique à la valeur donnée à l’élément et $widget est l’élément lui-même.

Le cinquième paramètre, $item_type, définit de quoi est constitué l’élément du menu. Ce paramètre doit être une des valeurs suivantes :

La seule subtilité ici, est pour les éléments de type RadioMenuItem. Le premier bouton radio du groupe (ex : path = /Choix/Pour ) aura $item_type égal à <RadioItem> alors que les autres auront $item_type égal à /Choix/Pour.

Enfin pour terminer, le dernier paramètre $extra_data devra être défini dans deux cas :

Nous savons donc maintenant comment déclarer le menu et il ne reste plus qu’à le créer.

Création du menu.

La première chose à faire est de créer un objet pour récupérer les raccourcis clavier du menu. Pour cela nous allons utiliser l’objet AccelGroup dont nous n’allons pas parler ici. La création de cet objet se fait à l’aide de cette fonction :

$accel = Gtk2::AccelGroup->new();

Ensuite, il faut créer l’objet ItemFactory avec cette fonction :

$item_factory = Gtk2::ItemFactory->new($container_type,$path, $accel);

Le premier paramètre $container_type, définit le type de menu que nous voulons créer. Il existe trois valeurs possibles :

Le paramètre $path est le nom que nous donnons au menu. Il représente la racine du menu et doit avoir la syntaxe suivante <nom_du_menu>.

Le dernier paramètre permet de récupérer les raccourcis clavier dans le AccelGroup. Ce paramètre peut être égal à undef.

Une fois le menu créé, il faut y insérer tous ses éléments avec la fonction :

$item_factory->create_items($window,@menu_items);

Le paramètre $window est la fenêtre contenant le menu et @menu_items est bien entendu le tableau préalablement créé décrivant les menus.

Il faut ensuite récupérer de tout cela pour pouvoir l’ajouter à notre fenêtre. Pour cela, il faut utiliser cette fonction :

$menubar = $item_factory->get_widget($path);

Et pour terminer tout cela, il faut associer les raccourcis à la fenêtre contenant le menu. Cela est possible par le biais d’une fonction du widget Window :

$window->add_accel_group($accel);
Et voila, le menu est terminé.

Exemple.

Nous allons reprendre l’exemple de la première partie, mais cette en utilisant des éléments de menu de type <StockItem>.

menus3

# !/usr/bin/perl -w

use strict ;
use Gtk2 ’-init’ ;
use constant TRUE => 1 ;
use constant FALSE => 0 ;

# Création de la fenêtre
my $window = Gtk2::Window->new(”toplevel” ) ;
$window->set_title (”Les menus faciles” ) ;
$window->signal_connect (destroy => sub { Gtk2->main_quit }) ;
$window->set_default_size(320 ,200 ) ;

# Création de la GtkVBox
my $vbox = Gtk2::VBox->new(FALSE, 0 ) ;
$window->add($vbox) ;

my @menu_items = (
[ ”/_Fichier” ,undef,0 ,0 ,<Branch> ],
[ ”/Fichier/_Nouveau” ,<control>N” ,\&menuitem_cb,0 ,<StockItem> ,”gtk-new” ,”coucou” ],
[ ”/Fichier/_Ouvrir” ,<control>O” ,\&menuitem_cb,0 ,<StockItem> , ’gtk-open’ ],
[ ”/Fichier/_Enregistrer” ,<control>S” ,\&menuitem_cb,0 ,<StockItem> ,’gtk-save’ ],
[ ”/Fichier/Enregistrer _sous...” , undef,\&menuitem_cb,0 ,<StockItem> ,’gtk-save’ ],
[ ”/Fichier/sep1” ,undef,\&menuitem_cb,0 ,<Separator> ],
[ ”/Fichier/_Quitter” ,<control>Q” ,\&on_quitter,0 ,<StockItem> ,’gtk-quit’ ],
[ ”/_Preferences” ,undef,0 ,0 ,<Branch> ],
[ ”/_Preferences/_Couleur” ,undef,0 ,0 ,<Branch> ],
[ ”/_Preferences/Couleur/_Rouge” ,undef,\&menuitem_cb,0 ,<RadioItem> ],
[ ”/_Preferences/Couleur/_Vert” ,undef,\&menuitem_cb,0 ,”/Preferences/Couleur/Rouge” ],
[ ”/_Preferences/Couleur/_Bleu” ,undef,\&menuitem_cb,0 ,”/Preferences/Couleur/Vert” ],
[ ”/_Preferences/_Forme” ,undef,0 ,0 ,<Branch> ],
[ ”/_Preferences/Forme/_Carre” ,undef,\&menuitem_cb,0 ,<RadioItem> ],
[ ”/_Preferences/Forme/_Rectangle” ,undef,\&menuitem_cb,0 ,”/Preferences/Forme/Carre” ],
[ ”/_Preferences/Forme/_Ovale” ,undef,\&menuitem_cb,0 ,”/Preferences/Forme/Rectangle” ],

# Si vous aviez voulu justifié le menu suivant à droite, il aurait fallu utiliser :
# <LastBranch> et non <Branch>. Les menus d’aide justifié à droite sont de nos
# jours considérés comme une mauvaise idée.
[ ”/_ ?” , undef, 0 , 0 , <Branch> ],
[ ”/ ?/_A propos” , undef, \&on_about, 0 ],
) ;
### Groupe de raccourci clavier
my $accel = Gtk2::AccelGroup->new() ;

### Création du menu
my $item_factory = Gtk2::ItemFactory->new(”Gtk2::MenuBar” ,<main> , $accel) ;
### Récuperation des éléments du menu
$item_factory->create_items($window,@menu_items) ;
### Récuperation du widget pour l’affichage du menu
my $menubar = $item_factory->get_widget(<main> ) ;
### Ajout du menu en haut de la fenêtre
$vbox->pack_start($menubar, FALSE, FALSE, 0 ) ;
### Association des raccourcis avec la fenetre
$window->add_accel_group($accel) ;

$window->show_all() ;
Gtk2->main() ;

################ Fonctions de rappels

sub on_quitter{
my ($widget,$window) = @_ ;
my $dialog = Gtk2::MessageDialog->new ($window,
[qw/modal destroy-with-parent/],
’question’ ,
’yes_no’ ,
”Voulez-vous vraiment \n quitter le programme ?” ) ;
my $reponse = $dialog->run ;
if ($reponse eq ”yes” ) {
Gtk2->main_quit ;
}
else {
$dialog->destroy() ;
}
}



sub on_about {
my ($widget,$window) = @_ ;

my $dialog = Gtk2::MessageDialog->new ($window,
[qw/modal destroy-with-parent/],
’info’ ,
’ok’ ,
”Gtk2 Perl tutoriel” ) ;
$dialog->run ;
$dialog->destroy() ;
}

sub menuitem_cb {
my ($window, $callback_action, $widget) = @_ ;
my $dialog = Gtk2::MessageDialog->new ($window,
’destroy-with-parent’ ,
’info’ ,
’close’ ,
sprintf ”Vous avez activé ou cliqué sur le menu item: \ %s\”” ,
Gtk2::ItemFactory->path_from_widget ($widget)) ;

# Ferme la boîte de dialogue après la réponse de l’utilisateur
$dialog->signal_connect (response => sub { $dialog->destroy ; 1 }) ;
$dialog->show ;
}