IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Apprendre à utiliser le module Python PyGTK 2.0


précédentsommairesuivant

XI. Chapitre 11. Les menus

Il y a deux méthodes de création des menus : la facile et la difficile. Toutes deux ont leur utilité, bien que dans la plupart des cas l'ItemFactory (la méthode facile) suffise. La méthode "difficile" consiste à créer tous les menus en les appelant directement, là où la méthode facile utilisera les appels de GtkItemFactory. Même si c'est effectivement beaucoup plus simple, des avantages et des inconvénients existent pour chaque approche.

Il est vrai que l'Itemfactory rend nettement plus simples la création et l'ajout ultérieur de menus ; mais faire la même chose manuellement, à l'aide de quelques fonctions, peut apporter beaucoup en termes d'ergonomie. Avec l'Itemfactory, vous ne pourrez pas ajouter d'images aux menus, ni y faire figurer le caractère "/".

XI-A. Création manuelle de menus

Comme le veut la bonne vieille tradition pédagogique, nous commençons par la méthode difficile :).

Trois widgets entrent en jeu dans la création d'une barre de menu et de ses sous-menus :

  • l'entrée de menu, qui représente ce que l'utilisateur veut faire/choisir (par exemple "Enregistrer") ;
  • le menu, qui contient les entrées de menu ;
  • la barre de menu, qui contient les menus.

Mais tout n'est pas si simple. En effet, les entrées de menu servent à deux choses : elles représentent à la fois les widgets placés dans le menu et celui placé dans la barre de menu (celui qui, une fois sélectionné, active le menu).

Observons les fonctions servant à créer menus et barres de menus :

 
Sélectionnez
  barre_menus = gtk.MenuBar()

Cette première fonction, vous l'aurez deviné, crée une nouvelle barre de menu. On utilisera la méthode add() de GtkContainer pour la placer dans une fenêtre, ou bien les différentes méthodes pack() de GtkBox pour la placer dans une boite (comme pour les boutons).

 
Sélectionnez
  menu = gtk.Menu()

Cette fonction renvoie une référence à un nouveau menu ; il n'est jamais concrètement affiché (par la méthode show()), c'est juste un conteneur pour les entrées de menu. Tout ceci vous paraîtra, je l'espère, beaucoup plus clair après que vous aurez jeté un œil à l'exemple plus bas.

La fonction ci-dessous sert à créer les entrées qui seront placées dans le menu (et la barre de menu) :

 
Sélectionnez
  entree = gtk.MenuItem(label=None)

L'argument label (étiquette), si spécifié, sera parcouru à la recherche de caractères mnémoniques. Cet appel crée les entrées de menu qui doivent apparaitre dans le menu. Attention à ne pas confondre le "menu", créé avec gtk.Menu(), et l'"entrée de menu", créée avec la fonction gtk.MenuItem(). L'entrée sera un véritable bouton, auquel sera associée une action, tandis que le menu sera un conteneur renfermant des entrées.

Une fois votre entrée créée, vous devez la placer dans un menu grâce à la méthode append(). Puis, pour pouvoir réagir à une sélection de cette entrée par l'utilisateur, il faudra capter son signal "activate" (activer) de la manière habituelle.

Imaginons que nous voulions créer un menu "Fichier" standard, avec les entrées Ouvrir, Enregistrer, et Quitter. Notre code devrait alors ressembler à ceci :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
  menu_fichier = gtk.Menu()    # Inutile d'afficher les menus avec show()

  # Création des entrées de menu
  entree_ouvrir = gtk.MenuItem("Ouvrir")
  entree_enreg = gtk.MenuItem("Enregistrer")
  entree_quitter = gtk.MenuItem("Quitter")

  # On les place dans le menu
  menu_fichier.append(entree_ouvrir)
  menu_fichier.append(entree_enreg)
  menu_fichier.append(entree_quitter)

  # On connecte les fonctions de rappel au signal "activate"
  entree_ouvrir.connect_object("activate", entrees_reponse, "fichier.ouvrir")
  entree_enreg.connect_object("activate", entrees_reponse, "fichier.enregistrer")

  # On peut connecter l’entrée Quitter à notre fonction de sortie
  entree_quitter.connect_object ("activate", destroy, "fichier.quitter")

  # Il nous faut afficher les entrées
  entree_ouvrir.show()
  entree_enreg.show()
  entree_quitter.show()

