Outils pour utilisateurs

Outils du site


barre_de_menu

Modèles pour la réalisation d'une barre de menu

Comme je n'ai pas envie de réinventer la poudre à chaque fois, je mettrai ici des modèles qui marchent pour réaliser une barre de menu, et je les enrichirai au fur et à mesure.

La barre de menu, située en haut de la fenêtre, comporte ici 2 items: “Fichier” et “Aide”. Un clic sur l'un de ces 2 items fait apparaitre une petite fenêtre avec des items qui, lorsqu'ils sont cliqués par la souris, déclenchent des actions décrites dans les fonctions appelées (Ouvrir, Fermer, etc…).

Vous noterez aussi l'option “underline=” qui désigne le caractère de l'item qui sera souligné et qui permettra à l'item d'être appelé directement au clavier par alt-caractère. Les enchainements de plusieurs commandes alt sont possibles, à condition de ne pas relâcher la touche alt entre 2 commandes.

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import Tkinter
 
class Application(Tkinter.Frame):
 
    def __init__(self, master=None):
        Tkinter.Frame.__init__(self, master, background="grey")
 
        # creation de la barre de menu:
        self.barremenu = Tkinter.Menu(self.master)
 
        # creation du menu "Fichier"
        self.fichier = Tkinter.Menu(self.barremenu, tearoff=0)
        self.barremenu.add_cascade(label="Fichier", underline=0, menu=self.fichier)
        self.fichier.add_command(label="Ouvrir", underline=0, command=self.ouvrir)
        self.fichier.add_command(label="Fermer", underline=0, command=self.fermer)
        self.fichier.add_command(label="Enregistrer", underline=0, command=self.enregistrer)
        self.fichier.add_command(label="Quitter", underline=0, command=self.quitter)
 
        # creation du menu "Aide"
        self.aide = Tkinter.Menu(self.barremenu, tearoff=0)
        self.barremenu.add_cascade(label="Aide", underline=0, menu=self.aide)
        self.aide.add_command(label="Manuel", underline=0, command = self.manuel)
        self.aide.add_command(label="A propos", underline=0, command = self.apropos)
 
        # afficher le menu
        self.master.config(menu=self.barremenu)
 
    def ouvrir(self): print "Ouvrir"
    def fermer(self): print "fermer"
    def enregistrer(self): print "enregistrer"
    def quitter(self): self.master.destroy()
    def manuel(self): print "manuel"
    def apropos(self): print "apropos"
 
#############################################################################
fen=Tkinter.Tk()
fen.title("Ma fenêtre")
app=Application(fen)
fen.geometry("%dx%d%+d%+d" % (300,300,100,100))
fen.mainloop()

Désactiver et réactiver un item de menu

Cas d'un item normal du menu

Pour construire un item de menu désactivé au démarrage de la fenêtre, il suffit d'ajouter l'option “state=Tkinter.DISABLED” dans la liste des options d'un add_commande.

Par exemple, pour avoir l'item “Enregistrer” du menu Fichier désactivé au départ:

self.fichier.add_command(label="Enregistrer", underline=0, state=Tkinter.DISABLED, command=self.enregistrer)

Pour réactiver l'item à partir d'une des méthodes appelées (l'item est le 3ème item du menu, donc à l'indice 2):

self.fichier.entryconfig(2,state=Tkinter.NORMAL)

et pour désactiver de nouveau:

self.fichier.entryconfig(2,state=Tkinter.DISABLED)

Cas d'un item de la barre de menu

Pour faire la même chose avec l'un des items de la barre de menu, par exemple ici, l'item “Aide”:

Pour désactiver l'item au départ:

self.barremenu.add_cascade(label="Aide",menu=self.aide, state=Tkinter.DISABLED)

Pour l'activer à partir d'une méthode:

self.barremenu.entryconfigure(3,state=Tkinter.NORMAL)

Et pour le désactiver de nouveau:

self.barremenu.entryconfigure(3,state=Tkinter.DISABLED)

Vous noterez une différence avec le cas précédent: l'item “Aide” de la barre de menu est le 3ème menu, son index devrait être “2” et en fait il est “3” (???).

Séparateur de menu

Il suffit d'ajouter entre deux items du menu, la méthode .add_separator(). Par exemple, dans le code précédent, ajoutez avant l'item “Quitter” du menu Fichier:

self.fichier.add_separator()

Ajouter un item de la barre de menu qui déclenche directement une action

