GtkFr - Cours Gtk+-2

PyLesMenus

PageAccueil :: LesNews :: Telechargement :: Liens :: Forum :: LeChat :: Contact
DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes 38.107.191.92
<< Les boutons (Partie 2) PyGtk La barre d'outils >>


Les Menus

1. Introduction

Avant toute chose, il faut savoir q'un menu est composé de plusieurs parties distinctes :
La barre de menu est l'élément principal qui contiendra des éléments. A chaque élément, nous pouvons associer un menu qui s'ouvrira lorsque l'utilisateur cliquera sur cet élément. Et chaque menu contiendra des éléments qui pourront ouvrir des sous-menus, etc...
En plus d'utiliser tous ces widgets, il faudra aussi le widget GtkMenuShell qui est une classe de base pour les widgets GtkMenuBar et GtkMenu.

1.1 Hiérarchie

GObject -> GtkObject -> GtkWidget -> GtkContainer -> GtkMenuShell -> GtkMenuBar
GObject -> GtkObject -> GtkWidget -> GtkContainer -> GtkMenuShell -> GtkMenu
GObject -> GtkObject -> GtkWidget -> GtkContainer -> GtkBin? -> GtkItem? -> GtkMenuItem
GObject -> GtkObject -> GtkWidget -> GtkContainer -> GtkBin? -> GtkItem? -> GtkMenuItem -> GtkImageMenuItem
GObject -> GtkObject -> GtkWidget -> GtkContainer -> GtkBin? -> GtkItem? -> GtkMenuItem -> GtkCheckMenuItem
GObject -> GtkObject -> GtkWidget -> GtkContainer -> GtkBin? -> GtkItem? -> GtkMenuItem -> GtkCheckMenuItem -> GtkRadioMenuItem
GObject -> GtkObject -> GtkWidget -> GtkContainer -> GtkBin? -> GtkItem? -> GtkMenuItem -> GtkSeparatorMenuItem
GObject -> GtkObject -> GtkWidget -> GtkContainer -> GtkBin? -> GtkItem? -> GtkMenuItem -> GtkTearoffMenuItem

2. Le principes

2.1 Les différentes étapes

La création d'un menu doit passer par au moins six étapes différentes :
Si par la suite, vous souhaitez ajouter d'autres menu, il suffit de recommencer à partir de l'étape 2.

2.2 Etape 1 : Création de l'élément GtkMenuBar

Cette étape, rapide et simple, se résume en l'utilisation d'une seule fonction :
menu_bar = gtk.MenuBar?()

2.3 Etape 2 : Création d'un élément GtkMenu

Cette fois aussi, une seule fonction est utilisée :
menu = gtk.Menu()

2.4 Etape 3 : Création des éléments GtkMenuItem (ou autres)

Dans un premier temps, il faut créer le GtkMenuItem grâce cette fonction :
menu_item = gtk.MenuItem?(label)
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(child)
menu.prepend(child)
Ces fonctions ne font pas partie du widget GtkMenu mais de GtkMenuShell qui est le widget dont GtkMenu dérive. La première fonction ajoute les éléments de haut en bas alors que la seconde les ajoute de bas en haut. Le paramètre menu_shell est le menu dans lequel nous voulons ajouter l'élément et le paramètre child est l'élément à ajouter.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.

2.5 Etape 4 : Création de l'élément GtkMenuItem qui ira dans l'élément GtkMenuBar

Il suffit d'utiliser une des fonctions de création du widget GtkMenuItem.

2.6 Etape 5 : Association de cet élément avec le menu créé précédemment

Il faut maintenant dire que lorsque l'utilisateur cliquera sur l'élément créer pendant l'étape 4, il faudra ouvrir le menu qui a été créé précédemment. La fonction adéquate est celle-ci :
menu_item.set_submenu(submenu)

2.7 Etape 6 : Ajout de l'élément GtkMenuItem dans la barre GtkMenuBar

GtkMenuBar dérivant aussi de GtkMenuShell, nous allons utiliser la même fonction que lors de l'étape 3 (gtk_menu_shell_append) pour ajouter le sous-menu au menu principal.

2.8 Programme exemple

Nous allons créer une fenêtre simple avec un menu "Fichier" et un menu "?".
# -*- Encoding: Latin-1 -*-
import gtk

