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

Apprendre à utiliser le module Python PyGTK 2.0


précédentsommairesuivant

XVI. Chapitre 16. Nouveaux Widgets dans PyGTK 2.4

Quelques nouveaux widgets et objets de contrôle ont été ajoutés dans PyGTK 2.4, incluant :

  • Action (Action), RadioAction (Action d'exclusion), ToggleAction (Action binaire) - objets qui représentent des actions qu'un utilisateur peut prendre. Les actions contiennent l'information nécessaire pour créer des widgets délégués (proxy) (par exemple : des icônes, des éléments de menu ou des éléments de barre d'outils) ;
  • ActionGroup - un objet contenant des Actions qui ont une certaine similarité, par exemple, les actions ouvrir, fermer et imprimer un document ;
  • Border - un objet contenant les valeurs pour une bordure ;
  • ColorButton - un bouton pour lancer un dialogue de sélection de couleurs ;
  • ComboBox - un widget proposant une liste d'éléments parmi lesquels choisir. Il remplace l'OptionMenu ;
  • ComboBoxEntry - un widget fournissant un champ d'entrée de texte avec une liste d'éléments parmi lesquels choisir. Il remplace le Combo ;
  • EntryCompletion - un objet permettant la complétion dans un champ de saisie Entry ;
  • Expander - un container qui peut montrer ou cacher son enfant en réponse à un clic sur son bouton ;
  • FileChooser - une interface pour le choix de fichiers ;
  • FileChooserWidget - un widget implémentant l'interface FileChooser. Il remplace le widget FileSelection ;
  • FileChooserDialog - une fenêtre de dialogue utilisée pour les actions "Fichier/Ouvrir" et "Fichier/Enregistrer". Elle remplace le FileSelectionDialog ;
  • FileFilter - un objet servant à filtrer les fichiers selon un jeu interne de règles ;
  • FontButton - un bouton qui ouvre la fenêtre de sélection de polices FontSelectionDialog ;
  • IconInfo - un objet contenant des informations sur une icône d'un IconTheme ;
  • IconTheme - un objet permettant une consultation des icônes avec leur nom et leur taille ;
  • ToolItem, ToolButton, RadioToolButton, SeparatorToolItem, ToggleToolButton - widgets qui peuvent être inclus dans une barre d'outils Toolbar. Ils remplacent les items de barre d'outils Toolbar précédents ;
  • TreeModelFilter - un objet fournissant un outil puissant pour transformer la représentation d'un modèle TreeModel sous-jacent. Il est décrit dans Section 14.10.2, « Le TreeModelFilter »Le TreeModelFilter ;
  • UIManager - un objet fournissant un moyen de construire des menus et des barres d'outils à partir d'une description d'interface utilisateur (UI) au format XML. Il possède aussi des méthodes pour gérer la fusion et séparation de multiples descriptions d'interfaces utilisateur.

XVI-A. Les objets Action et groupes d'Actions (ActionGroup)

Les objets Action et ActionGroup collaborent pour fournir les images, textes, fonctions de rappel et accélérateurs aux menus et barres d'outils des applications. L'UIManager utilise les Action et ActionGroup pour construire de manière automatique des barres de menus et des barres d'outils basées sur une description XML. Il est beaucoup plus facile de créer et remplir les menus et barres d'outils en utilisant le UIManager décrit dans une section ultérieure. Les sections suivantes sur les objets Action et ActionGroup décrivent comment utiliser directement ces objets, mais je recommande l'usage, dans la mesure du possible, de l'UIManager.

XVI-A-1. Actions

Un objet Action représente une action que l'utilisateur peut effectuer dans une interface d'application. Il contient l'information utilisée par les éléments de l'interface (par exemple, des éléments de MenuItem ou de Toolbar) pour présenter l'action à l'utilisateur. Il existe deux sous-classes d'Action :

ToggleAction

Un objet Action qui peut être commuté entre deux états.

RadioAction

Des objets Action qui peuvent être regroupés, mais dont un seul peut être activé.

Par exemple, l'élément de menu standard Fichier ? Quitter peut être représenté par une icône, un texte mnémonique ou un raccourci-clavier. Quand il est activé, l'élément de menu déclenche une fonction de rappel qui peut fermer l'application. En outre, un bouton Quitter d'une barre d'outils Toolbar peut partager les mêmes icônes, texte mnémonique et fonction de rappel. Ces deux éléments d'interface peuvent être des éléments délégués de la même Action.

Les widgets ordinaires Button, ToggleButton et RadioButton peuvent aussi agir comme une Action, quoique le UIManager ne possède aucun support pour ceux-ci.

XVI-A-1-a. Créer des Actions

Une Action peut être créée en utilisant le constructeur :

 
Sélectionnez
  action = gtk.Action(name, label, tooltip, stock_id)

name est une chaine employée pour identifier l'Action dans un ActionGroup ou dans des descriptions d'UIManager. Le label et le tooltip sont des chaines utilisées comme étiquette et infobulle dans des widgets délégués. Si label vaut None alors stock_id doit être une chaine indiquant un élément de Stock pour en récupérer le label. Si tooltip vaut None, l'Action n'aura pas d'infobulle.

Comme nous le verrons dans la Section 16.1.2, « ActionGroup »ActionGroup, il est beaucoup plus facile de créer des objets Action en utilisant les méthodes commodes de ActionGroup :

 
Sélectionnez
1.
2.
3.
  actiongroup.add_actions(entries, user_data=None)
  actiongroup.add_toggle_actions(entries, user_data=None)
  actiongroup.add_radio_actions(entries, value=0, on_change=None, user_data=None)

On en reparlera plus loin, mais d'abord, décrivons comment utiliser une Action avec un Button pour illustrer les opérations élémentaires de connexion d'une Action à un widget délégué.

XVI-A-1-b. Utiliser les Actions

La procédure de base pour l'utilisation d'une Action avec un Bouton proxy est illustrée par le programme exemple simpleaction.py. Le Bouton est connecté à l'Action par la méthode :

 
Sélectionnez
  action.connect_proxy(proxy)

où le proxy est un widget élément de menu MenuItem, élément de barre d'outils ToolItem ou un bouton Button.

Une action (Action) possède un signal, le signal "activate" qui est déclenché quand l'Action est activée, normalement par le résultat d'une activation d'un widget proxy (par exemple, on a cliqué sur un bouton de barre d'outils ToolButton). Il faut juste connecter une fonction de rappel à ce signal pour contrôler l'activation de n'importe lequel des widgets délégués (proxy).

Voici le code source pour le programme exemple simpleaction.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.
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.
#!/usr/bin/env python
 # -*- coding:utf-8 -*-
 import pygtk
 pygtk.require('2.0')
 import gtk
 
 class SimpleAction:
  def __init__(self):
      # Créer la fenêtre de premier niveau
      window = gtk.Window()
      window.set_size_request(70, 30)
      window.connect('destroy', lambda w: gtk.main_quit())
 
      # Créer un groupe de raccourcis
      groupe_rapide = gtk.AccelGroup()
      # Ajouter le groupe à la fenêtre de premier niveau
      window.add_accel_group(groupe_rapide)
 
      # Créer une action_quitte pour quitter le programme avec un élément de Stock
      action_quitte = gtk.Action('Quitter', None, None, gtk.STOCK_QUIT)
      # Connecter une fonction de rappel à l'action
      action_quitte.connect('activate', self.fonct_quitte)
 
      # Créer un ActionGroup appelé ActionSimple
      groupe_actions = gtk.ActionGroup('ActionSimple')
      # Ajouter l'action à groupe_actions avec un raccourci-clavier
      # "None" signifie utiliser l'accélérateur de l'élément Stock
      groupe_actions.add_action_with_accel(action_quitte, None)
 
      ## Lier l'action au groupe_rapide
      action_quitte.set_accel_group(groupe_rapide)
 
      # Connecter l'accélérateur à l'action
      action_quitte.connect_accelerator()
 
      # Créer un bouton pour l'utiliser comme autre widget délégué
      bouton_quitter = gtk.Button()
      # l'ajouter à la fenêtre
      window.add(bouton_quitter)
 
      # Lier l'action à son widget délégué
      action_quitte.connect_proxy(bouton_quitter)
 
      window.show_all()
      return
 
  def fonct_quitte(self, b):
      print 'Quitter le programme'
      gtk.main_quit()
 
 if __name__ == '__main__':
  sa = SimpleAction()
  gtk.main()

L'exemple crée une Action (ligne 20) qui utilise un élément Stock Item pour récupérer le texte de l'étiquette avec un mnémonique, une icône, un raccourci-clavier et un domaine de traduction. Si on n'utilise pas de Stock Item, il faut indiquer un label à la place. Ligne 22, on connecte le signal "activate" du paramètre action à la méthode self.quit_cb() afin qu'elle soit appelée quand l'action Action est activée par le bouton quitbutton. L'exemple simpleaction.py utilise pas mal de code (lignes 15, 17, 31 et 34) pour installer le raccourci pour le bouton. La procédure est la même pour les éléments de menu MenuItem, les barres d'outils Toolbar et les éléments de barre d'outils ToolItem.

La Figure 16.1, « Exemple d'Action simple » montre le résultat du programme simpleaction.py

Image non disponible
Figure 16.1. Exemple d'Action simple
XVI-A-1-c. Créer des widgets délégués (proxy)

Dans la section précédente, nous avons vu qu'un widget existant pouvait être connecté à une Action comme intermédiaire. Dans cette section nous verrons comment un widget délégué peut être créé par les méthodes d'Action :

 
Sélectionnez
1.
2.
3.
  menuitem = action.create_menu_item()

  toolitem = action.create_tool_item()

