# MenuBar (Python)

Tiffany Antopolski
tiffany.antopolski@gmail.com 2012
Marta Maria Casetti
mmcasetti@gmail.com 2012
Un widget que contiene widgets «GtkMenuItem»
Daniel Mustieles
daniel.mustieles@gmail.com 2011 - 2020
Nicolás Satragno
nsatragno@gmail.com 2012 - 2013
Jorge González
jorgegonz@svn.gnome.org 2011

# Una barra de menú creada usando XML y GtkBuilder.

Una barra de menú usando XML y GtkBuilder.

# Crear una barra de menú usando XML

Para crear la barra de menú usando XML:

Cree menubar.ui usando su editor de texto favorito.

Añada la siguiente línea en la parte superior del archivo:

<?xml version="1.0"? encoding="UTF-8"?>

Se quiere crear la interfaz que contendrá la barra de menú y sus submenús. Su barra de menú contendrá los submenús File, Edit, Choices y Help. Se le añade el siguiente código XML al archivo:

<?xml version="1.0" encoding="UTF-8"?> <interface> <menu id="menubar"> <submenu> <attribute name="label">File</attribute> </submenu> <submenu> <attribute name="label">Edit</attribute> </submenu> <submenu> <attribute name="label">Choices</attribute> </submenu> <submenu> <attribute name="label">Help</attribute> </submenu> </menu> </interface>

Ahora se crea el archivo .py y se usa «GtkBuilder» para importar el menubar.ui que acaba de crear.

# Añadir la barra de menú a la ventana usando «GtkBuilder»

from gi.repository import Gtk import sys

class MyWindow(Gtk.ApplicationWindow):

def __init__(self, app): Gtk.Window.__init__(self, title="MenuBar Example", application=app) self.set_default_size(200, 200)

class MyApplication(Gtk.Application):

def __init__(self): Gtk.Application.__init__(self)

def do_activate(self): win = MyWindow(self) win.show_all()

def do_startup(self): Gtk.Application.do_startup(self)

# a builder to add the UI designed with Glade to the grid: builder = Gtk.Builder() # get the file (if it is there) try: builder.add_from_file("menubar_basis.ui") except: print("file not found") sys.exit()

# we use the method Gtk.Application.set_menubar(menubar) to add the menubar # to the application (Note: NOT the window!) self.set_menubar(builder.get_object("menubar"))

app = MyApplication() exit_status = app.run(sys.argv) sys.exit(exit_status)

Ahora ejecute la aplicación de Python. Se debería ver como la imagen en la parte superior de esta página.

# Añadir elementos a los menús

Se empieza añadiendo 2 elementos al menú File: New y Quit. Esto se hace añadiéndole una `section` al submenú `File` con estos elementos. El menubar.ui debe verse así (líneas 6 a 13 inclusive conforman la sección nueva):

## menubar.ui

<?xml version="1.0" encoding="UTF-8"?> <interface> <menu id="menubar"> <submenu> <attribute name="label">File</attribute> <section> <item> <attribute name="label">New</attribute> </item> <item> <attribute name ="label">Quit</attribute> </item> </section> </submenu> <submenu> <attribute name="label">Edit</attribute> </submenu> <submenu> <attribute name="label">Choices</attribute> </submenu> <submenu> <attribute name="label">Help</attribute> </submenu> </menu> </interface>

De esta misma manera puede añadirle un elemento `Copy` y uno `Paste` al submenú `Edit`, y un elemento `About` al submenú `Help`.

# Configurar las acciones

Ahora se crean las acciones para «New» y «Quit», conectadas a una función de retorno de llamada en el archivo de Python; por ejemplo se crea «new» así:

new_action = Gio.SimpleAction.new("new", None) new_action.connect("activate", self.new_callback)

Y se crea la función de retorno de llamada de «new» como

def new_callback(self, action, parameter): print "You clicked \"New\""

Ahora, en el archivo XML, se conectan los elementos del menú a las acciones en el archivo XML añadiendo el atributo «action»:

<item> <attribute name="label">New</attribute> <attribute name="action">app.new</attribute> </item>

Tenga en cuenta que para una acción relativa a la aplicación, se usa el prefijo `app.`; para acciones relativas a la ventana, se usa el prefijo `win.`.

Finalmente, en el archivo de Python, se añade la acción a la aplicación o a la ventana: por ejemplo `app.new` se añadirá a la aplicación en el método `do_startup(self)` así:

self.add_action(new_action)

Consulte la sección para obtener una explicación más detallada sobre señales y retornos de llamada.

# Acciones: ¿aplicación o ventana?

Anteriormente, se crearon las acciones «new» y «open» como parte de la clase «MyApplication». Las acciones que controlan la aplicación en sí, como «quit» deben crearse de manera similar.

Algunas acciones, como «copy» y «paste» trabajan con la ventana, no con la aplicación. Las acciones de ventanas deben crearse como parte de la clase de la ventana.

