UIManager proporciona una manera de crear
menús y barras de herramientas a partir de una descripción similar a XML.
UIManager usa objetos ActionGroup
para gestionar los objetos Action que proporcionan la
estructura de control de los elementos del menú y la barra de
herramientas.
Al usar el gestor UIManager se pueden
introducir y eliminar dinámicamente múltiples acciones y descripciones de la
Interfaz de Usuario. Ello permite modificar los menús y las barras de
herramientas con los cambios de modo de la aplicación (por ejemplo, si cambia
de edición de texto a edición de imágenes), o en el caso de que se añadan
o eliminen características accesorias de la aplicación.
Se puede usar UIManager para crear los menús
y barras de herramientas de la interfaz de usuario de una aplicación
así:
UIManagerAccelGroup
del UIManager y se añade a la ventana de nivel
superiorActionGroup) y se rellenan pertinentemente con
instancias de acciones Action.ActionGroup
al UIManager en el orden en el que se desee que
aparezcan las instancias de acciones (Action).UIManager. Es necesario asegurarse de que todas las
acciones Action referenciadas por las descripciones
XML están disponibles en las instancias de los grupos
ActionGroup del
UIManager.ActionGroup).Las instancias de UIManager se crean con el
constructor:
uimamager = gtk.UIManager()
Los nuevos UIManager se crean con un grupo
de atajos (AccelGroup) asociado, que puede obtenerse
con el método:
accelgroup = uimanager.get_accel_group()
El grupo de atajos (AccelGroup) debería
añadirse a la ventana de nivel superior de la aplicación para que las
usuarias de la aplicación puedan usar los atajos de la
acción (Action). Por ejemplo:
window = gtk.Window() ... uimanager = gtk.UIManager() accelgroup = uimanager.get_accel_group() window.add_accel_group(accelgroup)
Tal como se describe en Sección 16.1.2, “Grupos de Acciones (ActionGroups)”,
los grupos de acciones ActionGroups pueden llenarse
con acciones (Actions) utilizando los métodos
auxiliares add_actions(),
add_toggle_actions() y
add_radio_actions(). Los grupos de acciones
(ActionGroup) se pueden usar desde un gestor
UIManager una vez que han sido añadidos a su lista de
grupo de acciones (ActionGroup) con el método:
uimanager.insert_action_group(action_group,pos)
donde pos es el índice de la posición en la
que debería insertarse action_group. Un gestor de
interfaces UIManager puede contener varios grupos de
acciones (ActionGroups) con nombres de acciones
(Action) repetidos. Por ello es importante el orden
de los objetos ActionGroup, puesto que la búsqueda
de una acción (Action) finaliza cuando se encuentra
la primera acción (Action) con el nombre dado. Ello
implica que las acciones que están en objetos
ActionGroup que están situados antes ocultan a los
que están colocados después.
Las acciones referenciadas en una descripción XML de la interfaz de
usuario deben añadirse al UIManager antes que la
propia descripción.
Se puede eliminar un grupo de acciones
ActionGroup de un gestor de interfaz de usuario
UIManager con el método:
uimanager.remove_action_group(action_group)
Se puede obtener la lista de los objetos
ActionGroup asociados con un determinado
UIManager con el método:
actiongrouplist = uimanager.get_action_groups()
Las descripciones de la Interfaz de Usuario aceptadas por
UIManager son simples definiciones XML con los
siguientes elementos:
ui | El elemento raíz de una descripción de una Interfaz de Usuario. Se puede omitir. Puede contener elementos menubar, popup, toolbar y accelerator. |
menubar | Elemento de nivel superior que describe una estructura de
barra de menú (MenuBar) y puede contener elementos
MenuItem,
separator,
placeholder y menu. Tiene un atributo opcional
name (nombre) que, si se omite,
toma el valor "menubar". |
popup | Elemento de nivel superior que describe una estructura de
menú emergente (Menu) y que puede contener elementos
menuitem,
separator,
placeholder, y menu. Tiene un atributo opcional
name (nombre) que, si se omite,
toma el valor "popup". |
toolbar | Elemento de nivel superior que describe una estructura de
barra de herramientas (Toolbar) y que puede contener
otros elementos toolitem,
separator
y placeholder. Posee un atributo opcional
name (nombre) que, si se omite, toma el valor
"toolbar". |
placeholder | Elemento que identifica una posición dentro de un menubar, toolbar, popup o menu. Este elemento puede contener otros elementos menuitem, separator, placeholder, y menu. Los elementos Placeholder se usan al incorporar descripciones de Interfaz de Usuario para permitir, por ejemplo, la construcción de un menú a partir de descripciones de Interfaz de usuario utilizando nombres de contenedores placeholder compartidos. Posee un atributo opcional name (nombre), que, si se omite, toma el valor "placeholder". |
menu | Elemento que describe una estructura de menú
Menu y puede contener otros elementos
menuitem,
separator, placeholder y menu. Un elemento menu tiene un atributo obligatorio
action que denomina un objeto de acción
Action que se usará en la creación del
Menu. Opcionalmente puede incluir los atributos
name (nombre) y position (posición).
Si no se especifica name se usa el valor correspondiente
al elemento action como nombre. El atributo
position puede tomar el valor "top" (superior) o
"bottom" (inferior), usándose éste último si no se
especifica position. |
menuitem | Elemento que escribe un elemento de menú
MenuItem. El elemento
menuitem posee un atributo obligatorio
action que denomina un objeto de acción
Action que se usa para crear el elemento de menú
MenuItem. También posee los atributos optativos
name (nombre) y position (posición).
Si no se indica name entonces se usa el nombre
correspondiente al elemento action. El atributo
position puede tomar el valor "top" (superior) o
el valor "bottom" (inferior), usándose éste último si no se especifica
position. |
toolitem | Elemento que describe un elemento de barra de herramientas
ToolItem. El elemento
toolitem posee un atributo obligatorio
action que denomina un objeto de acción
Action que se usa para crear la barra de herramientas
Toolbar. También posse los atributos optativos
name (nombre) y position (posición).
Si no se indica name entonces se usa el nombre
correspondiente al elemento action. El atributo
position puede tomar el valor "top" (superior) o
el valor "bottom" (inferior), usándose éste último si no se especifica
position. |
separator | Elemento que describe un separador de elemento de menú
SeparatorMenuItem o un separador de elemento de barra
de herramientas SeparatorToolItem según
corresponda. |
accelerator | Elemento que describe un atajo de teclado (acelerador). El
elemento accelerator posee un atributo
obligatorio action que denomina un objeto de acción
Action que define la combinación de teclas del atajo y
que se activa con el atajo. También tiene un atributo opcional de nombre
name. Si no se especifica name se
usa el nombre de action como nombre. |
Como ejemplo, una descripción de Interfaz de Usuario que se podría usar para la creación de una interfaz similar a la de Figura 16.4, “Ejemplo de ActionGroup” es:
<ui>
<menubar name="MenuBar">
<menu action="File">
<menuitem action="Quit"/>
</menu>
<menu action="Sound">
<menuitem action="Mute"/>
</menu>
<menu action="RadioBand">
<menuitem action="AM"/>
<menuitem action="FM"/>
<menuitem action="SSB"/>
</menu>
</menubar>
<toolbar name="Toolbar">
<toolitem action="Quit"/>
<separator/>
<toolitem action="Mute"/>
<separator name="sep1"/>
<placeholder name="RadioBandItems">
<toolitem action="AM"/>
<toolitem action="FM"/>
<toolitem action="SSB"/>
</placeholder>
</toolbar>
</ui>
Obsérvese que esta descripción simplemente usa los nombres de los elementos action como nombres de la mayoría de los elementos, en lugar de especificar sus atributos name. También es desaconsejable el uso del elemento ui puesto que parece innecesario.
La jerarquía de objetos que se crea al usar una descripción de Interfaz de Usuario es muy parecida a la jerarquía de elementos XML exceptuando que los elementos contenedores placeholder se introducen en sus elementos padre.
Se puede acceder a un control de la jerarquía creada por una descripción de Interfaz de Usuario mediante su ruta, que se compone del nombre del elemento de control y sus elementos anteriores separados por barras inclinadas ("/"). Por ejemplo, si se usa la descripción anterior, estas serían rutas válidas de algunos controles:
/MenuBar /MenuBar/File/Quit /MenuBar/RadioBand/SSB /Toolbar/Mute /Toolbar/RadioBandItems/FM
Hay que observar que el nombre de los contenedores placeholder deben incluirse en la ruta. Generalmente simplemente se accederá a los controles de nivel superior (por ejemplo, "/MenuBar" y "/Toolbar") pero es posible que sea necesario acceder a otros controles de nivel inferior para, por ejemplo, cambiar una propiedad.
Una vez que se configura un gestor de Interfaz de Usuario
UIManager con un grupo de acciones
ActionGroup entonces es posible añadir una
descripción de Interfaz de Usuario e integrarla con la interfaz existente
mediante los siguientes métodos:
merge_id = uimanager.add_ui_from_string(buffer) merge_id = uimanager.add_ui_from_file(filename)
donde buffer es una cadena que contiene una
descripción de Interfaz de Usuario y filename es el
archivo que contiene una descripción de Interfaz de Usuario. Ambos métodos
devuelven un identificador merge_id que consiste en un
valor entero único. Si falla el método se emite la excepción
GError. El identificador merge_id
puede usarse para eliminar la descripción de Interfaz de Usuario del gestor
UIManager con el método:
uimanager.remove_ui(merge_id)
Los mismos métodos se pueden usar más de una vez para añadir descripciones adicionales, que se incorporarán para obtener una descripción XML de Interfaz de Usuario combinada. Se hablará más de las Interfaces de Usuario combinadas de forma más detallada en la sección Sección 16.7.8, “Combinación de Descripciones de Interfaz de Usuario”.
Se puede añadir un elemento sencillo de Interfaz de Usuario a la descripción existente con el método:
uimanager.add_ui(merge_id,path,name,action,type,top)
donde merge_id es un valor entero único,
path es la ruta donde se añadirá el nuevo elemento,
action es el nombre de una acción
Action o None para añadir un elemento
separator, type es el
tipo de elemento que se ha de añadir y top (superior)
es un valor booleano. Si top es TRUE
el elemento se añadirá antes que sus elementos hermanos, y después en caso contrario.
merge_id se obtendría con el método:
merge_id = uimanager.new_merge_id()
Los valores enteros devueltos por el método
new_merge_id() son monótonamente crecientes.
path (ruta) es una cadena compuesta por el
nombre del elemento y los nombres de sus ancestros unidos por una barra
inclinada ("/") pero sin incluir el nudo optativo raíz "/ui". Por ejemplo,
"/MenuBar/RadioBand" es la ruta del elemento menu llamado "RadioBand" de la siguiente descripción
de Interfaz de Usuario:
<menubar name="MenuBar">
<menu action="RadioBand">
</menu>
</menubar>
El valor de type (tipo) debe ser uno de los
siguientes:
| El tipo del elemento de Interfaz de Usuario (menuitem, toolitem o separator) se establece en función del contexto. |
| Una barra de menú. |
| Un menú. |
| Una barra de herramientas. |
| Un contenedor (placeholder). |
| Un menú emergente. |
| Un elemento de menú. |
| Un elemento de barra de herramientas. |
| Un separador. |
| Un atajo o acelerador. |
add_ui() falla sin aviso si el elemento no
es añadido. El uso de add_ui() es de un nivel tan bajo
que se deberían usar siempre en su lugar los métodos auxiliares
add_ui_from_string() y
add_ui_from_file().
La adición de un elemento o una descripción de Interfaz de Usuario provoca la actualización de la jerarquía de controles en una función ociosa (idle). Se puede asegurar que la jerarquía de controles se ha actualizado antes de acceder a ella utilizando el método:
uimanager.ensure_update()
Se accede a un control de la jerarquía de controles de la Interfaz de Usuario mediante el método:
widget = uimanager.get_widget(path)
donde path (ruta) es una cadena que contiene
el nombre del elemento control y sus ancestros de la forma que se describe en
Sección 16.7.4, “Descripciones de la Interfaz de Usuario”.
Por ejemplo, dada la siguiente descripción de Interfaz de Usuario:
<menubar name="MenuBar">
<menu action="File">
<menuitem action="Quit"/>
</menu>
<menu action="Sound">
<menuitem action="Mute"/>
</menu>
<menu action="RadioBand">
<menuitem action="AM"/>
<menuitem action="FM"/>
<menuitem action="SSB"/>
</menu>
</menubar>
<toolbar name="Toolbar">
<toolitem action="Quit"/>
<separator/>
<toolitem action="Mute"/>
<separator name="sep1"/>
<placeholder name="RadioBandItems">
<toolitem action="AM"/>
<toolitem action="FM"/>
<toolitem action="SSB"/>
</placeholder>
</toolbar>
que haya sido añadida al gestor UIManager
uimanager, es posible acceder a la barra de menús
(MenuBar) y barra de herramientas
(Toolbar) para su uso en una ventana de aplicación
(Window) utilizando el código que sigue:
window = gtk.Window()
vbox = gtk.VBox()
menubar = uimanager.get_widget('/MenuBar')
toolbar = uimanager.get_widget('/Toolbar')
vbox.pack_start(meunbar, False)
vbox.pack_start(toolbar, False)
De la misma forma, se accede a los controles de los niveles
inferiores mediante sus rutas. Por ejemplo, se accede al elemento de la clase
RadioToolButton llamado "SSB" así:
ssb = uimanager.get_widget('/Toolbar/RadioBandItems/SSB')
Para facilitar las cosas, se pueden obtener todos los controles de nivel superior de un determinado tipo mediante el método:
toplevels = uimanager.get_toplevels(type)
donde type especifica el tipo de los
controles que se devolverán usando una combinación de las banderas:
gtk.UI_MANAGER_MENUBAR,
gtk.UI_MANAGER_TOOLBAR y
gtk.UI_MANAGER_POPUP. Se puede usar el método
gtk.Widget.get_name() para determinar qué control
de nivel superior se tiene.
Se puede obtener la acción Action que usa
el control auxiliar asociado con un elemento de Interfaz de Usuario usando
el método:
action = uimanager_get_action(path)
donde path (ruta) es una cadena que contiene
la ruta a un elemento de la Interfaz de Usuario de
uimanager. Si el elemento no posee una acción
Action asociada entonces se devuelve
None.
uimanager.py es un
ejemplo sencillo de programa que ilustra el uso de un gestor de interfaz de
usuario UIManager. Figura 16.13, “Programa sencillo de Gestor de Interfaz de Usuario
UIManager” muestra el programa en funcionamiento.
El programa de ejemplo
uimanager.py usa la descripción
XML de Sección 16.7.6, “Acceso a los Controles de la Interfaz de Usuario”. El texto de las dos
etiquetas se cambian como respuesta a la activación de la acción biestado
(ToggleAction) "Mute" y de las acciones de exclusión
mútua (RadioAction) "AM", "FM" and "SSB". Todas las
acciones están contenidas en un único grupo de acciones
(ActionGroup) que permite que se pueda conmutar la
sensibilidad y visibilidad de todos los controles auxiliares de las acciones
mediante los botones biestado "Sensitive" y "Visible". El uso del elemento
contenedor placeholder se describe
posteriormente en Sección 16.7.8, “Combinación de Descripciones de Interfaz de Usuario”.
La combinación de descripciones de Interfaz de Usuario se hace en función del nombre de los elementos XML. Tal como se indicó más arriba, los elementos individuales de la jerarquía pueden ser accedidos usando un nombre de ruta que está formado por el nombre del elemento y los nombres de sus ancestros. Por ejemplo, si usamos la descripción de Interfaz de Usuario de Sección 16.7.4, “Descripciones de la Interfaz de Usuario”, el elemento toolitem "AM" tiene la ruta "/Toolbar/RadioBandItems/AM" mientras que el elemento menuitem "FM" tiene la ruta "/MenuBar/RadioBand/FM".
Si se combina una descripción de Interfaz de Usuario con esa descripción de Interfaz entonces sus elementos se añaden como elementos del mismo nivel que los elementos existentes. Por ejemplo, si la descripción de Interfaz de Usuario:
<menubar name="MenuBar">
<menu action="File">
<menuitem action="Save" position="top"/>
<menuitem action="New" position="top"/>
</menu>
<menu action="Sound">
<menuitem action="Loudness"/>
</menu>
<menu action="RadioBand">
<menuitem action="CB"/>
<menuitem action="Shortwave"/>
</menu>
</menubar>
<toolbar name="Toolbar">
<toolitem action="Save" position="top"/>
<toolitem action="New" position="top"/>
<separator/>
<toolitem action="Loudness"/>
<separator/>
<placeholder name="RadioBandItems">
<toolitem action="CB"/>
<toolitem action="Shortwave"/>
</placeholder>
</toolbar>
se añade a nuestra descripción de Interfaz de Usuario de ejemplo:
<menubar name="MenuBar">
<menu action="File">
<menuitem action="Quit"/>
</menu>
<menu action="Sound">
<menuitem action="Mute"/>
</menu>
<menu action="RadioBand">
<menuitem action="AM"/>
<menuitem action="FM"/>
<menuitem action="SSB"/>
</menu>
</menubar>
<toolbar name="Toolbar">
<toolitem action="Quit"/>
<separator/>
<toolitem action="Mute"/>
<separator name="sep1"/>
<placeholder name="RadioBandItems">
<toolitem action="AM"/>
<toolitem action="FM"/>
<toolitem action="SSB"/>
</placeholder>
</toolbar>
se crearía la siguiente descripción de Interfaz de Usuario combinada:
<menubar name="MenuBar">
<menu name="File" action="File">
<menuitem name="New" action="New"/>
<menuitem name="Save" action="Save"/>
<menuitem name="Quit" action="Quit"/>
</menu>
<menu name="Sound" action="Sound">
<menuitem name="Mute" action="Mute"/>
<menuitem name="Loudness" action="Loudness"/>
</menu>
<menu name="RadioBand" action="RadioBand">
<menuitem name="AM" action="AM"/>
<menuitem name="FM" action="FM"/>
<menuitem name="SSB" action="SSB"/>
<menuitem name="CB" action="CB"/>
<menuitem name="Shortwave" action="Shortwave"/>
</menu>
</menubar>
<toolbar name="Toolbar">
<toolitem name="New" action="New"/>
<toolitem name="Save" action="Save"/>
<toolitem name="Quit" action="Quit"/>
<separator/>
<toolitem name="Mute" action="Mute"/>
<separator name="sep1"/>
<placeholder name="RadioBandItems">
<toolitem name="AM" action="AM"/>
<toolitem name="FM" action="FM"/>
<toolitem name="SSB" action="SSB"/>
<toolitem name="CB" action="CB"/>
<toolitem name="Shortwave" action="Shortwave"/>
</placeholder>
<separator/>
<toolitem name="Loudness" action="Loudness"/>
<separator/>
</toolbar>
Si se examina el XML resultante se puede ver que los elemnentos menuitem "New" y "Save" se han combinado antes que el elemento "Quit" como resultado de haber fijado el atributo "position" a "top", que significa que el elemento debe ser antepuesto. De la misma forma, los elementos toolitem "New" y "Save" se han antepuesto a "Toolbar". Obsérvese que los elementos "New" y "Save" son invertidos en el proceso de combinación.
El elemento toolitem "Loudness" se añade tras los elementos "Toolbar" y aparece el último en la descripción combinada de la Interfaz de Usuario, aunque no sea así en su propia descripción de Interfaz de Usuario. El elemento placeholder "RadioBandItems" en ambas Interfaces de Usuario combina los elementos toolitem "CB" y "Shortwave" con los elementos "AM", "FM", and "SSB". Si no se hubiese usado el elemento placeholder "RadioBandItems" entonces los elementos "CB" y "Shortwave" se habrían situado tras el elemento "Loudness".
Se puede obtener una representación de la descripción de Interfaz
de Usuario utilizada por un gestor UIManager
con el método:
uidesc = uimanager.get_ui()
El programa de ejemplo uimerge.py muestra la combinación de las descripciones de Interfaz de Usuario anteriores. Figura 16.14, “Ejemplo UIMerge” ilustra la Interfaz original y la combinada:
El programa de ejemplo usa tres objetos
ActionGroup:
Action para los menús
"File", "Sound" y "Radio Band"Action para los menús "Quit",
"Mute", "AM", "FM", "SSB" y "Radio Band"Action para los elementos
"Loudness", "CB" y "Shortwave"Los controles de botón biestado (ToggleButton)
"Sensitive" y Visible" controlan la sensibilidad y visibilidad de únicamente
el segundo grupo de acciones (ActionGroup).
UIManager posee una par de señales
interesantes a las que se puede conectar una aplicación. La señal
"actions-changed" se emite cuando se añade o elimina un grupo de acciones
ActionGroup de un gestor
UIManager. La signatura de la retrollamada es:
def callback(uimanager, ...)
La señal "add-widget" se emite cuando se crea un control auxiliar
MenuBar o Toolbar. La
signatura de la retrollamada es:
def callback(uimanager,widget, ...)
donde widget es el control recién
creado.