Le programme basicaction.py montre un élément de menu MenuItem, un bouton de barre d'outils ToolButton et un bouton Button partageant une même Action. Le MenuItem et le ToolButton ont été créés par les méthodes précédentes. Voici le code source du programme basicaction.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.
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.
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import pygtk
    pygtk.require('2.0')
    import gtk
    
    class BasicAction:
        def __init__(self):
            # Créer la fenêtre de premier niveau
            window = gtk.Window()
            window.connect('destroy', lambda w: gtk.main_quit())
            vbox = gtk.VBox()
            vbox.show()
            window.add(vbox)
    
            # Créer un groupe de raccourcis
            groupe_rapide = gtk.AccelGroup()
            # Ajouter le groupe à la fenêtre de premier niveau
            window.add_accel_group(groupe_rapide)
    
            # Créer une action_quitte pour quitter le programme avec un élément de Stock
            action_quitte = gtk.Action('Quitter', '_Quittez moi ! ', 'Quitter le programme',
                                gtk.STOCK_QUIT)
            action_quitte.set_property('short-label', '_Quitter')
            # Connecter une fonction de rappel à l'action
            action_quitte.connect('activate', self.fonct_quitte)
    
            # Créer un ActionGroup appelé ActionBasic
            groupe_actions = gtk.ActionGroup('ActionBasic')
            # Ajouter l'action à groupe_actions avec un raccourci-clavier
            # "None" signifie utiliser le raccourci de l'élément Stock
            groupe_actions.add_action_with_accel(action_quitte, None)
    
            # Lier l'action au groupe_rapide
            action_quitte.set_accel_group(groupe_rapide)
    
            # Créer une barre de menu
            barremenu = gtk.MenuBar()
            barremenu.show()
            vbox.pack_start(barremenu, False)
    
            # Créer une action "Fichier" et l'élément de menu correspondant
            action_fichier = gtk.Action('Fichier', '_Fichier', None, None)
            groupe_actions.add_action(action_fichier)
            elmenu_fichier = action_fichier.create_menu_item()
            barremenu.append(elmenu_fichier)
    
            # Créer le menu Fichier
            menu_fichier = gtk.Menu()
            elmenu_fichier.set_submenu(menu_fichier)
    
            # Créer un élément de menu délégué
            menuitem = action_quitte.create_menu_item()
            menu_fichier.append(menuitem)
    
            # Créer une barre d'outils
            barreoutils = gtk.Toolbar()
            barreoutils.show()
            vbox.pack_start(barreoutils, False)
    
            # Créer un élément de barre d'outils délégué
            elbarre1 = action_quitte.create_tool_item()
            barreoutils.insert(elbarre1, 0)
    
            # Créer et placer l'étiquette
            label = gtk.Label('''
    Choisir Fichier->quittez-moi ! ou
    cliquer sur le bouton Quitter de la barre d'outils ou
    cliquer sur le bouton Quitter du bas ou
    taper Control+q
    pour sortir.
    ''')
            label.show()
            vbox.pack_start(label)
    
            # Créer un bouton pour l'utiliser comme autre widget délégué
            bouton_quitter = gtk.Button()
            # l'ajouter à la fenêtre
            vbox.pack_start(bouton_quitter, False)
    
            # Lier l'action à son widget délégué
            action_quitte.connect_proxy(bouton_quitter)
            # On doit placer l'infobulle après l'ajout de l'élément à la barre d'outils
            action_quitte.set_property('tooltip', action_quitte.get_property('tooltip'))
            les_infobulles = gtk.Tooltips()
            les_infobulles.set_tip(bouton_quitter, action_quitte.get_property('tooltip'))
    
            window.show()
            return
    
        def fonct_quitte(self, b):
            print 'On quitte le programme'
            gtk.main_quit()
    
    if __name__ == '__main__':
        ba = BasicAction()
        gtk.main()

Cet exemple introduit un groupe d'actions ActionGroup contenant les Action utilisées dans ce programme. La Section 16.1.2, « ActionGroup »ActionGroup entrera plus dans le détail de l'utilisation des ActionGroup.

Le code des lignes 9-14 crée une fenêtre de premier niveau contenant une boite VBox. Lignes 16-35, on crée l' Action "Quitter" semblable à celle du programme simpleaction.py et on l'ajoute (ligne 32) avec le raccourci gtk.STOCK_QUIT à l' ActionGroup "BasicAction" créé ligne 29. Noter que, contrairement au programme simpleaction.py, il n'est pas nécessaire d'appeler la méthode connect_accelerator(), celle-ci étant appelée automatiquement quand la méthode create_menu_item() est appelée ligne 53.

Lignes 38-40, on crée une barre de menu MenuBar et on la place dans la VBox. Lignes 43-44, on crée une Action (action_fichier) pour le menu Fichier et on l'ajoute au actiongroup. Les éléments de menu Fichier et Quitter sont créés lignes 45 et 53 et ajoutés à la barre de menu barremenu et au menu menu_fichier en ligne 46 et 54.

De la même manière, on crée une Toolbar et on l'ajoute à la VBox aux lignes 57-59. Le ToolItem délégué est créé et ajouté à la Toolbar barreoutils ligne 62-63. Noter que l'infobulle de l'Action doit être établie (ligne 84) après l'ajout du ToolItem à la Toolbar pour être utilisable. De même l'infobulle du Button doit être ajoutée manuellement (lignes 84-86).

La Figure 16.2, « Exemple d'Action élémentaire » montre le programme basicaction.py en action.

Image non disponible
Figure 16.2. Exemple d'Action élémentaire

Un widget délégué peut être déconnecté d'une Action par la méthode :

 
Sélectionnez
  action.disconnect_proxy(proxy)
XVI-A-1-d. Propriétés des Actions

Une Action possède un certain nombre de propriétés qui contrôlent l'affichage et le fonctionnement de ses widgets délégués. Parmi celles-ci, les plus importantes sont les propriétés "sensitive" et "visible". La propriété "sensitive" détermine la sensibilité des widgets délégués. Si "sensitive" est FALSE les widgets délégués ne sont pas activables et seront normalement affichés "grisés". De même, la propriété "visible" détermine si les widgets délégués seront visibles. Si la propriété "visible" d'une Action est FALSE, ses widgets délégués seront cachés.

Comme on le verra dans la prochaine section, la sensibilité ou la visibilité d'une Action est également contrôlée par la sensibilité ou la visibilité de l'ActionGroup auquel elle appartient. Par conséquent, pour qu'une Action soit sensible (ou visible), elle-même et son ActionGroup doivent être sensibles (ou visibles) tous les deux. Pour déterminer la sensibilité ou visibilité effective d'une Action, il faut utiliser les méthodes suivantes :

 
Sélectionnez
1.
2.
3.
  resultat = action.is_sensitive()

  resultat = action.is_visible()

Le nom assigné à une Action est contenu dans sa propriété "name" qui est établie lors de la création de l'Action. On peut retrouver ce nom par la méthode :

 
Sélectionnez
  nom = action.get_name()

Les autres propriétés qui contrôlent l'affichage des widgets délégués d'une Action sont :

"hide-if-empty"

Si vaut TRUE, les contrôles délégués de menus vides sont cachés pour cette action.

"is-important"

Si vaut TRUE, les délégués ToolItem proxies pour cette action affichent le texte dans le mode gtk.TOOLBAR_BOTH_HORIZ.

"visible-horizontal"

Si vaut TRUE, le ToolItem est visible quand la barre d'outils est horizontale.

"visible-vertical"

Si vaut TRUE, le ToolItem est visible quand la barre d'outils est verticale.

Autres propriétés intéressantes :

"label"

L'étiquette utilisée pour les éléments de menu et les boutons qui déclenchent cette action.

"short-label"

Une étiquette plus courte qui peut être utilisée sur les boutons de barres d'outils et les boutons simples.

"stock-id"

L'élément de Stock à utiliser pour récupérer l'icône, l'étiquette et le raccourci à utiliser dans les widgets qui représentent cette action.

"tooltip"

Une infobulle pour cette action.

Noter que le programme d'exemple basicaction.py réécrit l'étiquette du gtk.STOCK_QUIT avec "_Quitter moi !" et définit l'étiquette courte à "_Quitter". L'étiquette courte est utilisée pour le bouton de barre d'outils ToolButton et pour le bouton isolé. L'étiquette complète est utilisée pour le l'élément de menu MenuItem. Noter aussi que l'infobulle ne peut pas être définie pour un ToolItem tant qu'elle n'est pas ajoutée à la barre d'outils Toolbar.

XVI-A-1-e. Actions et Accélérateurs

Une Action a trois méthodes qui peuvent être employées pour établir un accélérateur (raccourci-clavier) :

 
Sélectionnez
1.
2.
3.
4.
5.
  action.set_accel_group(accel_group)

  action.set_accel_path(accel_path)

  action.connect_accelerator()

Celles-ci, outre la méthode gtk.ActionGroup.add_action_with_accel(), devraient couvrir la plupart des cas de création d'accélérateur.

Il faut toujours définir un AccelGroup pour une Action. La méthode set_accel_path() est appelée par la méthode gtk.ActionGroup.add_action_with_accel(). Si on utilise la méthode set_accel_path(), le chemin de l'accélérateur doit avoir le format par défaut : "<Actions>/nom_du_groupe_actions/nom_de_action". Enfin, la méthode connect_accelerator() est appelée pour compléter la mise en place de l'accélérateur.

Une Action doit avoir un AccelGroup et un chemin d'accélérateur associé avant que la méthode connect_accelerator() soit appelée.

Puisque la méthode connect_accelerator() peut être appelée plusieurs fois (par exemple, une fois pour chaque widget délégué), le nombre d'appels est compté, ainsi un nombre égal d'appels à la méthode disconnect_accelerator() doit être réalisé avant d'éliminer l'accélérateur.

Comme illustré dans les programmes d'exemple précédents, un accélérateur d'Action peut être employé par tous les widgets délégués. Une Action doit faire partie d'un ActionGroup afin d'utiliser le chemin d'accélérateur par défaut avec ce format : "<Actions>/nom_du_groupe_actions/nom_de_action". La manière la plus simple d'ajouter un accélérateur est d'utiliser la méthode gtk.ActionGroup.add_action_with_accel() et la procédure générale suivante.

  • Créer un AccelGroup et l'ajouter à la fenêtre de premier niveau.
  • Créer un nouveau ActionGroup.
  • Créer une Action en précisant un élément de Stock avec un accélérateur.
  • Ajouter l'Action à l'ActionGroup avec la méthode gtk.ActionGroup.add_action_with_accel() en indiquant None pour utiliser l'accélérateur de l'élément de Stock ou une chaine d'accélérateur acceptable par la méthode gtk.accelerator_parse().
  • Définir l'AccelGroup pour l'Action en utilisant la méthode gtk.Action.set_accel_group().
  • Terminer la configuration de l'accélérateur avec la méthode gtk.Action.connect_accelerator().

Tous les widgets délégués créés ou connectés à l'Action utiliseront le raccourci.

XVI-A-1-f. Actions à bascule

Comme mentionnée précédemment, une action à bascule ToggleAction est une sous-classe d'Action qui peut être basculée entre deux états. Le constructeur pour une ToggleAction prend les mêmes paramètres que pour une Action :

 
Sélectionnez
  toggleaction = gtk.ToggleAction(name, label, tooltip, stock_id)

En supplément des méthodes pour Action, les méthodes suivantes pour ToggleAction :

 
Sélectionnez
  toggleaction.set_active(is_active)
  is_active = toggleaction.get_active()

spécifient et récupèrent la valeur actuelle de toggleaction. Le paramètre is_active contient une valeur booléenne.

On peut se connecter au signal "toggled" en spécifiant une fonction de rappel qui a la forme :

 
Sélectionnez
  def toggled_cb(toggleaction, user_data)

Le signal "toggled" est émis lorsque le ToggleAction change d'état.

Le widget délégué MenuItem d'un ToggleAction sera affiché par défaut comme un CheckMenuItem. Pour obtenir l'affichage du MenuItem comme un RadioMenuItem, il faut donner à la propriété "draw-as-radio" la valeur TRUE par la méthode :

 
Sélectionnez
  toggleaction.set_draw_as_radio(draw_as_radio)