Par exemple, entre l'item “Fichier” et l'item “Aide” de la barre de menu, on va ajouter un item “Calculer” qui, lorsqu'il sera cliqué, déclenchera directement une action:

Dans le code de base ci-dessus, avant la création de l'item “Aide”, ajoutez simplement:

self.barremenu.add_command(label="Calculer", command=self.calculer)

Et, bien sûr, la méthode qui va être appelée:

def calculer(self): print "calculer"

Avoir un item du menu qui change un drapeau

Par exemple, on va ajouter dans le menu “Fichier” un item qui s'appelle “Drapeau”, qui pourra avoir une coche devant.

A chaque fois qu'on le sélectionne, il change (coché → non-coché → coché → etc…)

self.drap=Tkinter.IntVar()
self.drap.set(0)  # initialisation: item non coché au départ
self.fichier.add_checkbutton(label="Drapeau", command=self.drapeau, variable=self.drap)

Si la coche doit être mise au départ, il suffit d'initialiser la variable self.drap avec 1:

self.drap.set(1)

Et bien sûr, la méthode appelée qui fait des choses différentes en fonction de la valeur de self.drap.get():

def drapeau(self):
    #on peut tester ici self.drap.get() qui passe a 0 ou a 1 selon la coche de l'item "drapeau" du menu.
    print "drapeau"

Avoir des choix exclusifs entre plusieurs item

On va placer 3 items dans le menu Action, qui comporteront une coche devant pour le dernier item sélectionné.

Les choix s'excluent: la sélection d'un item le coche, mais aussi décoche l'item précédemment choisi (comme des boutons radio).

Vous voyez l'utilisation de la variable nitem de type Tkinter.IntVar(). Elle est mise à 1 au départ (=1er choix coché). Elle est ensuite mise à 1, 2 ou 3 selon le dernier choix effectué. Les 3 items du choix exclusif appellent la même méthode (ici item()) qui peut tester le dernier choix fait (=la valeur de nitem) par self.nitem.get().

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import Tkinter
 
class Application(Tkinter.Frame):
 
    def __init__(self, master=None):
        Tkinter.Frame.__init__(self, master, background="grey")
 
        # creation de la barre de menu:
        self.barremenu = Tkinter.Menu(self.master)
 
        # creation du menu "Fichier"
        self.fichier = Tkinter.Menu(self.barremenu, tearoff=0)
        self.barremenu.add_cascade(label="Fichier",menu=self.fichier)
        self.fichier.add_command(label="Ouvrir", command=self.ouvrir)
        self.fichier.add_command(label="Fermer", command=self.fermer)
        self.fichier.add_command(label="Enregistrer", command=self.enregistrer)
        self.fichier.add_command(label="Quitter", command=self.quitter)
 
        # creation du menu "Action"
        self.action = Tkinter.Menu(self.barremenu, tearoff=0)
        self.barremenu.add_cascade(label="Action",menu=self.action)
        self.action.add_command(label="Format", command=self.format)
        self.action.add_separator()
 
        self.nitem=Tkinter.IntVar()
        self.nitem.set(1)
        self.action.add_radiobutton(label="item1", command=self.item, variable=self.nitem, value=1)
        self.action.add_radiobutton(label="item2", command=self.item, variable=self.nitem, value=2)
        self.action.add_radiobutton(label="item3", command=self.item, variable=self.nitem, value=3)
 
        self.action.add_separator()
        self.action.add_command(label="Configuration", command=self.configuration)
 
        # creation du menu "Aide"
        self.aide = Tkinter.Menu(self.barremenu, tearoff=0)
        self.barremenu.add_cascade(label="Aide",menu=self.aide)
        self.aide.add_command(label="Manuel", command = self.manuel)
        self.aide.add_command(label="A propos", command = self.apropos)
 
        # afficher le menu
        self.master.config(menu=self.barremenu)
 
    def ouvrir(self): print "Ouvrir"
    def fermer(self): print "fermer"
    def enregistrer(self): print "enregistrer"
    def quitter(self): self.master.destroy()
    def format(self): print "format"
    def item(self): print "item: ", self.nitem.get()
    def configuration(self): print "configuration"
    def manuel(self): print "manuel"
    def apropos(self): print "apropos"
 
#############################################################################
fen=Tkinter.Tk()
fen.title("Ma fenêtre")
app=Application(fen)
fen.geometry("%dx%d%+d%+d" % (300,300,100,100))
fen.mainloop()