def main():
    # Creation de la fenetre
    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.set_title("GtkMenu")
    window.set_default_size(320, 200)
    window.connect("destroy", gtk.main_quit, None)

    # Creation de la GtkVBox
    vbox = gtk.VBox(False, 0)
    window.add(vbox)

    #**** Creation du menu ****

    # ETAPE 1
    menu_bar = gtk.MenuBar()
    #** Premier sous-menu **
    # ETAPE 2
    menu = gtk.Menu()
    # ETAPE 3
    menu_item = gtk.MenuItem("Nouveau")
    menu.append(menu_item)

    menu_item = gtk.MenuItem("Ouvrir")
    menu.append(menu_item)

    menu_item = gtk.MenuItem("Enregistrer")
    menu.append(menu_item)

    menu_item = gtk.MenuItem("Fermer")
    menu.append(menu_item)

    menu_item = gtk.MenuItem("Quitter")
    menu_item.connect("activate", OnQuitter, window)
    menu.append(menu_item)
    # ETAPE 4
    menu_item = gtk.MenuItem("Fichier")
    # ETAPE 5
    menu_item.set_submenu(menu)
    # ETAPE 6
    menu_bar.append(menu_item)

    #* Second sous-menu *
    # ETAPE 2
    menu = gtk.Menu()
    # ETAPE 3
    menu_item = gtk.MenuItem("A propos de...")
    menu_item.connect("activate", OnAbout, window)
    menu.append(menu_item)
    # ETAPE 4
    menu_item = gtk.MenuItem("?")
    # ETAPE 5
    menu_item.set_submenu(menu)
    # ETAPE 6
    menu_bar.append(menu_item)

    # Ajout du menu a la fenetre
    vbox.pack_start(menu_bar, False, False, 0)

    window.show_all()

    gtk.main()

def OnQuitter(widget, data):
    question = gtk.MessageDialog(data,
        gtk.DIALOG_MODAL,
        gtk.MESSAGE_QUESTION,
        gtk.BUTTONS_YES_NO,
        "Voulez vous vraiment\n"
        "quitter le programme?")

    reponse = question.run()
    if reponse == gtk.RESPONSE_YES:
            gtk.main_quit()
    elif reponse in (gtk.RESPONSE_NONE, gtk.RESPONSE_NO):
            question.destroy()

def OnAbout(widget, data):
    about = gtk.MessageDialog(data,
        gtk.DIALOG_MODAL,
        gtk.MESSAGE_INFO,
        gtk.BUTTONS_OK,
        "Cours GTK+ 2.0\n"
        "http://www.gtk-fr.org")

    about.run()

    about.destroy()

if __name__ == '__main__':
    main()
Résultat :






3. Les éléments avancées d'un menu

En plus des GtkMenuItem, GTK+ offre cinq éléments de menu additionnels prêts à l'emploi : GtkImageMenuItem, GtkRadioMenuItem, GtkCheckMenuItem, GtkSeparatorMenuItem et GtkTearoffMenuItem.

3.1 Les GtkImageMenuItem