On peut utiliser la méthode suivante pour déterminer si les éléments MenuItem d'une action ToggleAction seront affichés comme des RadioMenuItem :

 
Sélectionnez
  draw_as_radio = toggleaction.get_draw_as_radio()
XVI-A-1-g. Actions avec exclusivité

Une action exclusive RadioAction est une sous-classe d'action ToggleAction qui peut être groupée de manière à ce qu'un seul RadioAction soit actif en même temps. Les widgets délégués correspondants sont le RadioMenuItem pour la barre de menu et le RadioToolButton pour la barre d'outils.

Le constructeur d'un RadioAction accepte les mêmes arguments qu'une Action avec l'ajout d'une valeur entière unique qui permet d'identifier le RadioAction actif dans le groupe :

 
Sélectionnez
  radioaction = gtk.RadioAction(name, label, tooltip, stock_id, value)

Le groupe d'un RadioAction peut être créé par la méthode :

 
Sélectionnez
  radioaction.set_group(group)

group est un autre RadioAction auquel doit se rattacher le radioaction. Le groupe contenant un RadioAction peut être obtenu par la méthode :

 
Sélectionnez
  group = radioaction.get_group()

qui renvoie une liste du groupe d'objets RadioAction qui inclut le radioaction.

La valeur de l'élément actuellement actif du groupe peut s'obtenir par la méthode :

 
Sélectionnez
  active_value = radioaction.get_current_value()

On peut connecter une fonction de rappel au signal "changed" pour être prévenu lorsque l'élément actif du RadioAction a été modifié. Noter qu'il faut se connecter à un seul des objets RadioAction pour surveiller les changements. La fonction de rappel est :

 
Sélectionnez
  def changed_cb(radioaction, current, user_data)

current est le RadioAction du groupe qui est actuellement actif.

XVI-A-1-h. Un exemple avec Actions

Le programme exemple actions.py montre l'utilisation d'objets Action, ToggleAction et RadioAction. Figure 16.3, « Exemple avec Actions » illustre le programme en cours de fonctionnement :

Image non disponible
Figure 16.3. Exemple avec Actions

Cet exemple est suffisamment proche de basicaction.py, une description détaillée est inutile.

XVI-A-2. ActionGroup

Comme indiqué dans la section précédente, des objets d'Action apparentés devraient être ajoutés à un groupe d'actions ActionGroup pour fournir un contrôle commun de leur visibilité et sensibilité. Par exemple, dans une application de traitement de texte, les éléments de menu et les boutons de la barre d'outils demandant la justification du texte peuvent être contenus dans un ActionGroup. On s'attend à ce qu'une interface utilisateur possède des objets ActionGroup multiples qui couvrent des aspects différents de l'application. Par exemple, les actions globales comme créer de nouveaux documents, ouvrir et sauvegarder un document ou quitter l'application forment probablement un ActionGroup tandis que des actions telles que modifier la vue du document en formeraient un autre.

XVI-A-2-a. Créer des ActionGroups

On crée un ActionGroup avec le constructeur :

 
Sélectionnez
actiongroup = gtk.ActionGroup(name)

name est un nom unique pour l'ActionGroup. Le nom doit être unique, car il est utilisé lors de la création des raccourcis des objets Action qu'il contient.

Le paramètre ActionGroup peut être obtenu par la méthode :

 
Sélectionnez
  name = actiongroup.get_name()

ou en récupérant le contenu de la propriété "name".

XVI-A-2-b. Ajouter des Actions

Comme on l'a montré dans Section 16.1.1, « Actions »Actions, une Action préexistante peut être ajoutée à un ActionGroup en utilisant une des méthodes :

 
Sélectionnez
1.
2.
3.
  actiongroup.add_action(action)

  actiongroup.add_action_with_accel(action, accelerator)