Avoir des sous-menus en cascades

On va faire en sorte que l'item “Titre” du menu “Action” affiche un fenêtre supplémentaire avec des items de menu à sélectionner.

On voit aussi dans cet exemple comment on peut transmettre une valeur en sélectionnant un item de menu avec lambda:

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import Tkinter
 
class Application(Tkinter.Frame):
 
    def __init__(self, master=None):
        Tkinter.Frame.__init__(self, master, background="grey")
 
        # creation de la barre de menu:
        self.barremenu = Tkinter.Menu(self.master)
 
        # creation du menu "Fichier"
        self.fichier = Tkinter.Menu(self.barremenu, tearoff=0)
        self.barremenu.add_cascade(label="Fichier",menu=self.fichier)
        self.fichier.add_command(label="Ouvrir", command=self.ouvrir)
        self.fichier.add_command(label="Fermer", command=self.fermer)
        self.fichier.add_command(label="Enregistrer", command=self.enregistrer)
        self.fichier.add_command(label="Quitter", command=self.quitter)
 
        # creation du menu "Action"
        self.action = Tkinter.Menu(self.barremenu, tearoff=0)
        self.barremenu.add_cascade(label="Action",menu=self.action)
        self.action.add_command(label="Format", command=self.format)
 
        # creation du sous-menu "Titre" du menu "Action"
        self.titre = Tkinter.Menu(self.action, tearoff=0)
        self.action.add_cascade(label="Titre",menu=self.titre)
        self.titre.add_command(label="Demo", command=lambda : self.changetitre('Demo'))
        self.titre.add_command(label="Test", command=lambda : self.changetitre('Test'))
 
        self.action.add_command(label="Configuration", command=self.configuration)
 
        # creation du menu "Aide"
        self.aide = Tkinter.Menu(self.barremenu, tearoff=0)
        self.barremenu.add_cascade(label="Aide",menu=self.aide)
        self.aide.add_command(label="Manuel", command = self.manuel)
        self.aide.add_command(label="A propos", command = self.apropos)
 
        # afficher le menu
        self.master.config(menu=self.barremenu)
 
    def ouvrir(self): print "Ouvrir"
    def fermer(self): print "fermer"
    def enregistrer(self): print "enregistrer"
    def quitter(self): self.master.destroy()
    def format(self): print "format"
    def changetitre(self,choix): self.master.title(choix)
    def configuration(self): print "configuration"
    def manuel(self): print "manuel"
    def apropos(self): print "apropos"
 
#############################################################################
fen=Tkinter.Tk()
fen.title("Ma fenêtre")
app=Application(fen)
fen.geometry("%dx%d%+d%+d" % (300,300,100,100))
fen.mainloop()

Changement de la police de caractères des menus

On va utiliser la même solution qu'avec les autres widgets.

1- Importer tkFont en plus de Tkinter (attention: les majuscules comptent!)

2- Instancier la classe tkFont.Font(), par exemple policemenu=tkFont.Font(), et lui fournir comme arguments les caractéristiques de la police voulue.

3- ajouter l'option “font=policemenu” à la création de chacun des items de la barre de menu.

NB: on ne change pas la police de la barre des menus elle-même, mais seulement des fenêtres d'items qui sont appelées par eux.

Les options possibles sont:

  • family=“Arial” ou “Times” ou Helvetica“ ou “Courier” etc…
  • size= la taille de la police en nombre de points (ex: size=10)
  • weight=tkFont.NORMAL ou tkFont.BOLD (=gras)
  • slant=tkFont.NORMAL ou tkFont.ITALIC (=italic)
  • overstrike=1 (barré) ou 0 (non barré)
  • name= nom donné à cette configuration de police

Exemple: dans le code suivant, les items du menu apparaissent en arial gras italic taille 10:

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import Tkinter, tkFont
 
