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 du
Action
fournissant une infrastructure commune
aux éléments de menu et de barre d'outils.
L'utilisation du UIManager
permet de fusionner et
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 :
UIManager
.AccelGroup
du
UIManager
et l'ajouter à la Fenêtre
de niveau supérieur.ActionGroup
et
les remplir avec les Action
voulues.
instances.ActionGroup
au UIManager
dans l'ordre dans lequel on souhaite
présenter les instances des Action
.UIManager
. Il faut s'assurer que toutes les
Actions
définies par les descriptions soient
disponibles dans les instances ActionGroup
du
UIManager
.ActionGroup
.Une instance de 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 Action
puissent être disponibles pour les utilisateurs.
Par exemple :
fenetre = gtk.Window() ... gestionui = gtk.UIManager() grouperacc = gestionui.get_accel_group() fenetre.add_accel_group(accelgroup)
Comme on l'a vu dans la Section 16.1.2, « 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
lorqu'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ù le 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 le 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 au UIManager
peut être récupérée
par la méthode :
listegroupesactions = gestionui.get_action_groups()
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 decription 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
toolitem, 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".
|
toolitem | Décrit un élémént de barre d'outils ToolItem . Un
élément toolitem 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
acceleratorpossè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 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 » :
<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"> <toolitem action="Quitter"/> <separator/> <toolitem action="Volume"/> <separator/> <placeholder name="ElementsMod"> <toolitem action="MA"/> <toolitem action="MF"/> <toolitem 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 recommenderais 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 :
/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" and "/Toolbar") mais on peut avoir besoin d'accèder à un widget de plus bas niveau pour, par exemple, modifier une propriété.
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 :
fusion_id = gestionui.add_ui_from_string(buffer
) fusion_id = gestionui.add_ui_from_file(filename
)
... où le paramètre buffer
est une chaîne
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 ».
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 chaîne 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 noeud 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 :
<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élerateur. |
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()
On peut avoir accès à un widget dans la hiérarchie de l'Interface Utilisateur en utilsant la méthode :
widget = gestionui.get_widget(path
)
... où le paramètre path
est une chaîne 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 ».
Par exemple, étant donné la description d'Interface Utilisateur suivante :
<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"> <toolitem action="Quitter"/> <separator/> <toolitem action="Volume"/> <separator name="sep1"/> <placeholder name="ElementsMod"> <toolitem action="MA"/> <toolitem action="MF"/> <toolitem 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 :
fenetre = 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 le Action
utilisé 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 chaîne
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.
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'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écrit en détail
dans la Section 16.7.8, « Combiner des descriptions d'Interface Utilisateur ».
La fusion de plusieurs descriptions d'Interface Utilisateur se réalise en fonctio du nom des éléments XML. Comme on l'a 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 », l'élément toolitem "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 :
<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"> <toolitem action="Enregistrer" position="top"/> <toolitem action="Nouveau" position="top"/> <separator/> <toolitem action="Intensite"/> <separator/> <placeholder name="ElementsMod"> <toolitem action="CB"/> <toolitem action="OndesCourtes"/> </placeholder> </toolbar>
... est ajoutée à notre exemple précédent :
<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"> <toolitem action="Quitter"/> <separator/> <toolitem action="Volume"/> <separator name="sep1"/> <placeholder name="ElementsMod"> <toolitem action="MA"/> <toolitem action="MF"/> <toolitem action="BLU"/> </placeholder> </toolbar>
Le résultat final créé sera :
<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"> <toolitem name="Nouveau" action="Nouveau"/> <toolitem name="Enregistrer" action="Enregistrer"/> <toolitem name="Quitter" action="Quitter"/> <separator/> <toolitem name="Son" action="Son"/> <separator name="sep1"/> <placeholder name="ElementsMod"> <toolitem name="MA" action="MA"/> <toolitem name="MF" action="MF"/> <toolitem name="BLU" action="BLU"/> <toolitem name="CB" action="CB"/> <toolitem 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 toolitem "Nouveau" et "Enregistrer" ont été incorporés au début de la barre d'outils "BarreOutils". Il faut remarque que les éléments "Nouveau" et "Enregistrer" ont été inversés par le processus de fusion.
L'élément toolitem "Intensite" est ajouté aux autres éléments de la barre d'outils "BarreOutils" et apparaît 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 toolitem "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 description 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
:
Action
pour les menus "Fichier",
"Son" et "Modulation"Action
pour les menus "Quitter",
"Son", "MA", "MF", "BLU" et "Modulation"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.
Le 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é du
UIManager
. La fonction de rappel est :
def fct_rappel(gestionui
, ...)
Le signal "add-widget" est émis lorsqu'un widget délégue 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éé.