où le paramètre action est l'Action qui doit être ajoutée et le paramètre accelerator est une chaine précisant un raccourci acceptable pour la fonction gtk.accelerator_parse(). Si accelerator vaut None, l'accélérateur (s'il existe) associé à la propriété "stock-id" du paramètre action sera utilisé. Comme on l'a vu précédemment, il vaut mieux utiliser la méthode add_action_wih_accel() si on souhaite utiliser les raccourcis-clavier.

Le groupe ActionGroup offre trois méthodes pour faciliter la création et l'ajout d'objets Action à un groupe ActionGroup :

 
Sélectionnez
1.
2.
3.
4.
5.
  actiongroup.add_actions(entries, user_data=None)

  actiongroup.add_toggle_actions(entries, user_data=None)

  actiongroup.add_radio_actions(entries, value=0, on_change=None, user_data=None)

Le paramètre entries est une liste de tuples d'entrée d'action qui fournissent l'information utilisée pour créer les actions ajoutées à l'ActionGroup. Le RadioAction avec la valeur value est réglé au départ comme actif. Le paramètre on_change représente la fonction de rappel connectée au signal "changed" du premier RadioAction du groupe. La signature de on_changed est :

 
Sélectionnez
  def on_changed_cb(radioaction, current, user_data)

Les tuples d'entrées pour les objets Action contiennent :

  • le nom de l'action. Doit être indiqué ;
  • l'identificateur de Stock pour cette action. Optionnel, sa valeur par défaut est None si l'étiquette est indiquée ;
  • l'étiquette pour l'action. Optionnel, sa valeur par défaut est None si l'identificateur de Stock est précisé ;
  • le raccourci pour l'action, dans un format compris par la fonction gtk.accelerator_parse(). Optionnel, sa valeur par défaut est None ;
  • l'infobulle pour l'action. Optionnel, sa valeur par défaut est None ;
  • la fonction de rappel appelée quand l'action est activée. Optionnel, sa valeur par défaut est None

Il faut indiquer au minimum une valeur pour le champ name et une valeur soit pour l'identificateur stock id, soit pour le champ étiquette label. Si on indique une étiquette, alors, on peut donner une valeur None à l'identificateur de stock si on ne l'utilise pas. Par exemple, la méthode suivante :

 
Sélectionnez
  actiongroup.add_actions([('quitter', gtk.STOCK_QUIT, '_Quittter moi !', None, 
                            'Quitter le programme', quit_cb)])

ajoute une action à actiongroup pour quitter un programme.

Les tuples d'entrée pour les objets ToggleAction sont semblables aux tuples d'entrée d'Action, mais il y a un champ facultatif flag supplémentaire qui contient une valeur booléenne indiquant si l'action est active.La valeur par défaut pour le champ flag est FALSE. Par exemple, la méthode suivante :

 
Sélectionnez
  actiongroup.add_toggle_actions([('volume, None, '_Volume', '<control>v', 
                                   'Niveau de son', mute_cb, True)])

ajoute un ToggleAction à l'actiongroup et l'initialise comme actif.

Les tuples d'entrée pour le RadioAction sont semblables à ceux de l'Action,mais avec un champ value à la place du champ callback :

  • le nom de l'action. Doit être indiqué ;
  • l'identificateur de Stock pour cette action. Optionnel, sa valeur par défaut vaut None si le label est précisé ;
  • le label pour l'action. Optionnel, sa valeur par défaut vaut None si l'identificateur de Stock est précisé ;
  • l'accélérateur pour l'action, dans un format compris par la fonction gtk.accelerator_parse(). Optionnel, sa valeur par défaut vaut None ;
  • l'infobulle pour l'action. Optionnel, sa valeur par défaut vaut None ;
  • la valeur à attribuer au radio-action. Optionnel, sa valeur par défaut vaut None. Devrait toujours être indiqué dans les applications.

Par exemple le fragment de code suivant :

 
Sélectionnez
1.
2.
3.
4.
  radioactionlist = [('ma', None, 'M_A', '<control>a', 'Mode MA', 0)
                     ('mf', None, 'M_F', '<control>f', 'Mode MF', 1)
                     ('blu', None, 'B_LU', '<control>b', 'Mode BLU', 2)]
  actiongroup.add_radio_actions(radioactionlist, 0, changed_cb)

crée trois objets RadioAction et fixe l'action active initiale à 'ma' et la fonction de rappel qui est appelée quand l'une de ces actions est activée à changed_cb.

XVI-A-2-c. Récupérer une Action

Une Action peut être retrouvée par son nom à partir d'un ActionGroup en utilisant la méthode :

 
Sélectionnez
  action = actiongroup.get_action(action_name)

Une liste de tous les objets Action contenus dans un ActionGroup peut être recherchée en utilisant la méthode :

 
Sélectionnez
  actionlist = actiongroup.list_actions()
XVI-A-2-d. Controler les Actions

La sensibilité et la visibilité de tous les objets Action d'un ActionGroup peuvent être contrôlées en fixant les valeurs de propriétés associées. Les méthodes suivantes récupèrent et fixent les propriétés :

 
Sélectionnez
1.
2.
3.
4.
5.
  is_sensitive = actiongroup.get_sensitive()
  actiongroup.set_sensitive(sensitive)

  is_visible = actiongroup.get_visible()
  actiongroup.set_visible(visible)

Enfin, il est possible de supprimer une Action d'un ActionGroup par la méthode :

 
Sélectionnez
  actiongroup.remove_action(action)
XVI-A-2-e. Exemple de ActionGroup

Le programme d'exemple actiongroup.py reprend la barre de menu et la barre d'outils du programme actions.py en utilisant les méthodes d'ActionGroup. En outre le programme fournit des boutons pour contrôler la sensibilité et la visibilité des éléments du menu et de la barre d'outils. La Figure 16.4, « Exemple avec ActionGroup » montre le programme en fonctionnement :

Image non disponible
Figure 16.4. Exemple avec ActionGroup
XVI-A-2-f. Les signaux de ActionGroup

L'application peut surveiller la connexion et le retrait de widgets délégués aux objets Action dans un ActionGroup en utilisant les signaux "connect-proxy" et "disconnect-proxy". Les fonctions de rappel sont de la forme :

 
Sélectionnez
1.
2.
3.
  def connect_proxy_cb(actiongroup, action, proxy, user_params)

  def disconnect_proxy_cb(actiongroup, action, proxy, user_params)

Par exemple, on peut vouloir surveiller ces changements pour effectuer quelques modifications supplémentaires aux propriétés du nouveau widget délégué quand il est connecté ou pour mettre à jour quelque autre partie de l'interface utilisateur quand un widget délégué est déconnecté.

Les signaux "pre-activate" et "post-activate" autorisent l'application à réaliser un traitement additionnel juste avant ou après l'activation d'une action. Les fonctions de rappel sont de la forme :

 
Sélectionnez
1.
2.
3.
  def pre_activate_cb(actiongroup, action, user_params)

  def post_activate_cb(actiongroup, action, user_params)

Ces signaux sont surtout utilisés par le UIManager pour fournir une notification globale pour tous les objets Action des objets ActionGroup qu'il utilise.

XVI-B. Les listes déroulantes (ComboBox) et listes déroulantes avec saisie (ComboBoxEntry)

XVI-B-1. Le widget ComboBox

La boite déroulante ComboBox remplace l'OptionMenu par un widget puissant qui utilise un TreeModel (généralement un ListStore) pour obtenir la liste d'éléments à afficher. Le ComboBox applique l'interface du CellLayout qui fournit un certain nombre de méthodes pour gérer l'affichage des éléments de liste. Un ou plusieurs CellRenderers peuvent être placés dans un ComboBox pour personnaliser l'affichage des éléments de liste.

XVI-B-1-a. Utiliser la boite déroulante de base

La manière simple de créer et remplir un ComboBox est d'utiliser la fonction suivante :

 
Sélectionnez
  boitederoul = gtk.combo_box_new_text()

Cette fonction crée un ComboBox et son ListStore associé et le place avec un CellRendererText. On utilise les méthodes suivantes pour remplir ou supprimer le contenu du ComboBox et de son ListStore :

 
Sélectionnez
1.
2.
3.
4.
  boitederoul.append_text(text)
  boitederoul.prepend_text(text)
  boitederoul.insert_text(position, text)
  boitederoul.remove_text(position)

text est une chaine à ajouter au ComboBox et position est l'index où le text doit être inséré ou retiré. Dans la plupart des cas, on n'aura besoin que de cette fonction et de ces méthodes.

Le programme d'exemple comboboxbasic.py montre l'usage des fonctions et méthodes ci-dessus. La Figure 16.5, « Basic ComboBox » illustre le programme en cours :

Image non disponible
Figure 16.5. Basic ComboBox

Malheureusement, les développeurs de GTK+ n'ont pas fourni de méthode commode pour récupérer l'élément actif. Ceci serait pourtant une méthode utile. Il faut créer la sienne, semblable à :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
  def get_active_text(boitederoul):
      modele = boitederoul.get_model()
      est_actif = boitederoul.get_active()
      if est_actif < 0:
          return None
      return modele[est_actif][0]

L'index de l'élément actif est récupéré par la méthode :

 
Sélectionnez
  est_actif = boitederoul.get_active()

L'élément actif peut être défini par la méthode :

 
Sélectionnez
  boitederoul.set_active(index)

index est un entier supérieur à -2. Si index vaut -1, il n'y a aucun élément actif et l'affichage du ComboBox est vierge. Si index est inférieur à -1, l'appel sera ignoré. Si index est supérieur à -1, l'élément de liste qui possède cette valeur d'index sera affiché.

On peut se connecter au signal "changed" d'un ComboBox pour être prévenu lorsque l'élément actif change. Le gestionnaire de "changed" a la forme :

 
Sélectionnez
  def fct_rappel_change(combobox, ...):

... représente zéro ou plusieurs arguments transmis à la méthode GObject.connect().

XVI-B-1-b. Usage avancé de ComboBox

Créer un ComboBox par la fonction gtk.combo_box_new_text() correspond à peu près au code suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
  liststore = gtk.ListStore(str)
  boitederoul = gtk.ComboBox(liststore)
  case = gtk.CellRendererText()
  boitederoul.pack_start(case, True)
  boitederoul.add_attribute(case, 'text', 0)

Pour utiliser les possibilités des divers objets des TreeModel et des CellRenderer, il faut créer le ComboBox par le constructeur :

 
Sélectionnez
  combobox = gtk.ComboBox(model=None)

model est un TreeModel. Lorsque l'on crée un ComboBox sans l'associer à un TreeModel, on peut ajouter celui-ci ensuite par la méthode :

 
Sélectionnez
  boitederoul.set_model(model)

Le TreeModel associé peut être récupéré par la méthode :

 
Sélectionnez
  modele = boitederoul.get_model()

Quelques-unes des possibilités réalisables avec un ComboBox

  • Partager le même TreeModel avec un autre ComboBox et un autre TreeView.
  • Afficher des images et du texte dans les éléments de liste du ComboBox.
  • Utiliser un TreeStore ou un ListStore préexistant comme modèle des éléments de liste du ComboBox.
  • Utiliser un TreeModelSort pour obtenir une liste classée dans le ComboBox.
  • Utiliser un TreeModelFilter pour utiliser un sous-arbre d'un TreeStore comme la source pour les éléments de liste du ComboBox.
  • Utiliser un TreeModelFilter pour utiliser un sous-ensemble des lignes d'un TreeStore ou d'un ListStore comme éléments de liste du ComboBox.
  • Utiliser une fonction de données de cellule pour modifier ou synthétiser l'affichage des articles de liste.

L'utilisation des objets TreeModel et CellRenderer objects est exposée en détail dans Chapitre 14, Le widget TreeViewChapitre 14. Le widget TreeView.

Si on a un ComboBox avec beaucoup d'éléments de liste, ceux-ci peuvent être affichés dans une grille. Autrement, si on ne peut afficher la liste entière, celle-ci aura des flèches de défilement. La méthode suivante est utilisée pour fixer le nombre de colonnes à afficher :

 
Sélectionnez
  boitederoul.set_wrap_width(width)

width est le nombre de colonnes de la grille affichant les éléments de liste. Par exemple, le programme comboboxwrap.py affiche une liste de 50 éléments sur 5 colonnes. La Figure 16.6, « ComboBox avec colonnes »« ComboBox avec colonnes »« ComboBox avec colonnes » illustre le programme en action :

Image non disponible
Figure 16.6. ComboBox avec colonnes

Avec un grand nombre d'éléments, c'est-à-dire au-delà de 50, l'utilisation de la méthode set_wrap_width() fournira une faible performance à cause du calcul de l'affichage de la grille. Pour avoir un aperçu de l'effet, modifier la ligne 18 du programme comboboxwrap.py pour afficher 150 éléments.

 
Sélectionnez
        for n in range(150):

Lancer le programme pour obtenir une estimation du temps d'initialisation. Puis le modifier en commentant la ligne 17 :

 
Sélectionnez
        #boitederoul.set_wrap_width(5)

Relancer le programme et chronométrer à nouveau. Il devrait s'exécuter beaucoup plus vite, à peu près 20 fois plus rapidement.

Outre la méthode get_active() décrite ci-dessus, il est possible d'obtenir un TreeIter désignant la ligne active en utilisant la méthode :

 
Sélectionnez
  iter = boitederoul.get_active_iter()

On peut aussi établir l'élément de liste actif en utilisant un TreeIter avec la méthode :

 
Sélectionnez
  boitederoul.set_active_iter(iter)

Les méthodes set_row_span_column() et set_column_span_column() sont supposées permettre la spécification du nombre de colonnes d'un TreeModel qui contient le nombre de lignes ou de colonnes sur lesquelles les éléments de liste doivent s'étendre dans la grille. Malheureusement, ces méthodes sont cassées dans GTK+ 2.4.

Puisque le ComboBox implémente l'interface CellLayout qui possède les mêmes capacités que le TreeViewColumn (voir Section 14.5, « TreeViewColumn »TreeViewColumn pour plus d'information). En bref, l'interface fournit :

 
Sélectionnez
1.
2.
3.
  boitederoul.pack_start(cell, expand=True)
  boitederoul.pack_end(cell, expand=True)
  boitederoul.clear()

Les deux premières méthodes placent un CellRenderer dans le ComboBox, la méthode clear() supprime tous les attributs de tous les CellRenderer.

Les méthodes suivantes :

 
Sélectionnez
1.
2.
3.
  comboboxentry.add_attribute(cell, attribute, column)

  comboboxentry.set_attributes(cell, ...)

fixent les attributs pour les CellRenderer indiqués par cell. La méthode add_attribute() prend une chaine, nom d'attribut attribute (par exemple, 'texte') et un entier, numéro de colonne de la column du TreeModel à utiliser pour placer l'attribut. Les arguments supplémentaires de la méthode set_attributes() sont des paires attribute=column (par exemple, texte=1).

XVI-B-2. Le widget ComboBoxEntry

Le widget ComboBoxEntry remplace le widget Combo. C'est une sous-classe du widget ComboBox qui contient un widget fils Entry dont le contenu est fixé en choisissant un élément dans une liste déroulante, en entrant directement le texte au clavier ou par un coller depuis un presse-papier Clipboard ou une sélection.

XVI-B-2-a. Utilisation fondamentale du ComboBoxEntry

Comme le ComboBox, le ComboBoxEntry peut être créé par la fonction :

 
Sélectionnez
  boitderoulsaisie = gtk.combo_box_entry_new_text()

Le ComboBoxEntry devrait être rempli en utilisant les méthodes auxiliaires du ComboBox décrites dans la section Section 16.2.1.1, « Utiliser la boite déroulante de base »Utiliser la boîte déroulante de base.

Comme un widget ComboBoxEntry est un widget Bin, son widget fils Entry est disponible en utilisant l'attribut "child" ou la méthode get_child() :

 
Sélectionnez
  saisie = boitderoulsaisie.child
  saisie = boitderoulsaisie.get_child()

On peut récupérer le texte de la zone Entry par la méthode get_text().

Comme pour le ComboBox, on peut surveiller les changements de l'élément actif de la liste en se connectant au signal "changed". Malheureusement, cela ne permet pas de suivre les modifications de texte dans le Entry fils lorsque ce sont des saisies directes. Quand une saisie directe est réalisée dans le widget fils Entry, le signal "changed" est bien émis, mais l'index retourné par la méthode get_active() vaudra -1. Pour surveiller tous les changements dans le texte de la zone de saisie Entry, il faudra utiliser le signal "changed" du widget Entry. Par exemple :

 
Sélectionnez
1.
2.
3.
4.
  def fct_rappel_change(saisie):
      print saisie.get_text()

  boitderoulsaisie.child.connect('changed', fct_rappel_change)

affichera le texte après chaque modification dans le widget fils Entry. Pour exemple, le programme comboboxentrybasic.py montre l'utilisation de l'API. La figure Figure 16.7, « Liste déroulante avec zone de saisie » illustre le programme en action.

Image non disponible
Figure 16.7. Liste déroulante avec zone de saisie

Il faut noter que lorsque le texte du Entry est modifié par un choix dans la liste déroulante, le gestionnaire du signal "changed" est appelé deux fois : une fois quand le texte est supprimé et une autre fois quand le texte prend la valeur du texte de l'élément de liste choisi.

XVI-B-2-b. Utilisation avancée du ComboBoxEntry

Le constructeur du ComboBoxEntry est :

 
Sélectionnez
  boitderoulsaisie = gtk.ComboBoxEntry(model=None, column=-1)

model est un TreeModel et column est le numéro de la colonne du model à utiliser pour créer la liste d'éléments. Si la colonne n'est pas précisée, la valeur par défaut est -1, ce qui signifie que la colonne du texte n'est pas indiquée.