GtkImageMenuItem est un widget qui permet de créer une entrée de menu textuelle avec une icône juste devant.
Pour créer un GtkImageMenuItem, on a à disposition la classe :
image_menu_item = gtk.ImageMenuItem?(stock_id=None, accel_group=None) GtkWidget* gtk_image_menu_item_new_with_label(const gchar *label);
GtkWidget* gtk_image_menu_item_new_with_mnemonic(const gchar *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ée est peut être le GtkAccelGroup? *accel_group de gtk_image_menu_item_new_from_stock, qui sert à ajouter l'entrée à un GtkAccelGroup? 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 :
image_menu_item.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 gtk_image_menu_item_new_from_stock définit pour l'entrée lors de sa création.

La dernière fonction spécifique des GtkImageMenuItem est :
image = image_menu_item.get_image()
Elle sert, comme vous l'aurez deviné, à récupérer ce qui sert d'icône à l'entrée.

3.2 Les GtkCheckMenuItem

Le widget GtkCheckMenuItem est en fait un GtkCheckButton qui a été modifié afin de pouvoir êtreinséré dans des menus.
Les GtkCheckMenuItem émettent le signal "toggled" lorsqu'on les (dé)coche.

Les fonctions de création d'un GtkCheckMenuItem sont :
GtkWidget* gtk_check_menu_item_new(void);
GtkWidget* gtk_check_menu_item_new_with_label(const gchar *label);
GtkWidget* gtk_check_menu_item_new_with_mnemonic(const gchar *label);
Rien de nouveau à l'horizon, alors nous continuons.

Nous avons plusieurs fonctions qui permettent de changer l'état de notre GtkCheckMenuItem par programme :
void gtk_check_menu_item_set_active(GtkCheckMenuItem *check_menu_item, gboolean is_active);
void gtk_check_menu_item_set_inconsistent(GtkCheckMenuItem *check_menu_item, gboolean setting);
void gtk_check_menu_item_toggled(GtkCheckMenuItem *check_menu_item);

La première fonction pemet de passer le GtkCheckMenuItem 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 GtkCheckMenuItem 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 GtkCheckMenuItem.

Nous disposons également des fonctions associées pour récupérer l'état d'un GtkCheckMenuItem :
gboolean gtk_check_menu_item_get_active(GtkCheckMenuItem *check_menu_item);
gboolean gtk_check_menu_item_get_inconsistent(GtkCheckMenuItem *check_menu_item);
La première permet de connaître l'état d'un GtkCheckMenuItem, elle renvoie TRUE si il est "coché" ou FALSE sinon.
La deuxième permet juste de savoir si le GtkCheckMenuItem est dans le troisième état "demi coché".

3.3 Les GtkRadioMenuItem

Ici aussi, le widget GtkRadioMenuItem est un GtkRadioButton adapté pour les menus.
Les GtkRadioMenuItem héritent des GtkCheckMenuItem, donc tout ce qui a été dit juste avant s'applique aussi ici.

Pour créer un GtkRadioMenuItem, nous pouvons nous servir de :
GtkWidget* gtk_radio_menu_item_new(GSList *group);
GtkWidget* gtk_radio_menu_item_new_with_label(GSList *group, const gchar *label);
GtkWidget* gtk_radio_menu_item_new_with_mnemonic(GSList *group, const gchar *label);
Ce widget fonctionne de la même manière que le widget GtkRadioButton, et donc le paramètre group de ces fonctions, sert à dire au GtkRadioMenuItem à quel groupe il va appartenir.
Le premier GtkRadioMenuItem d'un groupe prendra toujours NULL 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 GtkRadioMenuItem pour que celui ci fasse partie du même groupe que le premier :
GSList* gtk_radio_menu_item_get_group(GtkRadioMenuItem *radio_menu_item);
On peut aussi définir ou remplacer le groupe d'un GtkRadioMenuItem aprés coup grâce à :
void gtk_radio_menu_item_set_group(GtkRadioMenuItem *radio_menu_item, GSList *group);

3.4 Les GtkSeparatorMenuItem

Ce widget permet d'insérer une séparation constituée d'une ligne horizontale dans le menu.
Ce widget ne possède qu'une seule fonction de création :
GtkWidget* gtk_separator_menu_item_new(void);

3.5 Les GtkTearoffMenuItem

Le widget GtkTearoffMenuItem permet de détacher le menu de sa barre et d'en faire une fenêtre à part entière.
Pour le créer, il faut utiliser la fonction suivante :
GtkWidget* gtk_tearoff_menu_item_new(void);
Cette fonction va ajouter au menu une ligne en pointillée. Un premier clic sur l'élément GtkTearoffMenuItem 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 :
gboolean gtk_menu_get_tearoff_state(GtkMenu *menu);
Cette dernière renverra TRUE si le menu est détaché et FALSE sinon.

3.6 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 callbacks supplémentaires pour la mise à jour de nos labels.
# -*- Encoding: Latin-1 -*-
import gtk

def main():
    GSList *pList;

    # Creation de la fenetre
    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.set_title("GtkMenu")
    window.set_default_size(320, 200)
    window.connect("destroy", gtk.main_quit)

    # Creation de la GtkVBox
    vbox = gtk.VBox(False, 0)
    window.add(vbox)

    #*** Creation du menu ***

    # ETAPE 1
    menu_bar = gtk.MenuBar()
    #* Premier sous-menu *
    # ETAPE 2
    menu = gtk.Menu()
    # ETAPE 3

    # GtkTearoffMenuItem
    menu_item = gtk.TearoffMenuItem()
    menu.append(menu_item)
    menu_item.connect("activate", OnTearoff, menu)

    # GtkImageMenuItem
    menu_item = gtk.ImageMenuItem(stock=gtk.STOCK_NEW)
    menu.append(menu_item)

    menu_item = gtk.ImageMenuItem(stock=gtk.STOCK_OPEN)
    menu.append(menu_item)

    menu_item = gtk.ImageMenuItem(stock=gtk.STOCK_SAVE)
    menu.append(menu_item)

    menu_item = gtk.ImageMenuItem(stock=gtk.STOCK_CLOSE)
    menu.append(menu_item)

    # GtkSeparatorItem
    menu_item = gtk.SeparatorMenuItem()
    menu.append(menu_item)

    # GtkRadioMenuItem
    menu_item = gtk.RadioMenuItem(label="Radio 1")
    menu.append(menu_item)
    liste = menu_item.get_group()
    # Il est inutile ici d'utiliser le signal "toggled"
    menu_item.connect("activate", OnRadio)

    menu_item = gtk.RadioMenuItem(group=liste, label="Radio 2")
    menu.append(menu_item)
    liste = menu_item.get_group()
    menu_item.connect("activate", OnRadio)

    menu_item = gtk.RadioMenuItem(group=liste, label="Radio 3")
    menu.append(menu_item)
    liste = menu_item.get_group()
    menu_item.connect("activate", OnRadio)

    # GtkSeparatorItem
    menu_item = gtk.SeparatorMenuItem()
    menu.append(menu_item)

    # GtkCheckMenuItem
    menu_item = gtk.CheckMenuItem(label="Check")
    menu.append(menu_item)
    menu_item.connect("toggled", OnCheck, menu)

    # GtkSeparatorItem
    menu_item = gtk.SeparatorMenuItem()
    menu.append(menu_item)

    menu_item = gtk.ImageMenuItem(stock=gtk.STOCK_QUIT)
    menu_item.connect("activate", OnQuitter, window)
    menu.append(menu_item)

    # ETAPE 4
    menu_item = gtk.MenuItem(label="Fichier")
    # ETAPE 5
    menu_item.set_submenu(menu)
    # ETAPE 6
    menu_bar.append(menu_item)

    #* Deuxieme sous-menu *
    # ETAPE 2
    menu = gtk.Menu()
    # ETAPE 3
    menu_item = gtk.MenuItem(label="A propos de...")
    menu_item.connect("activate", OnAbout, window)
    menu.append(menu_item)
    # ETAPE 4
    menu_item = gtk.MenuItem(label="?")
    # ETAPE 5
    menu_item.set_submenu(menu)
    # ETAPE 6
    menu_bar.append(menu_item)

    # Creation de la deuxieme GtkVBox (pour les labels)
    vbox2 = gtk.VBox(False, 0)

    radio_label = gtk.Label("Radio 1 est actif")
    vbox2.pack_start(radio_label, True, True, 0)

    temp_label = u"Check est décoché"
    check_label = gtk.Label(temp_label)
    vbox2.pack_start(check_label, True, True, 0)

    temp_label = u"Menu attaché"
    tearoff_label = gtk.Label(temp_label)
    vbox2.pack_start(tearoff_label, True, True, 0)

    # Ajout du menu a la fenetre
    vbox.pack_start(menu_bar, False, False, 0)
    # Ajout des labels a la fenetre
    vbox.pack_start(vbox2, True, True, 0)

    window.show_all()

    gtk.main()

def OnRadio(widget, data):
    # Recuperer le label du bouton radio active
    radio_name = widget.child.get_label()

    label = "%s est actif" % radio_name
    radio_label.set_label(label)

def OnCheck(widget, data):
    # Savoir si le GtkCheckMenuItem est coche ou non
    coche = widget.get_active()

    if coche:
        label = u"Check est coché"
    else:
        label = u"Check est décoché"

    check_label.set_label(label)

def OnTearoff(widget, data):
     # Savoir si le menu est detache ou non
     detache = data.get_tearoff_state()

    if detache:
        label = u"Menu détaché"
    else:
        label = u"Menu attaché"

    tearoff_label.set_label(label)

def OnQuitter(widget, data):
    question = gtk.MessageDialog(data,
        gtk.DIALOG_MODAL,
        gtk.MESSAGE_QUESTION,
        gtk.BUTTONS_YES_NO,
        "Voulez vous vraiment\nquitter le programme?")

    reponse = question.run()
    if reponse == gtk.RESPONSE_YES:
            gtk.main_quit()
    elif reponse in (gtk.RESPONSE_NONE, gtk.RESPONSE_NO):
            question.destroy()

def OnAbout(widget, data):
    about = gtk.MessageDialog(data,
        gtk.DIALOG_MODAL,
        gtk.MESSAGE_INFO,
        gtk.BUTTONS_OK,
        "Cours GTK+ 2.0\nhttp://www.gtk-fr.org")

    about.run()
    about.destroy()
Résultat :





<< Les boutons (Partie 2) PyGtk La barre d'outils >>

Il n'y a pas de commentaire sur cette page. [Afficher commentaires/formulaire]
Apinc