Los archivos de ejemplo completos contienen tanto acciones de aplicación como de ventana. Estas últimas son generalmente también las incluidas en el menú de la aplicación. No es una buena práctica incluir acciones de ventana en el menú de la aplicación. Con motivo de demostración, los archivos de ejemplo completos incluyen XML en el archivo de IU que crea el menú de la aplicación incluyendo elementos «New» y «Open», y estos están vinculados a las mismas acciones que los elementos de la barra de menú del mismo nombre.

# Submenú «choices» y elementos con estado

Las líneas 30 a 80 inclusive del demuestran el código XML usado para crear la IU del menú Choices.

Las acciones creadas hasta ahora no tienen estado, esto significa que no mantienen o dependen de un estado dado por la acción en sí. Las acciones que necesita crear para el submenú «Choices», por otro lado, tienen estado. Un ejemplo de creación de una acción con estado es:

shape_action = Gio.SimpleAction.new_stateful("shape", GLib.VariantType.new('s'), GLib.Variant.new_string('line'))

donde las variables del método son: nombre, tipo de parámetro (en este caso, una cadena: consulte aquí para una lista completa de significados de caracteres), estado inicial (en este caso, «line»; en el caso de un valor booleano `True` debería ser `Glib.Variant.new_boolean(True)`, y así sucesivamente, consulte aquí para ver una lista completa).

Después de haber creado la «SimpleAction» con estado se conecta a su función de retorno de llamada y se añade a la ventana (o la aplicación, si es el caso), como antes:

shape_action.connect("activate", self.shape_callback) self.add_action(shape_action)

# Archivo de IU XML completo de este ejemplo

<?xml version="1.0" encoding="UTF-8"?> <interface> <menu id="menubar"> <submenu> <attribute name="label">File</attribute> <section> <item> <attribute name="label">New</attribute> <attribute name="action">app.new</attribute> </item> <item> <attribute name="label">Quit</attribute> <attribute name="action">app.quit</attribute> </item> </section> </submenu> <submenu> <attribute name="label">Edit</attribute> <section> <item> <attribute name="label">Copy</attribute> <attribute name="action">win.copy</attribute> </item> <item> <attribute name="label">Paste</attribute> <attribute name="action">win.paste</attribute> </item> </section> </submenu> <submenu> <attribute name="label">Choices</attribute> <submenu> <attribute name="label">Shapes</attribute> <section> <item> <attribute name="label">Line</attribute> <attribute name="action">win.shape</attribute> <attribute name="target">line</attribute> </item> <item> <attribute name="label">Triangle</attribute> <attribute name="action">win.shape</attribute> <attribute name="target">triangle</attribute> </item> <item> <attribute name="label">Square</attribute> <attribute name="action">win.shape</attribute> <attribute name="target">square</attribute> </item> <item> <attribute name="label">Polygon</attribute> <attribute name="action">win.shape</attribute> <attribute name="target">polygon</attribute> </item> <item> <attribute name="label">Circle</attribute> <attribute name="action">win.shape</attribute> <attribute name="target">circle</attribute> </item> </section> </submenu> <section> <item> <attribute name="label">On</attribute> <attribute name="action">app.state</attribute> <attribute name="target">on</attribute> </item> <item> <attribute name="label">Off</attribute> <attribute name="action">app.state</attribute> <attribute name="target">off</attribute> </item> </section> <section> <item> <attribute name="label">Awesome</attribute> <attribute name="action">app.awesome</attribute> </item> </section> </submenu> <submenu> <attribute name="label">Help</attribute> <section> <item> <attribute name="label">About</attribute> <attribute name="action">win.about</attribute> </item> </section> </submenu> </menu> <menu id="appmenu"> <section> <item> <attribute name="label">New</attribute> <attribute name="action">app.new</attribute> </item> <item> <attribute name="label">Quit</attribute> <attribute name="action">app.quit</attribute> </item> </section> </menu> </interface>

# Archivo de Python completo de este ejemplo

from gi.repository import Gtk from gi.repository import GLib from gi.repository import Gio import sys

class MyWindow(Gtk.ApplicationWindow):

def __init__(self, app): Gtk.Window.__init__(self, title="MenuBar Example", application=app) self.set_default_size(200, 200)

# action without a state created (name, parameter type) copy_action = Gio.SimpleAction.new("copy", None) # connected with the callback function copy_action.connect("activate", self.copy_callback) # added to the window self.add_action(copy_action)

# action without a state created (name, parameter type) paste_action = Gio.SimpleAction.new("paste", None) # connected with the callback function paste_action.connect("activate", self.paste_callback) # added to the window self.add_action(paste_action)

# action with a state created (name, parameter type, initial state) shape_action = Gio.SimpleAction.new_stateful( "shape", GLib.VariantType.new('s'), GLib.Variant.new_string('line')) # connected to the callback function shape_action.connect("activate", self.shape_callback) # added to the window self.add_action(shape_action)

# action with a state created about_action = Gio.SimpleAction.new("about", None) # action connected to the callback function about_action.connect("activate", self.about_callback) # action added to the application self.add_action(about_action)