Créer un ComboBoxEntry avec la fonction auxiliaire gtk.combo_box_entry_new_text() est équivalent à :

 
Sélectionnez
  liststore = gtk.ListStore(str)
  boitderoulsaisie = gtk.ComboBoxEntry(liststore, 0)

Le ComboBoxEntry ajoute quelques méthodes utilisées pour fixer et récupérer le numéro de colonne du TreeModel à utiliser pour fixer les chaines des éléments de liste :

 
Sélectionnez
  boitderoulsaisie.set_text_column(text_column)
  text_column = boitderoulsaisie.get_text_column()

La colonne du texte peut aussi être récupérée et fixée en utilisant la propriété "text-column". Se reporter à la section Section 16.2.1.2, « Usage avancé de ComboBox »Usage avancé de ComboBox pour plus de renseignements sur l'utilisation avancée du ComboBoxEntry.

Votre application doit indiquer la colonne de texte pour que le ComboBoxEntry établisse le contenu de la zone Entry depuis la liste déroulante. La colonne de texte ne peut être indiquée qu'une fois, soit en utilisant le constructeur, soit en utilisant la méthode set_text_column().

Lorsque l'on crée un ComboBoxEntry, il est placé avec un nouveau CellRendererText qui n'est pas accessible. L' attribut 'text' du CellRendererText doit être fixé, c'est un effet secondaire de l'utilisation de la méthode set_text_column() pour déterminer la colonne de texte. On peut placer des CellRenderer supplémentaires dans un ComboBoxEntry pour l'affichage dans la liste déroulante. Se reporter à la section Section 16.2.1.2, « Usage avancé de ComboBox »Usage avancé de ComboBox pour plus d'information.

XVI-C. Bouton de couleur (ColorButton) et de police (FontButton)

XVI-C-1. Bouton de couleur (ColorButton)

Un widget ColorButton fournit une manière commode d'afficher une couleur dans un bouton que l'on peut cliquer pour ouvrir une fenêtre ColorSelectionDialog de choix de couleur. C'est utile pour afficher et sélectionner des couleurs dans un dialogue et, de préférence d'utilisateurs. Un ColorButton se charge d'établir, d'afficher et récupérer le résultat de la fenêtre de sélection de couleur ColorSelectionDialog. On crée un ColorButton par le constructeur :

 
Sélectionnez
  colorbutton = gtk.ColorButton(color=gtk.gdk.Color(0,0,0))

La couleur de départ peut être précisée par le paramètre color ou établie par la suite avec la méthode :

 
Sélectionnez
  colorbutton.set_color(color)

Le titre de la fenêtre ColorSelectionDialog qui s'affiche quand on clique sur le bouton peut être fixé et récupéré par la méthode :

 
Sélectionnez
1.
2.
3.
  colorbutton.set_title(title)

  title = colorbutton.get_title()

L'opacité de la couleur est fixée en utilisant le canal alpha. Les méthodes suivantes récupèrent et fixent l'opacité de la couleur dans une gamme de 0 (transparent) à 65535 (opaque) :

 
Sélectionnez
1.
2.
3.
  alpha = colorbutton.get_alpha()

  colorbutton.set_alpha(alpha)

Par défaut, la valeur alpha est ignorée, car la propriété "use_alpha" est fixée à FALSE. La valeur de cette propriété "use_alpha" peut être fixée et récupérée par la méthode :

 
Sélectionnez
1.
2.
3.
  colorbutton.set_use_alpha(use_alpha)

  use_alpha = colorbutton.get_use_alpha()

Si "use_alpha" vaut TRUE, la fenêtre ColorSelectionDialog affiche un curseur pour régler l'opacité et montre la couleur sur un fond à damier.

On peut surveiller les changements de la couleur choisie en se reliant au signal "color-set" qui est émis quand l'utilisateur choisit une couleur. La fonction de rappel du signal est :

 
Sélectionnez
  def color_set_cb(colorbutton, user_data):

Le programme colorbutton.py illustre l'utilisation du bouton de couleur ColorButton. La Figure 16.8, « Exemple de bouton de couleur »« Exemple de bouton de couleur »« Exemple de bouton de couleur » montre le programme en cours d'exécution.

Image non disponible
Figure 16.8. Exemple de bouton de couleur

XVI-C-2. Bouton de police (FontButton)

Comme le ColorButton, le bouton de police FontButton est un widget pratique qui fournit un aperçu de la police actuellement choisie et qui ouvre une fenêtre FontSelectionDialog quand on le clique. Un bouton FontButton se charge d'établir, d'afficher et de récupérer le résultat de la fenêtre de sélection de police FontSelectionDialog. On le crée par le constructeur :

 
Sélectionnez
  boutonpolice = gtk.FontButton(nompolice=None)

nompolice est une chaine indiquant la police courante de la fenêtre FontSelectionDialog. Par exemple, le nom de la police peut être écrit comme 'Sans 12', 'Sans Bold 14', ou 'Monospace Italic 14'. Il est nécessaire d'indiquer au minimum la famille et la taille de la police.

La police en cours peut aussi être fixée et récupérée par les méthodes suivantes :

 
Sélectionnez
1.
2.
3.
  resultat = boutonpolice.set_font_name(nompolice)

  nompolice = boutonpolice.get_font_name()

resultat renvoie TRUE ou FALSE pour indiquer si la prise en compte de la police a été réalisée avec succès. Le FontButton possède un certain nombre de propriétés et méthodes associées qui agissent sur l'affichage de la police en cours dans le bouton FontButton. Les propriétés "show-size" et "show-style" contiennent des valeurs booléennes qui contrôlent si la taille et le style seront affichés dans l'étiquette du bouton. Les méthodes suivantes fixent et récupèrent les valeurs de ces propriétés :

 
Sélectionnez
1.
2.
3.
4.
5.
  boutonpolice.set_show_style(show_style)
  show_style = boutonpolice.get_show_style()

  boutonpolice.set_show_size(show_size)
  show_size = boutonpolice.get_show_size()

Autre manière, vous pouvez utiliser la taille et le style actuellement affichés par l'étiquette pour illustrer directement le choix de police. Voici les méthodes associées aux propriétés "use-size" et "use-font" :

 
Sélectionnez
1.
2.
3.
4.
5.
  boutonpolice.set_use_font(use_font)
  use_font = boutonpolice.get_use_font()

  boutonpolice.set_use_size(use_size)
  use_size = boutonpolice.get_use_size()

Employer la police courante sur l'étiquette semble une technique utile malgré les inévitables changements de taille du bouton, mais utiliser la taille choisie n'apparait pas aussi utile, surtout avec de très grandes ou très petites tailles de police. Il faut noter que si on fixe "use-font" ou "use-size" à TRUE pour ensuite les mettre à FALSE, les dernières polices et tailles utilisées seront conservées. Par exemple, si "use-font" et "use-size" ont la valeur TRUE et que la police actuelle est Monospace Italic 20, l'étiquette du bouton FontButton s'affiche en Monospace Italic 20 ; puis si "use-font" et "use-size" passent à FALSE et que la police en cours est modifiée en Sans 12, l'étiquette s'affichera encore en Monospace Italic 20. Employez le programme d'exemple fontbutton.py pour voir comment ceci fonctionne.

Enfin, le titre de la fenêtre FontSelectionDialog peut être fixé et récupéré grâce aux méthodes :

 
Sélectionnez
1.
2.
3.
  boutonpolice.set_title(titre)

  titre = boutonpolice.get_title()

Comme pour le bouton ColorButton, on peut surveiller les changements dans la police en cours en se connectant au signal émis lorsque l'utilisateur choisit une police. La fonction de rappel du signal a la forme :

 
Sélectionnez
  def fct_rappel_choixpolice(boutonpolice, données utilisateur):

Le programme d'exemple fontbutton.py illustre l'utilisation du FontButton. On peut fixer les propriétés "use-font", "use-size", "show-size" et "show-style" avec les boutons interrupteurs. La Figure 16.9, « Exemple de bouton de police » montre le programme en cours d'exécution.

Image non disponible
Figure 16.9. Exemple de bouton de police

XVI-D. Zone de saisie avec complètement (EntryCompletion)

Une zone de saisie avec complètement (EntryCompletion) est un objet associé à un champ de saisie (Entry) pour fournir la fonction de complètement. Lorsque l'utilisateur entre des données dans le champ de saisie Entry, le EntryCompletion fait apparaitre une fenêtre contextuelle montrant un ensemble de chaines de caractères correspondant au texte du champ de saisie (Entry).

Un EntryCompletion est créé par le constructeur :

 
Sélectionnez
  completion = gtk.EntryCompletion()

On peut utiliser la méthode set_completion() du champ de saisie Entry pour associer le EntryCompletion au Entry :

 
Sélectionnez
  entry.set_completion(completion)

Les chaines de caractères qu'utilise le EntryCompletion pour la correspondance sont récupérées depuis un TreeModel (généralement un ListStore) qui doit être défini par la méthode :

 
Sélectionnez
  completion.set_model(model)

Le EntryCompletion implémente l'interface CellLayout, à la manière du TreeViewColumn, pour gérer l'affichage des données du TreeModel. La méthode suivante définit un EntryCompletion sous la forme la plus courante - une liste de chaines de caractères :

 
Sélectionnez
  completion.set_text_column(column)

Cette méthode est équivalente à  :

 
Sélectionnez
1.
2.
3.
  cell = CellRendererText()
  completion.pack_start(cell)
  completion.add_attribute(cell, 'text', column)

Pour définir le nombre de caractères qui doivent être entrés avant que le EntryCompletion recherche une correspondance, on peut utiliser la méthode :

 
Sélectionnez
  completion.set_minimum_key_length(length)

Le programme d'exemple entrycompletion.py illustre l'utilisation du EntryCompletion. La Figure 16.10, « Saisie avec complètement » montre le programme en cours d'exécution.

Image non disponible
Figure 16.10. Saisie avec complètement

Le programme d'exemple démarre avec un faible nombre de chaines de "complètement" qui peut être augmenté en entrant des données dans le champ de saisie et en appuyant sur la touche Entrée. Si la chaine est unique, elle est ajoutée à la liste des chaines de "complètement".

La fonction interne de concordance ne tient pas compte de la casse (minuscule/majuscule). Si on a besoin d'une fonction plus spécifique, il est possible d'utiliser la méthode suivante pour installer sa propre fonction de concordance :

 
Sélectionnez
  completion.set_match_func(func, user_data)

La fonction func est :

 
Sélectionnez
  def func(completion, key_string, iter, data):

où le paramètre key_string contient le contenu courant du champ Entry, iter est un TreeIter pointant sur une ligne dans le TreeModel associé et data contient les données utilisateur user_data. Le paramètre func devrait renvoyer TRUE si la chaine de "complètement" de la ligne devrait être affichée.

