Menús y barra de herramientas dinámicas en PyGTK

gtkPython

Desde hace algunas versiones, GTK incorpora la capacidad para crear menús, barras de herramientas y menús desplegables (alias menú popup) a través de descripciones textuales similares a XML.

Esta funcionalidad de GTK nos la proporcionan, en principio, la utilización conjunta de tres clases: por un lado UIManager, que es quien tiene la descripción XML de la interfaz y quien, en caso de necesitarlos, nos proporciona los widgets que añadiremos a nuestra interfaz; por otro lado están ActionGroup y Action.

Estas dos últimas son las que representan los elementos de los menús. Podemos tener varios ActionGroup s que podemos asociar al UIManager. Las Action s son añadidas a cada ActionGroup. Cada elemento de la descripción XML del UIManager tiene que tener su Action asociada u obtendremos un precioso warning de GTK.

Al principio todo puede parecer un poco lioso… Así que voy a poner un breve ejemplo de como usar todo esto.

Usando UIManager y Action s (ActionGroup): primeros pasos

Lo primero es ver un ejemplo de descripción de interfaz muy sencillo:

ui = ‘’‘<ui>
  <menubar name="MenuBar">
    <menu action="Menu1">
      <menuitem action="Button1"/>
    </menu>
    <menu action="Menu2">
      <menuitem action="Button2"/>
    </menu>
  </menubar>
  <toolbar name="Toolbar">
    <toolitem action="Button1"/>
    <separator/>
    <toolitem action="Button3"/>
  </toolbar>
</ui>
‘‘’

En este ejemplo se observa lo siguiente:

  1. Todo está en un entorno
  2. Hay dos partes diferenciadas: la “Menubar” y la “Toolbar”.
  3. Dentro de la “Menubar” tenemos menús, y dentro de estos, menuitem s. En nuestro caso, dos menús con una acción cada uno.
  4. Dentro de la “Toolbar” sin embargo tenemos solamente toolitem s. También hay “separator” s, que me imagino que supones que puede ser… En nuestro caso tenemos dos elementos en el Toolbar

Necesitaremos obviamente un UIManager, y asociarle a éste la descripción:

uimanager = gtk.UIManager()
uimanager.add_ui_from_string(self.ui)

La otra parte de este bonito juego es la que tiene que ver con las Action s. Para añadirlas, crearemos un ActionGroup y a éste le añadiremos Action s.

Lo primero es tan sencillo como lo siguiente:

actiongroup = gtk.ActionGroup(‘UIManagerExample’) # create the actiongroup

Para añadir a este ActionGroup las Action s tenemos multitud de métodos, que nos añadirán un Action de forma individual, varios a la vez o de alguno de los tipos predefinidos en lugar de Action s vulgares y corrientes. Se pueden añadir de cualquiera de las formas, el resultado es el mismo. Lo que debemos tener en cuenta es que, bien en el constructor, bien en el primer elemento de la tupla en la que se describen las acciones al añadir varias, debe ponerse el nombre de la acción con el que la hemos identificado en la descripción XML anterior. De esa forma, cuando añadas el ActionGroup al UIManager, éste será capaz de encontrar la acción asociada para una determinada entrada.

Observa como se añaden las acciones de varias formas:

actiongroup.add_action(gtk.Action(‘Button1’, ‘Button one’, ‘First button’, gtk.STOCK_OK))
actiongroup.add_actions([
     (‘Menu1’, None, ‘Menu one’, None, ‘First menu’, None),
     (‘Menu2’, None, ‘Menu two’, None, ‘Second menu’, None), 
     (‘Button2’, gtk.STOCK_QUIT, ‘Button two’, None, ‘Second button’, self.button2_cb),
     (‘Button3’, gtk.STOCK_OPEN, ‘Button three’, None, ‘Third button’, self.button3_cb),
 ])

En la primera instrucción añadimos una sola acción y, el argumento de la función por tanto es un gtk.Action. Los argumentos son el nombre (identificador por el que se buscará en UIManager la acción), el texto que mostrará el renderizado de la acción. El tercer argumento será el tooltip y, por último, el icono de stock que se usará. si queremos conectar nuestra acción con una función, deberíamos tener la Action en una variable y conectar la señal “activate” a un callback.

En la segunda, sin embargo, se añaden varias acciones (el argumento único es una lista), y las acciones, en lugar de estar especificadas como en la llamada anterior, se especifica mediante una tupla que tiene, en este orden, el nombre, el icono de stock, la etiqueta que se mostrará, un acelerador (para otra receta), el tooltip y, por último, una función callback que se invocará cuando pulsemos en la acción.

Solamente nos falta añadir el ActionGroup” al *UIManager:

uimanager.insert_action_group(actiongroup, 0)

Poniendo todo junto

Para que todo este invento sirva de algo tenemos que pintar todos los widgets que el UIManager es capaz de generar en algún sitio. Lo más fácil, útil y obvio es tener una ventana de GTK con un VBox y añadirle tanto el Menubar como el Toolbar en la parte superior.

menubar = uimanager.get_widget(‘/MenuBar’)
vbox.pack_start(menubar, False)
 
toolbar = uimanager.get_widget(‘/Toolbar’)
vbox.pack_start(toolbar, False)

Dejo un ejemplo completo y funcional del resultado como adjunto (perdonad que la extensión sea .txt, pero Drupal no deja subir, por seguridad, scripts Python)

Referencias

(La documentación de PyGTK no está on-line en estos momentos. Me comprometo a hacer una buena recopilación de referencia de las clases, del FAQ y el tutorial de PyGTK sobre este tema)

AdjuntoTamaño
uimanager.py2.56 KB

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de shakaran

Corrección

Muy buen artículo. En mi opinión sería mas correcto el título como "Menús y barra de herramientas dinámicas en PyGTK" ya que utilizas el binding de python para GTK, sino estaríamos hablando de hacerlo con C. También estaría bien poner algunas capturas de los ejemplos del código (así te haces una idea del resultado). Me encanta Python y su facilidad para hacer interfaces Eye-wink

Today is a good day. Would you be tomorrow?

Imagen de Lk2

Llevas razón

Lo de ilustrarlo con imágenes lo tomaré con tiempo, porque quiero escribir otro post con algunas cosas un poquito más complejos sobre el mismo tema... pero lo del título llevas toda la razón

Imagen de shakaran

Sin prisas, pero sin pausa

Tranquilo, no hay prisas Eye-wink Lo que cuenta es compartir conocimientos. Estaré atento a próximos artículos de PyGTK, estoy metido en el tema y me gusta bastante. Saludos

Today is a good day. Would you be tomorrow?