Ce qui est considéré comme un menu par les utilisateurs est en fait composé de trois parties. Tout d'abord, il y a la barre de menus en haut de la fenêtre, puis à l'intérieur de la barre de menus, il y a plusieurs menus, enfin, chaque menu possède en général un ou plusieurs sous-menus.
Object +-- Widget +-- Container +-- MenuShell
Les widgets Barre de Menu et Menu sont des sous-classes de MenuShell. Chaque MenuShell a la capacité d'ajouter à la fin, au début ou d'insérer un widget enfant.
$menushell->;append( $child ); $menushell->prepend( $child ); $menushell->insert( $child, $position );
Le MenuShell peut-être effacé de l'écran par :
$menushell->deactivate();
Un enfant du MenuShell peut-être sélectionné par :
$menushell->select_item( $child );
Un enfant du MenuShell peut-être activé par :
$menushell->activate_item( $child );
Object +-- Widget +-- Container +-- MenuShell +-- MenuBar
Une barre de menu est créée par :
$menubar = new Gtk::MenuBar();
Les barres de menus sont habituellement placées en haut de la fenêtre. Normalement, vous devriez créer une VBox et l'ajouter à la fenêtre. Vous devriez ensuite placer le barre de menu en haut de la boîte verticale. La seule autre fonction concernant les barres de menus (et qui ne proviennent pas du MenuShell) déclare le type de l'ombre :
$menubar->set_shadow_type( $shadow_type );
Ou $shadow_type est soit :
'none''in'
'out'
'etched_in'
'etched_out'
Object +-- Widget +-- Container +-- MenuShell +-- Menu
Les menus sont créés par :
$menu = new Gtk::Menu();
Si vous voulez bouger un enfant d'une position à l'autre, vous pouvez le faire avec :
$menu->reorder_child( $child, $position );
$child est l'enfant à bouger et $position est la nouvelle position.
Les menus peuvent avoir un titre associé. Ce titre est déclaré par :
$menu->set_title( $title );
L'état tear-off peut-être déclaré par ;
$menu->set_tearoff_state( $tear_off );
$tear_off est une valeur vraie ou fausse qui détermine si le menu peut
être à l'état tear-off. Un menu est normalement affiché comme un cadre qui descend
et qui persiste tant que le menu est actif, alors que le menu tear-off est dans
une fenêtre qui persiste jusqu'à ce que la fenêtre soit fermée.
Enfin, si vous voulez que votre menu se comporte comme un menu popup, vous devrez appeler :
$menu->popup( $parent_menu_shell, $parent_menu_item, $activate_time, $button, \&menu_position_function, @optional_data );
Ou $parent_menu_shell et $parent_menu_item seront indéfinis si
le menu n'est pas associé à une barre de menus. Pour $activate_time,
vous pouvez habituellement vous en débarrasser à l'aide de $event->{ 'time' }.
Si vous désirez que le menu disparaisse quand vous relâchez le bouton de la
souris, vous devrez mettre 1.
L'argument $button proviendra souvent de $event->{ 'button' }.
Enfin, \&menu_position_function est une référence à une fonction fournit
par l'utilisateur, utilisée pour positionner le menu. La plupart des gens utilise
undef qui définit la position en haut à gauche du menu à l'endroit du
clic de la souris. @optional_data, s'il est inclus, est envoyé comme
argument de \&menu_position_function.
Attendez-vous à ce que cette fonction change bientôt. On suppose qu'il y aura
une interversion de $button et de $activate_time comme ceci :
$menu->popup( $parent_menu_shell, $parent_menu_item, $button, $activate_time, \&menu_position_function, @optional_data );
Object +-- Widget +-- Container +-- Bin +-- Item +-- MenuItem
Créer des items de menus est aussi simples que d'appeler l'une des fonctions suivantes :
$menuitem = new Gtk::MenuItem(); $menuitem = new Gtk::MenuItem( $label );
Vous pouvez sélectionner, déselectionner et activer un item de menu à l'aide de :
$menuitem->select(); $menuitem->deselect(); $menuitem->activate();
Si vous voulez faire d'un item de menu un sous-menu, vous pouvez utiliser :
$menuitem->set_submenu( $menu );
Vous pouvez aussi enlever un sous-menu :
$menuitem->remove_submenu();
Enfin, si vous voulez que le menu soit justifié à droite dans la barre de menu, comme le sont souvent les menus d'aide, vous pouvez utiliser la fonction suivante avant de l'attacher à la barre de menus.
$menu_item->right_justify();
Il y a deux manières de créer des menus : la facile et la difficile. Chacune a son usage mais vous pouvez habituellement utiliser l'usine à items ( ItemFactory, méthode facile ). La manière ``difficile'' est de créer directement tous les menus en utilisant les fonctions précédentes. La manière ``facile'' consiste à utiliser les appels de l'usine à items. C'est plus simple mais il y a des avantages et des inconvénients à chacune des approches.
L'usine à items est bien plus facile à utiliser et on peut y ajouter de nouveaux menus bien que d'écrire quelques fonctions en utilisant la méthode manuelle puisse être d'un grand secours. Avec l'usine à items, il n'est pas possible d'ajouter des images ou des caractères ``/'' aux menus.
Par pure tradition pédagogique, nous vous montrerons d'abord la méthode difficile. Le widget ItemFactory étant décrit ultérieurement.
Trois choses sont nécessaires pour créer une barre de menus et des sous-menus :
Quand un menu est créé, il n'est en fait jamais montré ( avec la fonction show()),
c'est juste un conteneur pour les items de menus. J'espère que ceci deviendra
plus clair en regardant les exemples ci-dessous.
Une fois que vous avez créé votre item de menu, vous devez le mettre dans un
menu. On y parvient avec la fonction append() . Afin de capturer le
moment ou l'item de menu est sélectionné par l'utilisateur, nous aurons besoin
de connecter le signal 'activate'. Ainsi, si vous voulez créer un menu
Fichier standard avec les fonctions Ouvrir, Sauver et Quitter, le code ressemblera
à :
$fichier_menu = new Gtk::Menu(); # Créer les items du menu $item_ouvrir = new Gtk::MenuItem( "Ouvrir" ); $item_sauver = new Gtk::MenuItem( "Sauver" ); $item_quitter = new Gtk::MenuItem( "Quitter" ); # Les ajouter au menu $fichier_menu->append( $item_ouvrir ); $fichier_menu->append( $item_sauver ); $fichier_menu->append( $item _quitter); # Attacher les fonctions de rappels au signal activate $item_ouvrir->signal_connect( 'activate', \&ouvrir_fichier ); $item_sauver->signal_connect( 'activate', \&sauver_fichier ); $item_quitter->signal_connect( 'activate', \&quitter_fichier ); # Nous n'avons pas besoin de montrer le menu mais nous devons montrer les items de menus $item_ouvrir->show(); $item_sauver->show(); $item_quitter->show();
A ce moment, nous avons notre menu. Maintenant nous créons notre barre de menus et notre item menu pour l'entrée Fichier auquel nous ajoutons notre menu. On obtient :
$menu_bar = new Gtk::MenuBar(); $window->add( $menu_bar ); $menu_bar->show(); $item_fichier = new Gtk::MenuItem( "Fichier" ); $item_fichier->show();
Maintenant, on a besoin d'associer notre menu avec $fichier_menu. Cela
est fait avec la fonction set_submenu(). Tout ce qui reste à faire est
d'ajouter le menu à la barre de menus, ce qui est accompli avec le fonction
append().
Voici un résumé des étapes nécessaires à la création d'une barre de menus avec des menus attachés :
new Gtk::Menu().
new Gtk::MenuItem() pour chaque item que
vous voulez voir apparaître au menu. Puis utiliser append() pour placer
chacun de ces items au menu.
new Gtk::MenuItem(). Il s'agira de la racine
du menu, le texte apparaissant ici sera dans la barre de menus elle-même.
set_submenu() pour attacher le menu à la racine de l'item menu
(créé à l'étape précédente).
new Gtk::MenuBar(). Cette étape
ne doit être faite que quand on a une série de menus à placer dans la barre
de menus.
append() pour placer le menu racine dans la barre de menu.
popup() d'un évènement bouton pressé, par exemple.
Les étapes sont donc :
event comme un évènement bouton ( ce qu'il est !) et
utiliser le comme dans l'exemple suivant pour passer l'information à la fonction
popup().
signal_connect().
Regardons un petit exemple pour essayer de nous clarifier les idées.
#!/usr/bin/perl -wuse Gtk;
use strict;
init Gtk;
my $false = 0;
my $true = 1;
my $i;
my $window;
my $menu;
my $menubar;
my $root_menu;
my $menu_item;
my $vbox;
my $button;
# Crée une nouvelle fenêtre
$window = new Gtk::Window( 'toplevel' );
$window->set_usize( 200, 100 );
$window->set_title( "GTK Menu Test" );
$window->signal_connect( 'delete_event', sub { Gtk->exit( 0 ); } );
# Initialise le widget menu ,et rappelez-vous: ne jamais montrer
# le widget menu !!
# C'est le menu qui contient les items du menus, celui qui apparaîtra quand
# vous cliquerez sur le "Root Menu" de l'aplication
$menu = new Gtk::Menu();
# Ensuite, on fait une petite boucle qui crée trois entrées menus pour le
# ``test-menu''. Noter l'appel à append(). Là, nous ajoutons une liste d'items
# de menus à notre menu. Normalement, nous devrions aussi attraper le signal
# ``cliqué'' sur chacun des items du menu et installer un rappel pour lui,
# mais on l'omet ici pour gagner de la place.
for ( $i = 0; $i < 3; $i++ ) { my $buffer; # Copie les noms dans le buffer $buffer = "Test-undermenu - $i"; # Crée un nouveau item menu avec un nom... $menu_item = new Gtk::MenuItem( $buffer ); # et l'ajoute au menu $menu->append( $menu_item ); # Fait quelque chose d'intéressant quand le menu est sélectionné. $menu_item->signal_connect( 'activate', sub { print( "$buffer\n" ); } ); #Montre le widget $menu_item->show(); }
# Il s'agit du menu Root, et ce sera le label affiché sur la barre de menus.
# Il n'y aura pas de gestionnaire attaché, comme il n'affiche le reste du menu
# que quand il est pressé
$root_menu = new Gtk::MenuItem( "Root Menu" );
$root_menu->show();
# Maintenant, nous spécifions que nous voulons que notre ``menu'' nouvellement
# créé soit le menu du "root menu"
$root_menu->set_submenu( $menu );
# Une vbox pour y placer un menu et un bouton :
$vbox = new Gtk::VBox( $false, 0 );
$window->add( $vbox );
$vbox->show();
# Crée une barre de menus qui contient nos menus et l'ajoute à notre fenêtre
$menubar = new Gtk::MenuBar();
$vbox->pack_start( $menubar, $false, $false, 2 );
$menubar->show();
# Crée un bouton auquel attacher le menu en tant que popup
$button = new Gtk::Button( "Press Me" );
$button->signal_connect( 'event', \&button_press, $menu );
$vbox->pack_end( $button, $true, $true, 2 );
$button->show();
# Enfin, nous ajoutons les items du menu à la barre de menus - c'est
# l'item de menu ``root'' à propos duquel je m'excitais tout à l'heure :-)
$menubar->append( $root_menu );
# Toujours afficher la fenêtre en dernier pour qu'elle apparaisse d'un coup
# sur l'écran
$window->show();
main Gtk;
exit( 0 );
### Routines
# Réponds au bouton pressé en plaçant un menu passé comme widget.
# Noter que l'argument ``widget'' est le menu placé,
# et NON le bouton qui fût pressé.
sub button_press { my ( $button, $menu, $event ) = @_; if ( defined( $event->{ 'type' } ) and ( $event->{ 'type' } eq 'button_press' ) ) { $menu->popup( undef, undef, $event->{'time'}, $event->{'button'}, undef ); # Dit au code appelant que nous avons capté cet évènement, le lièvre # s'arrête là. return ( $true ); } # Dit au code appelant que nous n'avons pas capté cet évènement, continuez. return ( $false ); }