L'extrait de code suivant utilise une fonction de concordance pour afficher les possibles chaines de "complètement" qui commencent par le contenu du champ de saisie et qui possèdent le suffixe indiqué (ici, un nom se terminant par .png pour un fichier PNG file.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
  ...
  completion.set_match_func(end_match, (0, '.png'))
  ...
  def end_match(completion, entrystr, iter, data):
      column, suffix = data
      model = completion.get_model()
      modelstr = model[iter][column]
      return modelstr.startswith(entrystr) and modelstr.endswith(suffix)
  ...

Par exemple, si l'utilisateur tape 'mou' et que le modèle de "complètement" contient une chaine comme 'moulin.png', 'farine.png', 'moule.png' et 'mou.tif', les choix 'moulin.png' et moule.png' seront proposés comme "complètement".

XVI-E. Expanseur (Expander)

L'expanseur (Expander) est un conteneur assez simple qui peut montrer ou cacher son widget fils en cliquant sur un triangle semblable au triangle du TreeView. On crée un Expander par le constructeur :

 
Sélectionnez
  expander = gtk.Expander(label=None)

où le paramètre label est une chaine de caractères utilisée comme étiquette de l'expanseur. Si label vaut None ou n'est pas défini, aucune étiquette ne sera créée. D'une autre manière, on peut utiliser la fonction :

 
Sélectionnez
  expander = gtk.expander_new_with_mnemonic(label=None)

qui définit le caractère de l'étiquette précédé par un trait de soulignement comme un raccourci-clavier.

Le widget Expander utilise l'API de Container pour ajouter ou retirer son widget fils :

 
Sélectionnez
1.
2.
3.
  expander.add(widget)

  expander.remove(widget)

Le widget fils peut être récupéré en utilisant l'attribut "child" de Bin ou par la méthode get_child().

L'option qui contrôle l'interprétation des caractères soulignés de l'étiquette peut être récupérée et modifiée par ces méthodes :

 
Sélectionnez
1.
2.
3.
  use_underline = expander.get_use_underline()

  expander.set_use_underline(use_underline)

Si on souhaite utiliser le marquage Pango (voir les détails dans Référence du marquage Pango) dans le libellé de l'étiquette, il faut utiliser les méthodes suivantes pour récupérer et définir l'état de la propriété "use-markup" :

 
Sélectionnez
1.
2.
3.
  expander.set_use_markup(use_markup)

  use_markup = expander.get_use_markup()

Enfin, on peut utiliser n'importe quel widget comme label en utilisant la méthode suivante :

 
Sélectionnez
  expander.set_label_widget(label_widget)

Ceci permet, par exemple, d'utiliser une boite HBox contenant une Image et un Label comme étiquette du Expander.

L'état du Expander peut être récupéré et défini par ces méthodes :

 
Sélectionnez
1.
2.
3.
  expanded = expander.get_expanded()

  expander.set_expanded(expanded)

Si le paramètre expanded vaut TRUE, le widget fils est affiché.

Dans la plupart des cas, le Expander effectue automatiquement ce que l'on veut lorsqu'il affiche ou cache le widget fils. Parfois, l'application peut vouloir créer un widget fils au moment de l'expansion. Le signal "notify::expanded" peut être utilisé pour garder trace des changements d'état du triangle d'expansion. Le gestionnaire de signal peut alors créer ou modifier le widget fils en fonction des besoins.

Le programme d'exemple expander.py illustre l'utilisation du Expander. La Figure 16.11, « Expander Widget » montre le programme en cours d'exécution.

Image non disponible
Figure 16.11. Expander Widget

Ce programme crée un Label contenant le temps courant et l'affiche quand l'expanseur est ouvert.

XVI-F. Sélection de fichiers basée sur le sélecteur FileChooser

La nouvelle manière de choisir un fichier dans PyGTK 2.4 consiste à utiliser les variantes du widget FileChooser. Les deux objets qui implémentent cette nouvelle interface dans PyGTK 2.4 sont FileChooserWidget et FileChooserDialog. Ce dernier est un dialogue complet avec la fenêtre et des boutons facilement définis. Le premier est un widget utile pour l'inscrire dans un autre widget.

Le FileChooserWidget comme le FileChooserDialog possèdent les capacités de naviguer dans l'arborescence du système de fichiers et d'en sélectionner. L'apparence du widget dépend de l'action utilisée pour l'ouvrir.

Pour créer une nouvelle fenêtre de sélection de fichiers et pour choisir un fichier existant (comme dans le classique Fichier ? Ouvrir), il faut utiliser :

 
Sélectionnez
  chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_OPEN,
                                  buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))

Pour créer une nouvelle fenêtre de sélection de fichiers et pour choisir un nouveau nom de fichier (comme dans le classique Fichier ? Enregistrer), il faut utiliser :

 
Sélectionnez
  chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_SAVE,
                                  buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))

Dans les exemples précédents, les deux boutons (éléments de stock Annuler et Ouvrir) sont créés et connectés à leur réponse respective (réponses Annuler et Valider(OK)).

Pour définir le dossier qui sera affiché dans le sélecteur de fichiers, on utilise la méthode :

 
Sélectionnez
  chooser.set_current_folder(pathname)

Pour définir le nom de fichier suggéré comme s'il était tapé par l'utilisateur (le classique Fichier ? Enregistrer Sous), on utilise la méthode :

 
Sélectionnez
  chooser.set_current_name(name)

La méthode ci-dessus n'exige pas que le nom du fichier existe déjà. Si on préfère présélectionner un fichier existant particulier (comme dans Fichier ? Ouvrir), on utilise la méthode :

 
Sélectionnez
  chooser.set_filename(filename)

Pour récupérer le nom du fichier que l'utilisateur a tapé ou sur lequel il a cliqué, on utilise la méthode :

 
Sélectionnez
  filename = chooser.get_filename()

Il est possible d'autoriser de multiples sélections (uniquement pour l'action gtk.FILE_CHOOSER_ACTION_OPEN) en utilisant la méthode :

 
Sélectionnez
  chooser.set_select_multiple(select_multiple)

où le paramètre select_mutiple doit valoir TRUE pour autoriser les sélections multiples. Dans ce cas, il faudra utiliser la méthode suivante pour récupérer la liste des fichiers sélectionnés :

 
Sélectionnez
  filenames = chooser.get_filenames()

Une caractéristique importante de tous les sélecteurs de fichiers est leur capacité à ajouter des filtres de sélection de fichiers. Le filtre peut être ajouté par cette méthode :

 
Sélectionnez
  chooser.add_filter(filter)

Dans l'exemple ci-dessus, filter doit être une instance de la classe FileFilter.

Le panneau de gauche du sélecteur de fichier contient quelques signets (raccourcis vers les dossiers) tels Dossier personnel, Système de fichiers, CD-ROM, etc. Il est possible d'ajouter un dossier à la liste de ces signets, ou de l'enlever, avec ces méthodes :

 
Sélectionnez
  chooser.add_shortcut_folder(folder)
  chooser.remove_shortcut_folder(folder)

folder est le chemin du dossier. Le programme d'exemple filechooser.py illustre l'utilisation du sélecteur de fichier. La Figure 16.12, « Exemple de sélecteur de fichiers » montre le programme en cours d'exécution.

Image non disponible
Figure 16.12. Exemple de sélecteur de fichiers

Voici le code source du programme filechooser.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.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
#!/usr/bin/env python
# coding: utf8
# exemple filechooser.py

import pygtk
pygtk.require('2.0')

import gtk

# Vérification du nouveau PyGtk : c'est une nouvelle classe de PyGtk 2.4
if gtk.pygtk_version < (2,3,90):
   print "Cet exemple nécessite PyGtk 2.3.90 ou ultérieur"
   raise SystemExit

dialogue = gtk.FileChooserDialog("Ouvrir. ",
                               None,
                               gtk.FILE_CHOOSER_ACTION_OPEN,
                               (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                gtk.STOCK_OPEN, gtk.RESPONSE_OK))
dialogue.set_default_response(gtk.RESPONSE_OK)

filtre = gtk.FileFilter()
filtre.set_name("All files")
filtre.add_pattern("*")
dialogue.add_filter(filtre)

filtre = gtk.FileFilter()
filtre.set_name("Images")
filtre.add_mime_type("image/png")
filtre.add_mime_type("image/jpeg")
filtre.add_mime_type("image/gif")
filtre.add_pattern("*.png")
filtre.add_pattern("*.jpg")
filtre.add_pattern("*.gif")
filtre.add_pattern("*.tif")
filtre.add_pattern("*.xpm")
dialogue.add_filter(filtre)

reponse = dialogue.run()
if reponse == gtk.RESPONSE_OK:
    print dialogue.get_filename(), 'choisi'
elif reponse == gtk.RESPONSE_CANCEL:
    print 'On ferme, pas de fichier sélectionné'
dialogue.destroy()

XVI-G. Le gestionnaire d'Interface Utilisateur UIManager

XVI-G-1. Aperçu

Le gestionnaire UIManager fournit des outils pour créer des menus et des barres d'outils à partir d'une description de type XML. Le UIManager utilise les objets du ActionGroup pour gérer les objets de l'Action fournissant une infrastructure commune aux éléments de menu et de barre d'outils.

L'utilisation de l'UIManager permet de fusionner et de scinder dynamiquement des descriptions et actions de UI multiples. Ceci permet de modifier les menus et les barres d'outils selon le mode utilisé dans l'application (par exemple, passer d'une édition de texte à une édition d'image), ou quand de nouvelles extensions sont ajoutées ou enlevées de l'application.

Un UIManager peut être utilisé pour créer les menus et les barres d'outils d' un interface utilisateur de la façon suivante.

  • Créer une instance de l'UIManager.
  • Extraire l'AccelGroup de l'UIManager et l'ajouter à la Fenêtre de niveau supérieur.
  • Créer des instances de l'ActionGroup et les remplir avec les Action voulues. instances.
  • Ajouter les instances de l'ActionGroup à l'UIManager dans l'ordre dans lequel on souhaite présenter les instances des Action.
  • Ajouter les descriptions XML de l'interface UI à l'UIManager. Il faut s'assurer que toutes les Actions définies par les descriptions soient disponibles dans les instances ActionGroup de l'UIManager.
  • Extraire, par leur nom, les références des widgets de la barre de menu, du menu et de la barre d'outils pour les utiliser dans la construction de l'interface utilisateur.
  • Modifier l'interface de manière dynamique, en ajoutant ou retirant des descriptions d'Interface Utilisateur et en ajoutant, réordonnant ou retirant les instances associées des groupes d'actions ActionGroup.

XVI-G-2. Créer un UIManager

Une instance de l'UIManager se crée par le constructeur :

 
Sélectionnez
  gestionui = gtk.UIManager()

Un nouveau UIManager est créé avec son groupe d'accélérateurs associé AccelGroup, lequel peut être récupéré avec la méthode  :

 
Sélectionnez
  grouperacc = gestionui.get_accel_group()