# callback function for copy_action def copy_callback(self, action, parameter): print("\"Copy\" activated")

# callback function for paste_action def paste_callback(self, action, parameter): print("\"Paste\" activated")

# callback function for shape_action def shape_callback(self, action, parameter): print("Shape is set to", parameter.get_string()) # Note that we set the state of the action! action.set_state(parameter)

# callback function for about (see the AboutDialog example) def about_callback(self, action, parameter): # a Gtk.AboutDialog aboutdialog = Gtk.AboutDialog()

# lists of authors and documenters (will be used later) authors = ["GNOME Documentation Team"] documenters = ["GNOME Documentation Team"]

# we fill in the aboutdialog aboutdialog.set_program_name("MenuBar Example") aboutdialog.set_copyright( "Copyright \xc2\xa9 2012 GNOME Documentation Team") aboutdialog.set_authors(authors) aboutdialog.set_documenters(documenters) aboutdialog.set_website("http://developer.gnome.org") aboutdialog.set_website_label("GNOME Developer Website")

# to close the aboutdialog when "close" is clicked we connect the # "response" signal to on_close aboutdialog.connect("response", self.on_close) # show the aboutdialog aboutdialog.show()

# a callback function to destroy the aboutdialog def on_close(self, action, parameter): action.destroy()

class MyApplication(Gtk.Application):

def __init__(self): Gtk.Application.__init__(self)

def do_activate(self): win = MyWindow(self) win.show_all()

def do_startup(self): # FIRST THING TO DO: do_startup() Gtk.Application.do_startup(self)

# action without a state created new_action = Gio.SimpleAction.new("new", None) # action connected to the callback function new_action.connect("activate", self.new_callback) # action added to the application self.add_action(new_action)

# action without a state created quit_action = Gio.SimpleAction.new("quit", None) # action connected to the callback function quit_action.connect("activate", self.quit_callback) # action added to the application self.add_action(quit_action)

# action with a state created state_action = Gio.SimpleAction.new_stateful( "state", GLib.VariantType.new('s'), GLib.Variant.new_string('off')) # action connected to the callback function state_action.connect("activate", self.state_callback) # action added to the application self.add_action(state_action)

# action with a state created awesome_action = Gio.SimpleAction.new_stateful( "awesome", None, GLib.Variant.new_boolean(False)) # action connected to the callback function awesome_action.connect("activate", self.awesome_callback) # action added to the application self.add_action(awesome_action)

# a builder to add the UI designed with Glade to the grid: builder = Gtk.Builder() # get the file (if it is there) try: builder.add_from_file("menubar.ui") except: print("file not found") sys.exit()

# we use the method Gtk.Application.set_menubar(menubar) to add the menubar # and the menu to the application (Note: NOT the window!) self.set_menubar(builder.get_object("menubar")) self.set_app_menu(builder.get_object("appmenu"))

# callback function for new def new_callback(self, action, parameter): print("You clicked \"New\"")

# callback function for quit def quit_callback(self, action, parameter): print("You clicked \"Quit\"") sys.exit()

# callback function for state def state_callback(self, action, parameter): print("State is set to", parameter.get_string()) action.set_state(parameter)

# callback function for awesome def awesome_callback(self, action, parameter): action.set_state(GLib.Variant.new_boolean(not action.get_state())) if action.get_state().get_boolean() is True: print("You checked \"Awesome\"") else: print("You unchecked \"Awesome\"")

app = MyApplication() exit_status = app.run(sys.argv) sys.exit(exit_status)

# Atajos y aceleradores

Las etiquetas pueden contener atajos. Los atajos son caracteres subrayados en la etiqueta, usados para navegar con el teclado. Se crean poniendo un guión bajo antes del carácter de atajo. Por ejemplo «_Archivo» en lugar de solo «Archivo» en el atributo «label» del «menubar.ui».

Los atajos son visibles cuando pulsa la tecla Alt. Presionar AltA abrirá el menú Archivo.

Los aceleradores pueden añadirse explícitamente en las definiciones de la IU. Por ejemplo, es común poder cerrar una aplicación presionando CtrlQ o guardar un archivo presionando CtrlS. Para añadir un acelerador a la definición de IU, simplemente añádale un atributo «accel» al elemento.

`<attribute name="accel">&lt;Primary&gt;q</attribute>` creará la secuencia CtrlQ cuando se añada al elemento de la etiqueta `Quit`. Aquí, «Primary» se refiere a la tecla Ctrl en una PC o ⌘ en una Mac.

<item> <attribute name="label">_Quit</attribute> <attribute name="action">app.quit</attribute> <attribute name="accel">&lt;Primary&gt;q</attribute> </item>

# Cadenas traducibles

Dado que las aplicaciones de GNOME se traducen a muchos idiomas, es importante que las cadenas en su aplicación puedan traducirse. Para hacer una etiqueta traducible, simplemente añada `translatable="yes"`:

<attribute name="label" translatable="yes">Quit</attribute>

# Referencias de la API

En este ejemplo se usa lo siguiente:

GSimpleAction

GtkBuilder