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 :
action =
gtk.Action
(
name, label, tooltip, stock_id)
où 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 :
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 :
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 :
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
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 :
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 :
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.
Un widget délégué peut être déconnecté d'une Action par la méthode :
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 :
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 :
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) :
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 :
toggleaction =
gtk.ToggleAction
(
name, label, tooltip, stock_id)
En supplément des méthodes pour Action, les méthodes suivantes pour ToggleAction :
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 :
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 :
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 :
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 :
radioaction =
gtk.RadioAction
(
name, label, tooltip, stock_id, value)
Le groupe d'un RadioAction peut être créé par la méthode :
radioaction.set_group
(
group)
où group est un autre RadioAction auquel doit se rattacher le radioaction. Le groupe contenant un RadioAction peut être obtenu par la méthode :
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 :
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 :
def
changed_cb
(
radioaction, current, user_data)
où 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 :
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 :
actiongroup =
gtk.ActionGroup
(
name)
où 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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
2.
3.
4.
boitederoul.append_text
(
text)
boitederoul.prepend_text
(
text)
boitederoul.insert_text
(
position, text)
boitederoul.remove_text
(
position)
où 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 :
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 à :
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 :
est_actif =
boitederoul.get_active
(
)
L'élément actif peut être défini par la méthode :
boitederoul.set_active
(
index)
où 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 :
def
fct_rappel_change
(
combobox, ...):
où ... 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 :
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 :
combobox =
gtk.ComboBox
(
model=
None
)
où 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 :
boitederoul.set_model
(
model)
Le TreeModel associé peut être récupéré par la méthode :
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 :
boitederoul.set_wrap_width
(
width)
où 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 :
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.
for
n in
range(
150
):
Lancer le programme pour obtenir une estimation du temps d'initialisation. Puis le modifier en commentant la ligne 17 :
#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 :
iter =
boitederoul.get_active_iter
(
)
On peut aussi établir l'élément de liste actif en utilisant un TreeIter avec la méthode :
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 :
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 :
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 :
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() :
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 :
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.
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 :
boitderoulsaisie =
gtk.ComboBoxEntry
(
model=
None
, column=-
1
)
où 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 à :
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 :
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 :
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 :
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 :
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) :
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 :
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 :
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.
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 :
boutonpolice =
gtk.FontButton
(
nompolice=
None
)
où 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 :
2.
3.
resultat =
boutonpolice.set_font_name
(
nompolice)
nompolice =
boutonpolice.get_font_name
(
)
où 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 :
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" :
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 :
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 :
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.
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 :
completion =
gtk.EntryCompletion
(
)
On peut utiliser la méthode set_completion() du champ de saisie Entry pour associer le EntryCompletion au Entry :
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 :
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 :
completion.set_text_column
(
column)
Cette méthode est équivalente à :
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 :
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.
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 :
completion.set_match_func
(
func, user_data)
La fonction func est :
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.
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 :
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 :
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 :
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 :
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" :
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 :
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 :
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.
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
chooser.add_shortcut_folder
(
folder)
chooser.remove_shortcut_folder
(
folder)
où 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.
Voici le code source du programme filechooser.py :
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 :
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 :
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 :
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 :
gestionui.insert_action_group
(
action_group, pos)
où 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 :
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 :
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 » :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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 :
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.
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 :
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 :
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 :
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 :
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.
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 :
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 :
def
fct_rappel
(
gestionui, widget, ...)
où le paramètre widget représente le nouveau widget créé.