Le groupe AccelGroup doit être ajouté à la fenêtre de niveau supérieur pour que les accélérateurs (raccourcis-clavier) de l'Action puissent être disponibles pour les utilisateurs. Par exemple :

 
Sélectionnez
1.
2.
3.
4.
5.
  fenetre = gtk.Window()
  ...
  gestionui = gtk.UIManager()
  grouperacc = gestionui.get_accel_group()
  fenetre.add_accel_group(accelgroup)

XVI-G-3. Ajouter et supprimer des groupes d'actions

Comme on l'a vu dans la Section 16.1.2, « ActionGroup »ActionGroup, un groupe d'actions ActionGroups peut être rempli avec des Actions en utilisant les méthodes add_actions(), add_toggle_actions() et add_radio_actions(). Un ActionGroup peut être utilisé par un UIManager lorsqu'il a été ajouté à sa liste des ActionGroup par la méthode :

 
Sélectionnez
  gestionui.insert_action_group(action_group, pos)

pos est l'indication de la position où l'action_group doit être inséré. Un UIManager peut comporter plusieurs groupes ActionGroup avec des noms de Action en double. L'ordre des objets d'un ActionGroup est important, car la recherche d'une Action par son nom s'arrête sur la première Action trouvée. Ceci signifie que les premières actions dans les objets ActionGroup masquent les suivantes.

Les actions inscrites dans la description XML d'une Interface Utilisateur doivent être ajoutées dans l'UIManager avant que la description elle-même puisse l'être.

Un ActionGroup peut être supprimé d'un UIManager par la méthode :

 
Sélectionnez
  gestionui.remove_action_group(action_group)

Une liste des objets ActionGroup associés à l'UIManager peut être récupérée par la méthode :

 
Sélectionnez
  listegroupesactions = gestionui.get_action_groups()

XVI-G-4. Descriptions de l'Interface Utilisateur

Les descriptions d'Interface Utilisateur acceptées par le UIManager sont de simples définitions XML qui comportent les éléments suivants :

ui

L'élément racine de la description de l'Interface Utilisateur. Il peut être omis. Il peut contenir les éléments menubar, popup, toolbar et accelerator.

menubar

Un élément de premier niveau qui décrit une structure de barre de menu MenuBar qui peut contenir les éléments MenuItem, separator, placeholder et menu. Il possède en option un attribut name. Si cet attribut name n'est pas précisé, il aura pour valeur "menubar".

popup

Un élément de premier niveau qui décrit une structure de menu popup Menu qui peut contenir les éléments menuitem, separator, placeholder et menu. Il possède en option un attribut name. Si cet attribut name n'est pas précisé, il aura pour valeur "popup".

toolbar

Un élément de premier niveau qui décrit une structure de barre d'outils Toolbar qui peut contenir les éléments tolite, separator et placeholder. Il possède en option un attribut name. Si cet attribut name n'est pas précisé, il aura pour valeur "toolbar".

placeholder

Un élément identifiant une position dans un menubar, toolbar, popup ou menu. Ce paramètre substituable peut contenir les éléments menuitem, separator, placeholder et menu. Les éléments substituables Placeholder sont utilisés pour fusionner plusieurs descriptions d'Interface Utilisateur pour permettre, par exemple, la construction d'un menu à partir de descriptions d'Interface Utilisateur en utilisant des noms de placeholder partagés. Il possède en option un attribut name. Si cet attribut name n'est pas précisé, il aura pour valeur "placeholder".

menu

Un élément décrivant une structure de Menu qui peut contenir les éléments menuitem, separator, placeholder et menu. Un élément menu possède obligatoirement un attribut action qui désigne un objet Action, utilisé pour créer le Menu. Il possède en option les attributs name et position. Si l'attribut name n'est pas précisé, il aura pour valeur le nom de l'élément action. L'attribut position peut avoir pour valeur "top" ou "bottom". Si sa valeur n'est pas précisée, ce sera, par défaut, "bottom".

menuitem

Un élément décrivant un MenuItem. Un élément menuitem possède un attribut obligatoire action qui désigne un objet Action utilisé pour créer l'élément de menu MenuItem. Il possède également les attributs facultatifs name et position. Si name n'est pas précisé, le nom de action sera utilisé. L'attribut position peut avoir pour valeur "top" ou "bottom". Si sa valeur n'est pas précisée, ce sera, par défaut, "bottom".

tolite

Décrit un élément de barre d'outils ToolItem. Un élément tolite possède un attribut obligatoire action qui désigne un objet Action utilisé pour créer la barre d'outils Toolbar. Il possède également les attributs facultatifs name et position. Si name n'est pas précisé, le nom de action sera utilisé. L'attribut position peut avoir pour valeur "top" ou "bottom". Si sa valeur n'est pas précisée, ce sera par défaut, "bottom".

separator

Élément décrivant un séparateur d'éléments de menu SeparatorMenuItem ou SeparatorToolItem selon les cas.

accelerator

Élément décrivant un raccourci-clavier. Un élément accelerator possède un attribut obligatoire action qui désigne un objet Action pour définir la combinaison de touches du clavier et qui est activé par l'accélérateur. Il possède également l'attribut facultatif name. Si name n'est pas précisé, le nom de l'action sera utilisé.

Par exemple, voici une description d'Interface Utilisateur qui peut être utilisée pour créer une interface semblable à celle de la Figure 16.4, « Exemple avec ActionGroup » :

 
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.
  <ui>
    <menubar name="BarreMenu">
      <menu action="Fichier">
        <menuitem action="Quitter"/>
      </menu>
      <menu action="Son">
        <menuitem action="Volume"/>
      </menu>
      <menu action="Modulation">
        <menuitem action="MA"/>
        <menuitem action="MF"/>
        <menuitem action="BLU"/>
      </menu>
    </menubar>
    <toolbar name="BarreOutils">
      <tolite action="Quitter"/>
      <separator/>
      <tolite action="Volume"/>
      <separator/>
      <placeholder name="ElementsMod">
        <tolite action="MA"/>
        <tolite action="MF"/>
        <tolite action="BLU"/>
      </placeholder>
    </toolbar>
  </ui>

Il faut noter que cette description utilise simplement les noms d'attributs du action comme nom de la plupart des éléments plutôt que de préciser leurs attributs name. Aussi, je recommanderais de ne pas préciser l'élément ui lorsque cela n'est pas indispensable.

La hiérarchie de widgets créée par une description d'Interface Utilisateur est tout à fait semblable à une hiérarchie d'éléments XML, excepté que les éléments placeholder sont fusionnés dans leurs parents.

On peut avoir accès à un widget appartenant à la hiérarchie de la description de l'Interface Utilisateur en utilisant son chemin ; celui-ci est composé du nom du widget et de ses éléments parents reliés par des barres obliques ("/"). À partir de la description ci-dessus, voici des exemples de chemins de widgets valides :

 
Sélectionnez
1.
2.
3.
4.
5.
  /BarreMenu
  /BarreMenu/Fichier/Quitter
  /BarreMenu/Modulation/BLU
  /BarreOutils/Volume
  /BarreOutils/ElementsMod/MF

Il faut noter que le nom de l'élément de substitution placeholder doit être inclus dans le chemin. Dans la plupart des cas, on ne s'intéresse qu'aux widgets de niveau supérieur (par exemple "/MenuBar" et "/Toolbar"), mais on peut avoir besoin d'accéder à un widget de plus bas niveau pour, par exemple, modifier une propriété.

XVI-G-5. Ajouter et supprimer des descriptions d'Interface Utilisateur

Une fois le UIManager configuré avec un ActionGroup, une description d'Interface Utilisateur peut être ajoutée ou fusionnée avec l'Interface Utilisateur existant par l'une de ces méthodes :

 
Sélectionnez
1.
2.
3.
  fusion_id = gestionui.add_ui_from_string(buffer)

  fusion_id = gestionui.add_ui_from_file(filename)

où le paramètre buffer est une chaine de caractères contenant une description d'Interface Utilisateur et filename se réfère au fichier contenant la description. Les deux méthodes renvoient un identifiant fusion_id qui est une valeur entière unique. Si la méthode échoue, une exception GError est levée. L'identifiant merge_id peut servir à supprimer la description d'Interface Utilisateur en utilisant la méthode :

 
Sélectionnez
  gestionui.remove_ui(fusion_id)

Les mêmes méthodes peuvent être utilisées plusieurs fois pour ajouter des descriptions supplémentaires qui peuvent être fusionnées pour obtenir une description combinée d'Interface Utilisateur en XML. Les Interfaces Utilisateurs combinées seront traitées plus en détail dans la Section 16.7.8, « Combiner des descriptions d'Interface Utilisateur »Combiner des descriptions d'Interface Utilisateur.

On peut ajouter un seul élément à la description d'Interface Utilisateur existante par la méthode :

 
Sélectionnez
  gestionui.add_ui(fusion_id, path, name, action, type, top)

où l'identifiant fusion_id est un entier unique, path est le chemin où le nouvel élément doit être ajouté, action est le nom de l'Action ou None pour ajouter un separator, type est le type de l'élément à ajouter et top une valeur booléenne. Si top vaut TRUE, l'élément est inséré avant son frère (élément de même niveau), sinon, il est ajouté à la suite.

Le paramètre merge_id sera obtenu par la méthode :

 
Sélectionnez
  fusion_id = gestionui.new_merge_id()

Les valeurs entières retournées par la méthode new_merge_id() augmentent arithmétiquement.

Le paramètre path est une chaine de caractères composée du nom de l'élément et du nom de ses ancêtres, séparés par un trait oblique ("/"), qui n'inclut pas le nœud racine optionnel "/ui". Par exemple "/BarreMenu/Modulation" représente le chemin de l'élément de menu nommé "Modulation" dans la description d'Interface Utilisateur suivante :

 
Sélectionnez
1.
2.
3.
4.
  <menubar name="BarreMenu">
    <menu action="Modulation">
    </menu>
  </menubar>

La valeur du paramètre type doit être parmi :

gtk.UI_MANAGER_AUTO

Le type de l'élément d'Interface Utilisateur (menuitem, toolitem ou separator) est défini en fonction du contexte.

gtk.UI_MANAGER_MENUBAR

Une barre de menu.

gtk.UI_MANAGER_MENU

Un menu.

gtk.UI_MANAGER_TOOLBAR

Une barre d'outils.

gtk.UI_MANAGER_PLACEHOLDER

Une élément de réservation (placeholder).

gtk.UI_MANAGER_POPUP

Un menu popup.

gtk.UI_MANAGER_MENUITEM

Un élément de menu).

gtk.UI_MANAGER_TOOLITEM

Un élément de barre d'outils.

gtk.UI_MANAGER_SEPARATOR

Un séparateur.

gtk.UI_MANAGER_ACCELERATOR

Un raccourci ou accélérateur.

La méthode add_ui() échoue sans le signaler si l'élément n'est pas ajouté. La méthode add_ui() est de si bas niveau qu'il faut plutôt toujours essayer d'utiliser les méthodes pratiques add_ui_from_string() et add_ui_from_file()