Nous avons maintenant notre menu. Il nous reste à créer une barre de menu, puis une entrée "Fichier" à laquelle nous relierons notre menu. Le code pour ce faire est le suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
  barre_menus = gtk.MenuBar()
  fenetre.add(barre_menus)
  barre_menus.show()

  entree_fichier = gtk.MenuItem("Fichier")
  entree_fichier.show()

Maintenant associons le menu avec entree_fichier. On fait appel pour cela à la méthode suivante :

 
Sélectionnez
  entree.set_submenu(sous_menu)

Ce qui donnerait, pour la suite de notre exemple :

 
Sélectionnez
  entree.set_submenu(menu_fichier)

Tout ce qui nous reste à faire est de placer le menu dans la barre de menu, en utilisant la méthode :

 
Sélectionnez
  barre_menus.append(enfant)

qui, dans notre cas, donne :

 
Sélectionnez
  barre_menus.append(entree_fichier)

Si nous voulions aligner notre menu sur la droite de la barre de menu, comme le sont souvent les menus d'aide, nous pourrions faire appel à la méthode ci-dessous (toujours sur entree_fichier dans notre exemple) avant de l'attacher à la barre de menu.

 
Sélectionnez
  entree.set_right_justified(align_droite)

Voici un résumé des étapes nécessaires à la céation d'une barre de menus avec ses menus :

  • créez un nouveau menu avec gtk.Menu() ;
  • faites un appel à gtk.MenuItem() pour chaque entrée que vous voulez voir figurer dans votre menu, puis utilisez la méthode append() pour placer chacune de ces nouvelles entrées dans le menu ;
  • créez une entrée avec gtk.MenuItem(). Ce sera la racine du menu, son étiquette apparaitra directement dans la barre de menus.
  • Utilisez la méthode set_submenu() pour attacher le menu à l'entrée racine (celle créée à l'étape précédente) ;
  • créez une barre de menu avec gtk.MenuBar(). Si l'on crée une série de menus que l'on veut placer sur une seule barre de menu, cette étape n'a besoin d'être effectuée qu'une seule fois ;
  • utilisez la méthode append() pour placer la racine dans la barre de menu.

Le procédé de création d'un menu popup est plus ou moins identique. La différence est que le menu n'est pas affiché "automatiquement" par une barre de menu, mais explicitement par un appel à la méthode popup(), lors d'un événement "button-press", par exemple. Procédez comme suit :

  • créez une fonction de rappel gestionnaire d'événement. Elle doit être de la forme :

     
    Sélectionnez
      def fct_rappel(widget, evenement):

    et utilisera l'événement pour savoir où afficher le menu ;

  • dans le gestionnaire d'événement, si l'événement est une pression d'un bouton de la souris, traitez-le comme un événement bouton (ce qu'il est) et utilisez-le comme montré dans l'exemple de code pour transmettre l'information à la méthode popup() ;

  • attachez ce gestionnaire d'événement à un widget ainsi :
 
Sélectionnez
  widget.connect_object("evenement", fct_rappel, menu)

widget est le widget auquel vous connectez l'événement fct_rappel la fonction de rappel, et menu le menu crée par GtkMenu(). Ce dernier peut aussi être affiché par une barre d'état, comme dans notre code.

XI-B. Démonstration de création manuelle de menus

Voilà pour la théorie. Maintenant, jetons un œil du côté de l'exemple menu.py pour tenter de clarifier un peu tout ça. La Figure 11.1 nous montre la fenêtre du programme :

Image non disponible
Figure 11.1. Exemple de menu créé manuellement

Le code source de menu.py est le suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
#!/usr/bin/env python
   
# exemple menu.py
  
import pygtk
pygtk.require('2.0')
import gtk