class Application(Tkinter.Frame):
 
    def __init__(self, master=None):
        Tkinter.Frame.__init__(self, master, background="grey")
 
        policemenu=tkFont.Font(self, size=10, family='Arial', weight=tkFont.BOLD, slant=tkFont.ITALIC)
 
        # creation de la barre de menu:
        self.barremenu = Tkinter.Menu(self.master)
 
        # creation du menu "Fichier"
        self.fichier = Tkinter.Menu(self.barremenu, tearoff=0, font=policemenu)
        self.barremenu.add_cascade(label="Fichier",menu=self.fichier)
        self.fichier.add_command(label="Ouvrir", command=self.ouvrir)
        self.fichier.add_command(label="Fermer", command=self.fermer)
        self.fichier.add_command(label="Enregistrer", command=self.enregistrer)
        self.fichier.add_separator()
        self.fichier.add_command(label="Quitter", command=self.quitter)
 
          # creation du menu "Aide"
        self.aide = Tkinter.Menu(self.barremenu, tearoff=0, font=policemenu)
        self.barremenu.add_cascade(label="Aide",menu=self.aide)
        self.aide.add_command(label="Manuel", command = self.manuel)
        self.aide.add_command(label="A propos", command = self.apropos)
 
        # afficher le menu
        self.master.config(menu=self.barremenu)
 
    def ouvrir(self): print "Ouvrir"
    def fermer(self): print "fermer"
    def enregistrer(self): print "enregistrer"
    def quitter(self): self.master.destroy()
    def manuel(self): print "manuel"
    def apropos(self): print "apropos"
 
#############################################################################
fen=Tkinter.Tk()
fen.title("Ma fenêtre")
app=Application(fen)
fen.geometry("%dx%d%+d%+d" % (300,300,100,100))
fen.mainloop()

Changement de la couleur des menus

On peut changer la couleur de la police, la couleur de fond ainsi que la couleur de la barre de sélection au passage de la souris. Cela ne concerne pas les items de la barre de menu eux-même, mais des fenêtres d'items qui sont appelées par eux.

  • fg (ou foreground) change la couleur des caractères
  • bg (ou background) change le fond
  • activebackground change la couleur de la barre de sélection du menu
  • activeforeground change la couleur des caractères dans la barre de sélection du menu

La couleur peut être définie par les noms habituels ('red' = rouge, 'blue' = bleu, etc…), ou par des valeurs hexadécimales.

Comme pour le changement de police, il faut provoquer la modification pour chacun des items de la barre de menu.

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import Tkinter
 
class Application(Tkinter.Frame):
 
    def __init__(self, master=None):
        Tkinter.Frame.__init__(self, master, background="grey")
 
        # creation de la barre de menu:
        self.barremenu = Tkinter.Menu(self.master)
 
        # creation du menu "Fichier"
        self.fichier = Tkinter.Menu(self.barremenu, tearoff=0, bg='yellow', fg='green', activebackground='red', activeforeground='yellow')
        self.barremenu.add_cascade(label="Fichier",menu=self.fichier)
        self.fichier.add_command(label="Ouvrir", command=self.ouvrir)
        self.fichier.add_command(label="Fermer", command=self.fermer)
        self.fichier.add_command(label="Enregistrer", command=self.enregistrer)
        self.fichier.add_separator()
        self.fichier.add_command(label="Quitter", command=self.quitter)
 
          # creation du menu "Aide"
        self.aide = Tkinter.Menu(self.barremenu, tearoff=0, bg='yellow', fg='green', activebackground='red', activeforeground='yellow')
        self.barremenu.add_cascade(label="Aide",menu=self.aide)
        self.aide.add_command(label="Manuel", command = self.manuel)
        self.aide.add_command(label="A propos", command = self.apropos)
 
        # afficher le menu
        self.master.config(menu=self.barremenu)
 
    def ouvrir(self): print "Ouvrir"
    def fermer(self): print "fermer"
    def enregistrer(self): print "enregistrer"
    def quitter(self): self.master.destroy()
    def manuel(self): print "manuel"
    def apropos(self): print "apropos"
 
#############################################################################
fen=Tkinter.Tk()
fen.title("Ma fenêtre")
app=Application(fen)
fen.geometry("%dx%d%+d%+d" % (300,300,100,100))
fen.mainloop()

Faire en sorte que les codes clavier soient calés à droite

On veut qu'un menu se présente un peu comme cela (exemple des items d'un menu de type “Fichier”):

Ouvrir        Ctrl+O
Fermer        Ctrl+W
Enregistrer   Ctrl+S
Quitter       Alt+X

C'est à dire que les raccourcis commandes claviers sont alignés.

Le problème, c'est que dans une police de caractères type “arial”, les caractères n'ont pas tous la même largeur en pixels à l'écran.

Solution "normale" avec l'option "accelerator"

J'ai mis pas mal de temps à trouver cette option qui ne se trouve pas dans tous les manuels.

Au lieu de faire par exemple:

self.edition.add_command(label="Copier   Ctrl-C", underline=2, command = self.copier)

On fait:

self.edition.add_command(label="Copier", accelerator="Ctrl-C", underline=2, command = self.copier)

Et les différents codes de commande clavier d'un même menu et cités par accelerator, seront alignés

Solution avec "measure"

Je cite cette solution pour mémoire et parce que c'est un exemple d'utilisation de la méthode “measure” qui peut servir à d'autres choses.

On va utiliser une des fonctions du module tkFont: “measure(texte)”, qui mesure en pixel la longueur d'un texte. Et on ajustera à la fin avec des espaces.

L'alignement n'est pas parfait: on peut faire une erreur maxi égale au nombre de pixels d'un espace - 1. Mais c'est tout de même très bien!

l'alignement choisi ici est de caler les codes clavier à droite. Mais on pourrait aussi les aligner sur leur 1er caractère en modifiant le code.

La fonction qui ajuste l'item s'appelle ici: ajusteitems().

Voilà le code (il est auto-documenté):

#!/usr/bin/python
# -*- coding: utf-8 -*-
 
import Tkinter, tkFont
 
class Application(Tkinter.Frame):
 
    def __init__(self, master=None):
        Tkinter.Frame.__init__(self, master, background="grey")
 
        self.policemenu=tkFont.Font(self, size=9, family='Arial')
 
        # creation de la barre de menu:
        self.barremenu = Tkinter.Menu(self.master)
 
        # représentation des items du menu "Fichier" sous forme de liste:
        self.itemmenu=[
                  ["Ouvrir", "Ctrl+O"],
                  ["Fermer", "Ctrl+W"],
                  ["Enregistrer", "Ctrl+S"],
                  ["Quitter", "Alt+X"]
                      ]
        items=self.ajusteitems(self.itemmenu)
 
        # creation du menu "Fichier"
        self.fichier = Tkinter.Menu(self.barremenu, tearoff=0, font=self.policemenu)
        self.barremenu.add_cascade(label="Fichier",menu=self.fichier)
        self.fichier.add_command(label=items[0], command=self.ouvrir)
        self.fichier.add_command(label=items[1], command=self.fermer)
        self.fichier.add_command(label=items[2], command=self.enregistrer)
        self.fichier.add_separator()
        self.fichier.add_command(label=items[3], command=self.quitter)
 
        # représentation des items du menu "Aide" sous forme de liste:
        self.itemmenu=[
                  ["Manuel", "F1"],
                  ["A propos", ""]
                      ]
        items=self.ajusteitems(self.itemmenu)
 
          # creation du menu "Aide"
        self.aide = Tkinter.Menu(self.barremenu, tearoff=0, font=self.policemenu)
        self.barremenu.add_cascade(label="Aide",menu=self.aide)
        self.aide.add_command(label=items[0], command = self.manuel)
        self.aide.add_command(label=items[1], command = self.apropos)
 
        # afficher le menu
        self.master.config(menu=self.barremenu)
 
    def ajusteitems(self, itemmenu):
        # Calcul de la longueur maxi en pixels des items du menu fichier:
        lg=0
        for i1, i2 in itemmenu:
            lg1=self.policemenu.measure(i1)
            lg2=self.policemenu.measure(i2)
            if lg1+lg2>lg:
                lg=lg1+lg2
        esp=self.policemenu.measure(" ")  # = nb de pixels d'un espace
        lg=lg+2*esp  # ajout de 2 espaces
 
        # Ajustement des espaces pour que les commandes clavier soient calées à droite
        lch=[]
        for i1, i2 in self.itemmenu:
            lg1=self.policemenu.measure(i1)
            lg2=self.policemenu.measure(i2)
            n=(lg-lg1-lg2)/esp
            lch.append(i1 + " "*n + i2)
        return lch
 
    def ouvrir(self): print "Ouvrir"
    def fermer(self): print "fermer"
    def enregistrer(self): print "enregistrer"
    def quitter(self): self.master.destroy()
    def manuel(self): print "manuel"
    def apropos(self): print "apropos"
 
#############################################################################
fen=Tkinter.Tk()
fen.title("Ma fenêtre")
app=Application(fen)
fen.geometry("%dx%d%+d%+d" % (300,300,100,100))
fen.mainloop()

barre_de_menu.txt · Dernière modification: 2008/07/08 07:40 par tyrtamos

Outils de la page