Ajouter un élément ou une description d'Interface Utilisateur entraine l'actualisation de la hiérarchie des widgets dans une fonction en attente. On peut s'assurer que la hiérarchie a bien été actualisée avant d'y accéder en appelant la méthode :

 
Sélectionnez
  gestionui.ensure_update()

XVI-G-6. Accès aux widgets d'une Interface Utilisateur

On peut avoir accès à un widget dans la hiérarchie de l'Interface Utilisateur en utilisant la méthode :

 
Sélectionnez
  widget = gestionui.get_widget(path)

où le paramètre path est une chaine de caractères qui contient le nom de l'élément recherché et celui de ses ancêtres comme on l'a expliqué dans la Section 16.7.4, « Descriptions de l'Interface Utilisateur »Descriptions de l'Interface Utilisateur.

Par exemple, étant donné la description d'Interface Utilisateur suivante :

 
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.
  <menubar name="BarreMenu">
    <menu action="Fichier">
      <menuitem action="Quitter"/>
    </menu>
    <menu action="Son">
      <menuitem action="Volume"/>
    </menu>
    <menu action="Modulation">
      <menuitem action="MA"/>
      <menuitem action="MF"/>
      <menuitem action="BLU"/>
    </menu>
  </menubar>
  <toolbar name="BarreOutils">
    <tolite action="Quitter"/>
    <separator/>
    <tolite action="Volume"/>
    <separator name="sep1"/>
    <placeholder name="ElementsMod">
      <tolite action="MA"/>
      <tolite action="MF"/>
      <tolite action="BLU"/>
    </placeholder>
  </toolbar>

que l'on a ajouté au gestionnaire d'UIManager gestionui, on peut accéder à la BarreMenu et à la BarreOutils pour les utiliser dans une application Window en utilisant le code suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
  fenêtre = gtk.Window()
  vbox = gtk.VBox()
  barremenus = gestionui.get_widget('/BarreMenu')
  barreoutils = gestionui.get_widget('/BarreOutils')
  vbox.pack_start(barremenus, False)
  vbox.pack_start(barreoutils, False)

De la même manière, les widgets de plus bas niveau dans la hiérarchie sont accessibles en utilisant leur chemin. Par exemple, le bouton RadioToolButton appelé "BLU" est accessible ainsi :

 
Sélectionnez
  blu = gestionui.get_widget('/BarreOutils/ElementsMod/BLU')

Pour faciliter la tâche, on peut accéder à tous les widgets de haut niveau d'un même type avec la méthode :

 
Sélectionnez
  toplevels = gestionui.get_toplevels(type)

où le paramètre type indique le type des widgets à renvoyer en utilisant une combinaison des drapeaux : gtk.UI_MANAGER_MENUBAR, gtk.UI_MANAGER_TOOLBAR et gtk.UI_MANAGER_POPUP. On peut utiliser la méthode gtk.Widget.get_name() pour déterminer quel est le widget de haut niveau obtenu.

Pour trouver l'Action utilisée par le widget délégué associé à un élément d'Interface Utilisateur, on utilise la méthode :

 
Sélectionnez
  action = gestionui_get_action(path)

où le paramètre path est une chaine de caractères représentant le chemin d'un élément d'Interface Utilisateur dans le gestionnaire gestionui. Si l'élément ne possède pas d'Action associé, la valeur est retournée.

XVI-G-7. Un exemple d'Interface Utilisateur simple

Le programme uimanager.py illustre l'utilisation du gestionnaire UIManager. La Figure 16.13, « Exemple simple de UIManager » montre le programme en cours d'exécution.

Image non disponible
Figure 16.13. Exemple simple de UIManager

Le programme uimanager.py utilise la description XML de la Section 16.7.6, « Accès aux widgets d'une Interface Utilisateur »Accès aux widgets d'un Interface Utilisateur. Le texte des deux étiquettes est modifié par l'activation de l'action interrupteur ToggleAction "Volume" et des choix des RadioAction "MA", "MF" et "BLU". Toutes les actions sont inscrites dans un unique ActionGroup qui permet à la sensibilité et à la visibilité de tous les widgets délégués d'être commutées en utilisant les boutons interrupteurs "Sensible" et "Visible". L'utilisation de l'élément placeholder sera décrite en détail dans la Section 16.7.8, « Combiner des descriptions d'Interface Utilisateur »Combiner des descriptions d'Interface Utilisateur.

XVI-G-8. Combiner des descriptions d'Interface Utilisateur

La fusion de plusieurs descriptions d'Interface Utilisateur se réalise en fonction du nom des éléments XML. Comme on a ce nom auparavant, on peut avoir accès aux éléments individuels de la hiérarchie par leur nom de chemin qui est représenté par leur nom plus le nom de leurs ancêtres. Par exemple, si on utilise la description d'Interface Utilisateur de la Section 16.7.4, « Descriptions de l'Interface Utilisateur »Descriptions de l'Interface Utilisateur, l'élément tolite "MA" a pour nom de chemin "/BarreOutils/ElementsMod/MA" alors que le nom de chemin de l'élément menuitem est "/BarreMenu/Modulation/MF".

Si une description d'Interface Utilisateur est fusionnée avec la précédente, les éléments sont ajoutés en tant que frères (au même niveau) aux éléments existants. Par exemple, si la description d'Interface Utilisateur :

 
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.
  <menubar name="BarreMenu">
    <menu action="Fichier">
      <menuitem action="Enregistrer" position="top"/>
      <menuitem action="Nouveau" position="top"/>
    </menu>
    <menu action="Son">
      <menuitem action="Intensite"/>
    </menu>
    <menu action="Modulation">
      <menuitem action="CB"/>
      <menuitem action="OndesCourtes"/>
    </menu>
  </menubar>
  <toolbar name="BarreOutils">
    <tolite action="Enregistrer" position="top"/>
    <tolite action="Nouveau" position="top"/>
    <separator/>
    <tolite action="Intensite"/>
    <separator/>
    <placeholder name="ElementsMod">
      <tolite action="CB"/>
      <tolite action="OndesCourtes"/>
    </placeholder>
  </toolbar>

est ajoutée à notre exemple précédent :

 
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.
  <menubar name="BarreMenu">
    <menu action="Fichier">
      <menuitem action="Quitter"/>
    </menu>
    <menu action="Son">
      <menuitem action="Volume"/>
    </menu>
    <menu action="Modulation">
      <menuitem action="MA"/>
      <menuitem action="MF"/>
      <menuitem action="BLU"/>
    </menu>
  </menubar>
  <toolbar name="BarreOutils">
    <tolite action="Quitter"/>
    <separator/>
    <tolite action="Volume"/>
    <separator name="sep1"/>
    <placeholder name="ElementsMod">
      <tolite action="MA"/>
      <tolite action="MF"/>
      <tolite action="BLU"/>
    </placeholder>
  </toolbar>

Le résultat final créé sera :

 
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.
  <menubar name="BarreMenu">
    <menu name="Fichier" action="Fichier">
      <menuitem name="Nouveau" action="Nouveau"/>
      <menuitem name="Enregistrer" action="Enregistrer"/>
      <menuitem name="Quitter" action="Quitter"/>
    </menu>
    <menu name="Son" action="Son">
      <menuitem name="Volume" action="Volume"/>
      <menuitem name="Intensite" action="Intensité"/>
    </menu>
    <menu name="Modulation" action="Modulation">
      <menuitem name="MA" action="MA"/>
      <menuitem name="MF" action="MF"/>
      <menuitem name="BLU" action="BLU"/>
      <menuitem name="CB" action="CB"/>
      <menuitem name="OndesCourtes" action="OndesCourtes"/>
    </menu>
  </menubar>
  <toolbar name="BarreOutils">
    <tolite name="Nouveau" action="Nouveau"/>
    <tolite name="Enregistrer" action="Enregistrer"/>
    <tolite name="Quitter" action="Quitter"/>
    <separator/>
    <tolite name="Son" action="Son"/>
    <separator name="sep1"/>
    <placeholder name="ElementsMod">
      <tolite name="MA" action="MA"/>
      <tolite name="MF" action="MF"/>
      <tolite name="BLU" action="BLU"/>
      <tolite name="CB" action="CB"/>
      <tolite name="OndesCourtes" action="OndesCourtes"/>
    </placeholder>
    <separator/>
    <toolitem name="Intensite" action="Intensite"/>
    <separator/>
  </toolbar>

Si on examine le résultat XML, on peut constater que les éléments menuitem "Nouveau" et "Enregistrer" ont été incorporés avant l'élément "Quitter". Ceci est dû à la valeur "top" de l'attribut "position" qui signifie que l'élément doit être ajouté en tête. De la même manière, les éléments tolite "Nouveau" et "Enregistrer" ont été incorporés au début de la barre d'outils "BarreOutils". Il faut remarquer que les éléments "Nouveau" et "Enregistrer" ont été inversés par le processus de fusion.

L'élément tolite "Intensite" est ajouté aux autres éléments de la barre d'outils "BarreOutils" et apparait en dernière place dans la description fusionnée même s'il n'est pas le dernier de sa propre description. Dans les deux descriptions, l'élément placeholder "ElementsMod" mêle les éléments tolite "CB" et "OndesCourtes" avec les éléments "MA", "MF", et "BLU". Si on n'avait pas utilisé un élément placeholder "ElementsMod", les éléments "CB" et "OndesCourtes" se seraient retrouvés après l'élément "Intensite".

On peut obtenir une représentation de l'Interface Utilisateur utilisée par un UIManager par la méthode :

 
Sélectionnez
  uidesc = uimanager.get_ui()

Le programme uimerge.py illustre la fusion des descriptions précédentes UIManager. La Figure 16.14, « Exmple de fusion UIMerge » montre les Interfaces Utilisateurs séparés et fusionnés.

Image non disponible
Figure 16.14. Exemple de fusion UIMerge

Le programme exemple utilise trois objets ActionGroup :

  • des objets Action pour les menus "Fichier", "Son" et "Modulation" ;
  • des objets Action pour les menus "Quitter", "Son", "MA", "MF", "BLU" et "Modulation" 
  • des objets Action pour les éléments "Intensité", "CB" et "Ondes Courtes".

Les widgets de choix ToggleButton "Sensible" et "Visible" contrôlent la sensibilité et la visibilité du deuxième ActionGroup uniquement.

XVI-G-9. Signaux de l'Interface Utilisateur

L'UIManager possède une paire de signaux intéressants auxquels se connecter. Le signal "actions-changed" est émis lorsqu'un ActionGroup est ajouté ou retiré de l'UIManager. La fonction de rappel est :

 
Sélectionnez
  def fct_rappel(gestionui, ...)

Le signal "add-widget" est émis lorsqu'un widget délégué de Toolbar ou de MenuBar est créé. La fonction de rappel est :

 
Sélectionnez
  def fct_rappel(gestionui, widget, ...)

où le paramètre widget représente le nouveau widget créé.


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.