class ExempleMenu:
    def __init__(self):
        # Création d'une fenêtre
        fenêtre = gtk.Window(gtk.WINDOW_TOPLEVEL)
        fenetre.set_size_request(200, 100)
        fenetre.set_title("Test menu GTK")
        fenetre.connect("delete_event", gtk.main_quit)

        # Initialisation du widget. Souvenez-vous : on n'affiche jamais
        # (avec show()) le widget menu !
        # Il s'agit du menu qui contiendra les commandes, celui qui apparaitra
        # après un clic sur le "Menu racine" de l'application.
        menu = gtk.Menu()

        # Ensuite, on écrit une petite boucle qui crée trois entrees pour le menu.
        # Notez l'appel à gtk_menu_append. Ici, nous ajoutons une liste de commandes
        # à notre menu. Nous devrions aussi nous débrouiller pour capter le signal
        # "clicked" de chacune des commandes et mettre en place une fonction de rappel
        # pour le traiter, mais pour ne pas faire trop long, on s'en passera ici.
        for i in range(3):
            # On copie les noms dans une variable "tampon".
            tampon = "Sous-menu test - %d" % i

            # On crée une nouvelle commande, avec un nom...
            commandes = gtk.MenuItem(tampon)

            # … et on l'ajoute au menu
            menu.append(commandes)

        # On réagit à la sélection de la commande
        commandes.connect("activate", self.reponse_commande, tampon)

            # On affiche le widget
            commandes.show()

        # Voici le menu racine. Ce sera aussi l'étiquette visible dans la barre de
        # menus. On ne lui connecte pas de gestionnaire de signal, son rôle étant
        # seulement de faire apparaitre le reste du menu lorsqu'on le clique.
        menu_racine = gtk.MenuItem("Menu racine")

        menu_racine.show()

        # Ici on indique que notre "menu" créé plus haut doit être le menu de 
        # "Menu racine"
        menu_racine.set_submenu(menu)

        # Une boite verticale pour y placer un menu et un bouton :
        boitev = gtk.VBox(False, 0)
        fenetre.add(boitev)
        boitev.show()

        # On crée une barre pour contenir les menus, et on la place dans notre fenêtre
        barre_menus = gtk.MenuBar()
        boitev.pack_start(barre_menus, False, False, 2)
        barre_menus.show()

        # Création d'un bouton, auquel on attache le menu comme popup
        bouton = gtk.Button("Cliquez-moi")
        bouton.connect_object("event", self.evnmt_button_press, menu)
        boitev.pack_end(bouton, True, True, 2)
        bouton.show()

        # Enfin, on rattache la commande à la barre de menu -- il s'agit de la commande
        # "Menu racine" sur laquelle je me suis emballé =)
        barre_menus.append (menu_racine)

        # Toujours afficher la fenêtre en dernier, afin qu'elle soit complète lors de
        # son apparition à l'écran.
        fenetre.show()

    # On répond à l'événement "button-press" en affichant un menu, qui est
    # transmis comme "widget".
    # Notez que l'argument "widget" N'EST PAS le bouton qui a été enfoncé,
    #, mais bien le menu à afficher
    def evnmt_button_press(self, widget, evenement):
        if evenement.type == gtk.gdk.BUTTON_PRESS:
            widget.popup(None, None, None, evenement.button, evenement.time)
            # On fait savoir au code appelant que l'on a traité l'événement. Son
            # histoire s'arrête ici.
            return True
        # On fait savoir au code appelant que l'événement n'a pas été traité. Il continue.
        return False

    # Affiche une chaine de caractères lorsqu'une commande est sélectionnée.
    def reponse_commande(self, widget, chaine):
        print "%s" % chaine

def main():
    gtk.main()
    return 0

if __name__ == "__main__":
    ExempleMenu()
    main()

Vous pouvez aussi n'affecter aucune réaction à la sélection d'une entrée de menu et, par l'intermédiaire d'une table de raccourcis-clavier, lier certaines touches aux fonctions de rappel du menu.

XI-C. Création de menus avec l'ItemFactory

À présent que nous avons vu la méthode difficile, voici comment faire la même chose avec les appels de gtk.ItemFactory.

XI-D. Démonstration de l'ItemFactory

La Figure 11.2 montre la fenêtre créée par le programme d'exemple itemfactory.py, qui utilise la gtk.ItemFactory :

Image non disponible
Figure 11.2. Exemple de menu créé avec l'ItemFactory

Voici le code source de itemfactory.py :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
#!/usr/bin/env python
  
# exemple itemfactory.py
  
import pygtk
pygtk.require('2.0')
import gtk
  
class ExempleItemFactory:
    # L'inévitable petite fonction de rappel
    def affiche_hello(self, w, donnees):
        print "Salut tout le monde !"

    # Voici la structure d'ItemFactoryEntry utilisée pour générer de nouveaux menus
    # Element 1: Le chemin du menu. la lettre qui suit le caractère "_" indique un 
    #            raccourci-clavier actif une fois le menu ouvert.
    # Element 2: Le raccourci-clavier pour cette entrée.
    # Element 3: La fonction de rappel.
    # Element 4: L'action de la fonction de rappel. Modifie les paramètres avec
    #            lesquels la fonction de rappel est appelée. 0 par défaut.
    # Element 5: Le type d'entrée. Indique quelle sorte d'entrée l'on souhaite créer.
    #            Voici les différentes valeurs possibles :

    #       NULL               -> ""
    #       ""                 -> ""
    #       "

précédentsommairesuivant

Copyright © 2005 John Finlay. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.