Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Instalación
El primer paso antes de comenzar con la codificación real consiste en configurar PyGObject y sus
dependencias. PyGObject es un módulo de Python que permite a los desarrolladores acceder a
bibliotecas basadas en GObject como GTK + dentro de Python. Es compatible exclusivamente con
GTK + versión 3 o posterior.
1.1. Dependencias
• GTK + 3
• Python 2 (2.6 o posterior) o Python 3 (3.1 o posterior)
• introspección de objetos
Imprimirá todas las aplicaciones y bibliotecas que faltan actualmente en su sistema pero que son
necesarias para la compilación. Debe instalar los que usan el repositorio de paquetes de su distribución.
En la wiki de GNOME se mantiene una lista de nombres de paquetes para diferentes distribuciones.
Ejecute el comando anterior nuevamente para asegurarse de que las herramientas necesarias estén
presentes.
La ejecución del siguiente comando construirá PyGObject y todas sus dependencias:
$ jhbuild build pygobject
Para iniciar un shell con el mismo entorno que utiliza JHBuild, ejecute:
$ jhbuild shell
2. Comenzando
2.1. Ejemplo simple
Para comenzar con nuestro tutorial creamos el programa más simple posible. Este programa creará una
ventana vacía de 200 x 200 píxeles.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
win = Gtk.Window()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
Al principio, tenemos que importar el módulo Gtk para poder acceder a las clases y funciones de GTK
+. Dado que el sistema de un usuario puede tener varias versiones de GTK + instaladas al mismo
tiempo, queremos asegurarnos de que cuando importamos Gtk se refiere a GTK + 3 y no a ninguna otra
versión de la biblioteca, que es el propósito de la declaración .gi.require_version('Gtk',
'3.0')
La siguiente línea crea una ventana vacía.
win = Gtk.Window()
Finalmente, iniciamos el ciclo de procesamiento GTK + que salimos cuando se cierra la ventana (ver
línea 6).
Gtk.main()
Para ejecutar el programa, abra una terminal, cambie al directorio del archivo e ingrese:
python simple_example.py
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Hello World")
Este ejemplo difiere del ejemplo simple ya que subclasificamos Gtk.Windowpara definir nuestra
propia MyWindowclase.
class MyWindow(Gtk.Window):
Las siguientes tres líneas se utilizan para crear un widget de botón, conectarse a su señal de clic y
agregarlo como hijo a la ventana de nivel superior.
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
El último bloque, fuera de la clase, es muy similar al ejemplo simple anterior, pero en lugar de crear
una instancia de la Gtk.Windowclase genérica , creamos una instancia de MyWindow.
3. Conceptos básicos
Esta sección presentará algunos de los aspectos más importantes de GTK +.
En primer lugar, el widget es una instancia de un widget que creamos anteriormente. A continuación, el
evento que nos interesa. Cada widget tiene sus propios eventos particulares que pueden ocurrir. Por
ejemplo, si tiene un botón, por lo general desea conectarse al evento en el que se hizo clic. Esto
significa que cuando se hace clic en el botón, se emite la señal. En tercer lugar, el argumento de
devolución de llamada es el nombre de la función de devolución de llamada. Contiene el código que se
ejecuta cuando se emiten señales del tipo especificado. Finalmente, el argumento de datos incluye
cualquier dato que deba pasarse cuando se emite la señal. Sin embargo, este argumento es
completamente opcional y puede omitirse si no es necesario.
La función devuelve un número que identifica este par de señal-devolución de llamada en particular. Es
necesario desconectarse de una señal de modo que no se llame a la función de devolución de llamada
durante ninguna emisión futura o en curso de la señal a la que se ha conectado.
widget.disconnect(handler_id)
Si ha perdido el "handler_id" por alguna razón (por ejemplo, los controladores se instalaron usando
Gtk.Builder.connect_signals()), aún puede desconectar una devolución de llamada
específica usando la función disconnect_by_func():
widget.disconnect_by_func(callback)
Las aplicaciones deben conectarse a la señal de "destrucción" de la ventana de nivel superior. Se emite
cuando se destruye un objeto, por lo que cuando un usuario solicita que se cierre una ventana de nivel
superior, el controlador predeterminado para esta señal destruye la ventana, pero no finaliza la
aplicación. La conexión de la señal de "destrucción" de la ventana de nivel superior a la función
Gtk.main_quit()dará como resultado el comportamiento deseado.
window.connect("destroy", Gtk.main_quit)
3.2. Propiedades
Las propiedades describen la configuración y el estado de los widgets. En cuanto a las señales, cada
widget tiene su propio conjunto particular de propiedades. Por ejemplo, un botón tiene la propiedad
"etiqueta" que contiene el texto del widget de etiqueta dentro del botón. Puede especificar el nombre y
el valor de cualquier número de propiedades como argumentos de palabra clave al crear una instancia
de un widget. Para crear una etiqueta alineada a la derecha con el texto "Hola mundo" y un ángulo de
25 grados, use:
label = Gtk.Label(label="Hello World", angle=25, halign=Gtk.Align.END)
que es equivalente a
label = Gtk.Label()
label.set_label("Hello World")
label.set_angle(25)
label.set_halign(Gtk.Align.END)
En lugar de utilizar getters y setters, también puede obtener y establecer las propiedades de gobject a
través de la propiedad "props", como . Esto es equivalente al más detallado
y .widget.props.prop_name = valuewidget.get_property("prop-
name")widget.set_property("prop-name", value)
Para ver qué propiedades están disponibles para un widget en la versión en ejecución de GTK, puede
"dir" la propiedad "props":
widget = Gtk.Box()
print(dir(widget.props))
4.1. Definiciones
Conceptualmente, una cadena es una lista de caracteres como 'A', 'B', 'C' o 'É'. Los caracteres son
representaciones abstractas y su significado depende del idioma y el contexto en el que se utilizan. El
estándar Unicode describe cómo se representan los caracteres mediante puntos de código . Por
ejemplo, los caracteres anteriores se representan con los puntos de código U + 0041, U + 0042, U +
0043 y U + 00C9, respectivamente. Básicamente, los puntos de código son números en el rango de 0 a
0x10FFFF.
Como se mencionó anteriormente, la representación de una cadena como una lista de puntos de código
es abstracta. Para convertir esta representación abstracta en una secuencia de bytes, la cadena Unicode
debe estar codificada . La forma más simple de codificación es ASCII y se realiza de la siguiente
manera:
1. Si el punto de código es <128, cada byte es el mismo que el valor del punto de código.
2. Si el punto de código es 128 o mayor, la cadena Unicode no se puede representar en esta
codificación. (Python genera una UnicodeEncodeErrorexcepción en este caso).
Aunque la codificación ASCII es fácil de aplicar, solo se puede codificar para 128 caracteres diferentes,
lo que no es suficiente. Una de las codificaciones más utilizadas que resuelve este problema es UTF-8
(puede manejar cualquier punto de código Unicode). UTF significa "Formato de transformación
Unicode", y el '8' significa que se utilizan números de 8 bits en la codificación.
4.2. Python 2
4.2.1. Soporte Unicode de Python 2.x
Python 2 viene con dos tipos diferentes de objetos que se pueden usar para representar cadenas stry
unicode. Las instancias de este último se utilizan para expresar cadenas Unicode, mientras que las
instancias del strtipo son representaciones de bytes (la cadena codificada). Debajo del capó, Python
representa cadenas Unicode como enteros de 16 o 32 bits, dependiendo de cómo se compiló el
intérprete de Python. Las cadenas Unicode se pueden convertir en cadenas de 8 bits con
unicode.encode():
>>> unicode_string = u"Fu\u00dfb\u00e4lle"
>>> print unicode_string
Fußbälle
>>> type(unicode_string)
<type 'unicode'>
>>> unicode_string.encode("utf-8")
'Fu\xc3\x9fb\xc3\xa4lle'
Las cadenas de 8 bits de Python tienen un str.decode()método que interpreta la cadena usando la
codificación dada:
>>> utf8_string = unicode_string.encode("utf-8")
>>> type(utf8_string)
<type 'str'>
>>> u2 = utf8_string.decode("utf-8")
>>> unicode_string == u2
True
Desafortunadamente, Python 2.x le permite mezclar unicodey strsi la cadena de 8 bits contiene
solo bytes de 7 bits (ASCII), pero obtendría UnicodeDecodeErrorsi contuviera valores no ASCII:
>>> utf8_string = " sind rund"
>>> unicode_string + utf8_string
u'Fu\xdfb\xe4lle sind rund'
>>> utf8_string = " k\xc3\xb6nnten rund sein"
>>> print utf8_string
könnten rund sein
>>> unicode_string + utf8_string
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 2:
ordinal not in range(128)
4.3. Python 3
4.3.1. Soporte Unicode de Python 3.x
Desde Python 3.0, todas las cadenas se almacenan como Unicode en una instancia del strtipo. Las
cadenas codificadas, por otro lado, se representan como datos binarios en forma de instancias del
bytestipo. Conceptualmente, se strrefiere a texto , mientras que se bytesrefiere a datos . Utilice
str.encode()para ir de stra bytesy bytes.decode()para ir de bytesa str.
Además, ya no es posible mezclar cadenas Unicode con cadenas codificadas, porque resultará en
TypeError:
>>> text = "Fu\u00dfb\u00e4lle"
>>> data = b" sind rund"
>>> text + data
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bytes' object to str implicitly
>>> text + data.decode("utf-8")
'Fußbälle sind rund'
>>> text.encode("utf-8") + data
b'Fu\xc3\x9fb\xc3\xa4lle sind rund'
4.3.2. Unicode en GTK +
Como consecuencia, las cosas son mucho más limpias y consistentes con Python 3.x, porque
PyGObject codificará / decodificará automáticamente a / desde UTF-8 si pasa una cadena a un método
o un método devuelve una cadena. Las cadenas o texto siempre se representarán como instancias de
strsolo:
>>> from gi.repository import Gtk
>>> label = Gtk.Label()
>>> text = "Fu\u00dfb\u00e4lle"
>>> label.set_text(text)
>>> txt = label.get_text()
>>> type(txt), txt
(<class 'str'>, 'Fußbälle')
>>> txt == text
True
4.4. Referencias
Las novedades de Python 3.0 describen los nuevos conceptos que distinguen claramente entre texto y
datos.
El CÓMO de Unicode analiza el soporte de Python 2.x para Unicode y explica varios problemas que la
gente encuentra comúnmente cuando intenta trabajar con Unicode.
El Unicode HOWTO para Python 3.x analiza el soporte de Unicode en Python 3.x.
La tabla de codificación UTF-8 y los caracteres Unicode contienen una lista de puntos de código
Unicode y su codificación UTF-8 respectiva.
5. Galería de widgets
Gtk.AboutDialog
Gtk.AccelLabel
Gtk.ActionBar
Gtk.AppChooserButton
Gtk.AppChooserDialog
Gtk.Assistant
Gtk.Button
Gtk.CheckButton
Gtk.ColorButton
Gtk.ColorChooserDialog
Gtk.ComboBox
Gtk.ComboBoxText
Gtk.Entry
Gtk.FileChooserButton
Gtk.FileChooserDialog
Gtk.FlowBox
Gtk.FontButton
Gtk.FontChooserDialog
Gtk.Frame
Gtk.GLArea
Gtk.Grid
Gtk.HeaderBar
Gtk.IconView
Gtk.Image
Gtk.InfoBar
Gtk.Label
Gtk.LevelBar
Gtk.LinkButton
Gtk.ListBox
Gtk.LockButton
Gtk.MenuBar
Gtk.MenuButton
Gtk.MessageDialog
Gtk.Notebook
Gtk.Paned
Gtk.PlacesSidebar
Gtk.ProgressBar
Gtk.RadioButton
Gtk.RecentChooserDialog
Gtk.Scale
Gtk.Scrollbar
Gtk.ScrolledWindow
Gtk.SearchBar
Gtk.SearchEntry
Gtk.Separator
Gtk.SpinButton
Gtk.Spinner
Gtk.Stack
Gtk.StackSwitcher
Gtk.Statusbar
Gtk.Switch
Gtk.TextView
Gtk.ToggleButton
Gtk.ToolPalette
Gtk.Toolbar
Gtk.TreeView
Gtk.VolumeButton
Gtk.Window
6. Diseño de contenedores
Si bien muchos kits de herramientas de GUI requieren que coloques con precisión los widgets en una
ventana, usando el posicionamiento absoluto, GTK + usa un enfoque diferente. En lugar de especificar
la posición y el tamaño de cada widget en la ventana, puede organizar sus widgets en filas, columnas
y / o tablas. El tamaño de su ventana se puede determinar automáticamente, en función del tamaño de
los widgets que contiene. Y los tamaños de los widgets, a su vez, están determinados por la cantidad de
texto que contienen, o los tamaños mínimo y máximo que especifique, y / o cómo haya solicitado que
el espacio disponible se comparta entre conjuntos de widgets. Puede perfeccionar su diseño
especificando la distancia de relleno y los valores de centrado para cada uno de sus widgets. GTK +
luego usa toda esta información para cambiar el tamaño y reposicionar todo de manera sensata y sin
problemas cuando el usuario manipula la ventana.
GTK + organiza los widgets jerárquicamente, utilizando contenedores . Son invisibles para el usuario
final y se insertan en una ventana o se colocan entre sí para diseñar componentes. Hay dos tipos de
contenedores: contenedores de un solo hijo, que son todos descendientes de Gtk.Bin, y contenedores
de varios hijos, que son descendientes de Gtk.Container. Los más utilizados son los cuadros
verticales u horizontales ( Gtk.Box) y las cuadrículas ( Gtk.Grid).
6.1. Cajas
Las cajas son contenedores invisibles en los que podemos guardar nuestros widgets. Al empaquetar los
widgets en una caja horizontal, los objetos se insertan horizontalmente de izquierda a derecha o de
derecha a izquierda, dependiendo de si se usa Gtk.Box.pack_start()o
Gtk.Box.pack_end(). En una caja vertical, los widgets se empaquetan de arriba a abajo o
viceversa. Puede utilizar cualquier combinación de cuadros dentro o al lado de otros cuadros para crear
el efecto deseado.
6.1.1. Ejemplo
Echemos un vistazo a una versión ligeramente modificada del ejemplo extendido con dos botones.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Hello World")
self.box = Gtk.Box(spacing=6)
self.add(self.box)
self.button1 = Gtk.Button(label="Hello")
self.button1.connect("clicked", self.on_button1_clicked)
self.box.pack_start(self.button1, True, True, 0)
self.button2 = Gtk.Button(label="Goodbye")
self.button2.connect("clicked", self.on_button2_clicked)
self.box.pack_start(self.button2, True, True, 0)
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
Primero, creamos un contenedor de caja orientado horizontalmente donde se colocan 6 píxeles entre los
niños. Este cuadro se convierte en el hijo de la ventana de nivel superior.
self.box = Gtk.Box(spacing=6)
self.add(self.box)
self.button2 = Gtk.Button(label="Goodbye")
self.button2.connect("clicked", self.on_button2_clicked)
self.box.pack_start(self.button2, True, True, 0)
Mientras que los Gtk.Box.pack_start()widgets se colocan de izquierda a derecha, los
Gtk.Box.pack_end()coloca de derecha a izquierda.
6.2. Red
Gtk.Grides un contenedor que organiza sus widgets secundarios en filas y columnas, pero no es
necesario especificar las dimensiones en el constructor. Los niños se agregan usando
Gtk.Grid.attach(). Pueden abarcar varias filas o columnas. El Gtk.Grid.attach()método
toma cinco parámetros:
1. El childparámetro es el que se va Gtk.Widgeta agregar.
6.2.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class GridWindow(Gtk.Window):
def __init__(self):
sper().__init__(title="Grid Example")
grid = Gtk.Grid()
self.add(grid)
grid.add(button1)
grid.attach(button2, 1, 0, 2, 1)
grid.attach_next_to(button3, button1, Gtk.PositionType.BOTTOM, 1, 2)
grid.attach_next_to(button4, button3, Gtk.PositionType.RIGHT, 2, 1)
grid.attach(button5, 1, 2, 1, 1)
grid.attach_next_to(button6, button5, Gtk.PositionType.RIGHT, 1, 1)
win = GridWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class ListBoxRowWithData(Gtk.ListBoxRow):
def __init__(self, data):
super().__init__()
self.data = data
self.add(Gtk.Label(label=data))
class ListBoxWindow(Gtk.Window):
def __init__(self):
super().__init__(title="ListBox Demo")
self.set_border_width(10)
listbox = Gtk.ListBox()
listbox.set_selection_mode(Gtk.SelectionMode.NONE)
box_outer.pack_start(listbox, True, True, 0)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
listbox.add(row)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
label = Gtk.Label(label="Enable Automatic Update", xalign=0)
check = Gtk.CheckButton()
hbox.pack_start(label, True, True, 0)
hbox.pack_start(check, False, True, 0)
listbox.add(row)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
label = Gtk.Label(label="Date Format", xalign=0)
combo = Gtk.ComboBoxText()
combo.insert(0, "0", "24-hour")
combo.insert(1, "1", "AM/PM")
hbox.pack_start(label, True, True, 0)
hbox.pack_start(combo, False, True, 0)
listbox.add(row)
listbox_2 = Gtk.ListBox()
items = "This is a sorted ListBox Fail".split()
listbox_2.connect("row-activated", on_row_activated)
win = ListBoxWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
6.4. Stack y StackSwitcher
A Gtk.Stackes un contenedor que solo muestra uno de sus hijos a la vez. A diferencia de
Gtk.Notebook, Gtk.Stackno proporciona un medio para que los usuarios cambien al niño
visible. En su lugar, el Gtk.StackSwitcherwidget se puede utilizar Gtk.Stackpara
proporcionar esta funcionalidad.
Las transiciones entre páginas se pueden animar como diapositivas o fundidos. Esto se puede controlar
con Gtk.Stack.set_transition_type(). Estas animaciones respetan la configuración "gtk-
enable-animations".
La velocidad de transición se puede ajustar con Gtk.Stack.set_transition_duration()
6.4.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class StackWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Stack Demo")
self.set_border_width(10)
stack = Gtk.Stack()
stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
stack.set_transition_duration(1000)
label = Gtk.Label()
label.set_markup("<big>A fancy label</big>")
stack.add_titled(label, "label", "A label")
stack_switcher = Gtk.StackSwitcher()
stack_switcher.set_stack(stack)
vbox.pack_start(stack_switcher, True, True, 0)
vbox.pack_start(stack, True, True, 0)
win = StackWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
6.5. HeaderBar
A Gtk.HeaderBares similar a una horizontal Gtk.Box, permite colocar a los niños al principio o al
final. Además, permite mostrar un título. El título estará centrado con respecto al ancho del cuadro,
incluso si los niños de cada lado ocupan diferentes cantidades de espacio.
Dado que GTK + ahora es compatible con la decoración del lado del cliente, Gtk.HeaderBarse
puede usar a en lugar de la barra de título (que se representa con el Administrador de ventanas).
Gtk.HeaderBarPor lo general, A se encuentra en la parte superior de una ventana y debe contener
controles de uso común que afecten el contenido a continuación. También brindan acceso a los
controles de la ventana, incluido el botón para cerrar la ventana y el menú de la ventana.
6.5.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio
class HeaderBarWindow(Gtk.Window):
def __init__(self):
super().__init__(title="HeaderBar Demo")
self.set_border_width(10)
self.set_default_size(400, 200)
hb = Gtk.HeaderBar()
hb.set_show_close_button(True)
hb.props.title = "HeaderBar example"
self.set_titlebar(hb)
button = Gtk.Button()
icon = Gio.ThemedIcon(name="mail-send-receive-symbolic")
image = Gtk.Image.new_from_gicon(icon, Gtk.IconSize.BUTTON)
button.add(image)
hb.pack_end(button)
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
Gtk.StyleContext.add_class(box.get_style_context(), "linked")
button = Gtk.Button()
button.add(
Gtk.Arrow(arrow_type=Gtk.ArrowType.LEFT, shadow_type=Gtk.ShadowType.NONE)
)
box.add(button)
button = Gtk.Button()
button = Gtk.Button.new_from_icon_name("pan-end-symbolic", Gtk.IconSize.MENU)
box.add(button)
hb.pack_start(box)
self.add(Gtk.TextView())
win = HeaderBarWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
6.6. FlowBox
Nota
Este ejemplo requiere al menos GTK + 3.12.
A Gtk.FlowBoxes un contenedor que coloca los widgets secundarios en secuencia según su
orientación.
Por ejemplo, con la orientación horizontal, los widgets se organizarán de izquierda a derecha,
comenzando una nueva fila debajo de la fila anterior cuando sea necesario. Reducir el ancho en este
caso requerirá más filas, por lo que se solicitará una altura mayor.
Asimismo, con la orientación vertical, los widgets se ordenarán de arriba hacia abajo, comenzando una
nueva columna a la derecha cuando sea necesario. Reducir la altura requerirá más columnas, por lo que
se solicitará un ancho mayor.
Los elementos secundarios de a Gtk.FlowBoxse pueden clasificar y filtrar dinámicamente.
6.6.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
class FlowBoxWindow(Gtk.Window):
def __init__(self):
super().__init__(title="FlowBox Demo")
self.set_border_width(10)
self.set_default_size(300, 250)
self.set_titlebar(header)
scrolled = Gtk.ScrolledWindow()
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
flowbox = Gtk.FlowBox()
flowbox.set_valign(Gtk.Align.START)
flowbox.set_max_children_per_line(30)
flowbox.set_selection_mode(Gtk.SelectionMode.NONE)
self.create_flowbox(flowbox)
scrolled.add(flowbox)
self.add(scrolled)
self.show_all()
width = widget.get_allocated_width()
height = widget.get_allocated_height()
Gtk.render_background(context, cr, 0, 0, width, height)
r, g, b, a = data["color"]
cr.set_source_rgba(r, g, b, a)
cr.rectangle(0, 0, width, height)
cr.fill()
button = Gtk.Button()
area = Gtk.DrawingArea()
area.set_size_request(24, 24)
area.connect("draw", self.on_draw, {"color": rgba})
button.add(area)
return button
win = FlowBoxWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
6.7.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Simple Notebook Example")
self.set_border_width(3)
self.notebook = Gtk.Notebook()
self.add(self.notebook)
self.page1 = Gtk.Box()
self.page1.set_border_width(10)
self.page1.add(Gtk.Label(label="Default Page!"))
self.notebook.append_page(self.page1, Gtk.Label(label="Plain Title"))
self.page2 = Gtk.Box()
self.page2.set_border_width(10)
self.page2.add(Gtk.Label(label="A page with an image for a Title."))
self.notebook.append_page(
self.page2, Gtk.Image.new_from_icon_name("help-about",
Gtk.IconSize.MENU)
)
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
7. Etiqueta
Las etiquetas son el método principal para colocar texto no editable en ventanas, por ejemplo, para
colocar un título junto a un Gtk.Entrywidget. Puede especificar el texto en el constructor o más
tarde con los métodos Gtk.Label.set_text()o Gtk.Label.set_markup().
Gtk.Labeladmite algunos formatos simples, por ejemplo, lo que le permite hacer un texto en negrita,
coloreado o más grande. Puede hacer esto proporcionando una cadena a
Gtk.Label.set_markup(), utilizando la sintaxis 1 de Pango Markup . Por ejemplo, . Además,
admite hipervínculos en los que se puede hacer clic. El marcado de los enlaces se toma prestado de
HTML, utilizando los atributos a con href y title. GTK + muestra los enlaces de forma similar a la
forma en que aparecen en los navegadores web, con texto subrayado en color. El atributo de título se
muestra como información sobre herramientas en el enlace.<b>bold text</b> and
<s>strikethrough text</s>Gtk.Label
label.set_markup("Go to <a href=\"https://www.gtk.org\" "
"title=\"Our website\">GTK+ website</a> for more")
Las etiquetas pueden contener nemotécnicos . Los mnemónicos son caracteres subrayados en la
etiqueta que se utilizan para la navegación con el teclado. Los mnemónicos se crean proporcionando
una cadena con un guión bajo antes del carácter mnemónico, como "_File", a las funciones
Gtk.Label.new_with_mnemonic()o Gtk.Label.set_text_with_mnemonic(). Los
mnemónicos activan automáticamente cualquier widget activable dentro de la etiqueta, como a
Gtk.Button; si la etiqueta no está dentro del widget de destino del mnemónico, debe informarle a la
etiqueta sobre el destino que usa Gtk.Label.set_mnemonic_widget().
7.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class LabelWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Label Example")
hbox = Gtk.Box(spacing=10)
hbox.set_homogeneous(False)
vbox_left = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
vbox_left.set_homogeneous(False)
vbox_right = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
vbox_right.set_homogeneous(False)
label = Gtk.Label(
label="This is a right-justified label.\nWith multiple lines."
)
label.set_justify(Gtk.Justification.RIGHT)
vbox_left.pack_start(label, True, True, 0)
label = Gtk.Label(
label="This is an example of a line-wrapped label. It "
"should not be taking up the entire "
"width allocated to it, but automatically "
"wraps the words to fit.\n"
" It supports multiple paragraphs correctly, "
"and correctly adds "
"many extra spaces. "
)
label.set_line_wrap(True)
label.set_max_width_chars(32)
vbox_right.pack_start(label, True, True, 0)
label = Gtk.Label(
label="This is an example of a line-wrapped, filled label. "
"It should be taking "
"up the entire width allocated to it. "
"Here is a sentence to prove "
"my point. Here is another sentence. "
"Here comes the sun, do de do de do.\n"
" This is a new paragraph.\n"
" This is another newer, longer, better "
"paragraph. It is coming to an end, "
"unfortunately."
)
label.set_line_wrap(True)
label.set_justify(Gtk.Justification.FILL)
label.set_max_width_chars(32)
vbox_right.pack_start(label, True, True, 0)
label = Gtk.Label()
label.set_markup(
"Text can be <small>small</small>, <big>big</big>, "
"<b>bold</b>, <i>italic</i> and even point to "
'somewhere in the <a href="https://www.gtk.org" '
'title="Click to find out more">internets</a>.'
)
label.set_line_wrap(True)
label.set_max_width_chars(48)
vbox_left.pack_start(label, True, True, 0)
label = Gtk.Label.new_with_mnemonic(
"_Press Alt + P to select button to the right"
)
vbox_left.pack_start(label, True, True, 0)
label.set_selectable(True)
self.add(hbox)
window = LabelWindow()
window.connect("destroy", Gtk.main_quit)
window.show_all()
Gtk.main()
8. Entrada
Los widgets de entrada permiten al usuario ingresar texto. Puede cambiar el contenido con el
Gtk.Entry.set_text()método y leer el contenido actual con el
Gtk.Entry.get_text()método. También puede limitar la cantidad de caracteres que la Entrada
puede tomar llamando Gtk.Entry.set_max_length().
Ocasionalmente, es posible que desee hacer que un widget de entrada sea de solo lectura. Esto se puede
hacer pasando Falseal Gtk.Entry.set_editable()método.
Los widgets de entrada también se pueden utilizar para recuperar contraseñas del usuario. Es una
práctica común ocultar los caracteres escritos en la entrada para evitar revelar la contraseña a un
tercero. Llamar Gtk.Entry.set_visibility()con Falsehará que el texto se oculte.
Además, una entrada puede mostrar iconos a ambos lados de la entrada. Estos iconos se pueden activar
haciendo clic en, se pueden configurar como fuente de arrastre y pueden tener información sobre
herramientas. Para agregar un icono, utilice Gtk.Entry.set_icon_from_icon_name()o una
de las otras funciones que establecen un icono a partir de un nombre de icono, un pixbuf o un tema de
icono. Para establecer una información sobre herramientas en un icono, utilice
Gtk.Entry.set_icon_tooltip_text()o la función correspondiente para el marcado.
8.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
class EntryWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Entry Demo")
self.set_size_request(200, 100)
self.timeout_id = None
self.entry = Gtk.Entry()
self.entry.set_text("Hello World")
vbox.pack_start(self.entry, True, True, 0)
hbox = Gtk.Box(spacing=6)
vbox.pack_start(hbox, True, True, 0)
self.check_editable = Gtk.CheckButton(label="Editable")
self.check_editable.connect("toggled", self.on_editable_toggled)
self.check_editable.set_active(True)
hbox.pack_start(self.check_editable, True, True, 0)
self.check_visible = Gtk.CheckButton(label="Visible")
self.check_visible.connect("toggled", self.on_visible_toggled)
self.check_visible.set_active(True)
hbox.pack_start(self.check_visible, True, True, 0)
self.pulse = Gtk.CheckButton(label="Pulse")
self.pulse.connect("toggled", self.on_pulse_toggled)
self.pulse.set_active(False)
hbox.pack_start(self.pulse, True, True, 0)
self.icon = Gtk.CheckButton(label="Icon")
self.icon.connect("toggled", self.on_icon_toggled)
self.icon.set_active(False)
hbox.pack_start(self.icon, True, True, 0)
win = EntryWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
9. Botones de widgets
9.1. Botón
El widget de botón es otro widget de uso común. Generalmente se usa para adjuntar una función a la
que se llama cuando se presiona el botón.
El Gtk.Buttonwidget puede contener cualquier widget secundario válido. Es decir, puede contener
casi cualquier otro estándar Gtk.Widget. El niño más utilizado es el Gtk.Label.
Por lo general, desea conectarse a la señal de "clic" del botón que se emite cuando se presiona y se
suelta el botón.
9.1.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class ButtonWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Button Demo")
self.set_border_width(10)
hbox = Gtk.Box(spacing=6)
self.add(hbox)
button = Gtk.Button.new_with_mnemonic("_Open")
button.connect("clicked", self.on_open_clicked)
hbox.pack_start(button, True, True, 0)
button = Gtk.Button.new_with_mnemonic("_Close")
button.connect("clicked", self.on_close_clicked)
hbox.pack_start(button, True, True, 0)
win = ButtonWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
9.2. Botón de activación
A Gtk.ToggleButtones muy similar a una normal Gtk.Button, pero cuando se hace clic
permanecen activados, o se presionan, hasta que se hace clic de nuevo. Cuando se cambia el estado del
botón, se emite la señal "conmutada".
Para recuperar el estado del Gtk.ToggleButton, puede utilizar el
Gtk.ToggleButton.get_active()método. Esto vuelve Truesi el botón está "abajo". También
puede establecer el estado del botón de alternancia, con Gtk.ToggleButton.set_active().
Tenga en cuenta que, si hace esto, y el estado realmente cambia, hará que se emita la señal
"conmutada".
9.2.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class ToggleButtonWindow(Gtk.Window):
def __init__(self):
super().__init__(title="ToggleButton Demo")
self.set_border_width(10)
hbox = Gtk.Box(spacing=6)
self.add(hbox)
9.3. CheckButton
Gtk.CheckButtonhereda de Gtk.ToggleButton. La única diferencia real entre los dos es
Gtk.CheckButtonla apariencia. A Gtk.CheckButtoncoloca un discreto
Gtk.ToggleButtonjunto a un widget, (generalmente a Gtk.Label). La señal "conmutada"
Gtk.ToggleButton.set_active()y Gtk.ToggleButton.get_active()se heredan.
9.4.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class RadioButtonWindow(Gtk.Window):
def __init__(self):
super().__init__(title="RadioButton Demo")
self.set_border_width(10)
hbox = Gtk.Box(spacing=6)
self.add(hbox)
button2 = Gtk.RadioButton.new_from_widget(button1)
button2.set_label("Button 2")
button2.connect("toggled", self.on_button_toggled, "2")
hbox.pack_start(button2, False, False, 0)
win = RadioButtonWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
9.5. LinkButton
A Gtk.LinkButtones un Gtk.Buttonhipervínculo, similar al que utilizan los navegadores web,
que activa una acción cuando se hace clic en él. Es útil mostrar enlaces rápidos a recursos.
El URI vinculado a a Gtk.LinkButtonse puede establecer específicamente con
Gtk.LinkButton.set_uri()y recuperar con Gtk.LinkButton.get_uri().
9.5.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class LinkButtonWindow(Gtk.Window):
def __init__(self):
super().__init__(title="LinkButton Demo")
self.set_border_width(10)
button = Gtk.LinkButton.new_with_label(
uri="https://www.gtk.org",
label="Visit GTK+ Homepage"
)
self.add(button)
win = LinkButtonWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
9.6. SpinButton
A Gtk.SpinButtones una forma ideal de permitir que el usuario establezca el valor de algún
atributo. En lugar de tener que escribir directamente un número en a Gtk.Entry,
Gtk.SpinButtonpermite al usuario hacer clic en una de las dos flechas para incrementar o
disminuir el valor mostrado. Aún se puede ingresar un valor, con la ventaja de que se puede verificar
para asegurarse de que esté en un rango determinado. Se establecen las principales propiedades de
Gtk.SpinButtona Gtk.Adjustment.
También podemos ajustar la política de actualización de Gtk.SpinButton. Aquí hay dos opciones;
de forma predeterminada, el botón de número actualiza el valor incluso si los datos ingresados no son
válidos. Alternativamente, podemos configurar la política para que solo se actualice cuando el valor
ingresado sea válido llamando Gtk.SpinButton.set_update_policy().
9.6.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class SpinButtonWindow(Gtk.Window):
def __init__(self):
super().__init__(title="SpinButton Demo")
self.set_border_width(10)
hbox = Gtk.Box(spacing=6)
self.add(hbox)
check_numeric = Gtk.CheckButton(label="Numeric")
check_numeric.connect("toggled", self.on_numeric_toggled)
hbox.pack_start(check_numeric, False, False, 0)
win = SpinButtonWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
9,7. Cambiar
A Gtk.Switches un widget que tiene dos estados: encendido o apagado. El usuario puede controlar
qué estado debe estar activo haciendo clic en el área vacía o arrastrando el controlador.
No debe usar la señal de "activar" en el Gtk.Switch, que es una señal de acción y su emisión hace que
el interruptor se anime. Las aplicaciones nunca deben conectarse a esta señal, pero deben usar la señal
"notificar :: activa", vea el ejemplo a continuación.
9.7.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class SwitcherWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Switch Demo")
self.set_border_width(10)
hbox = Gtk.Box(spacing=6)
self.add(hbox)
switch = Gtk.Switch()
switch.connect("notify::active", self.on_switch_activated)
switch.set_active(False)
hbox.pack_start(switch, True, True, 0)
switch = Gtk.Switch()
switch.connect("notify::active", self.on_switch_activated)
switch.set_active(True)
hbox.pack_start(switch, True, True, 0)
win = SwitcherWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
10. Expansor
Los expansores permiten ocultar o mostrar información dinámicamente dentro de una ventana o
diálogo. Un expansor puede tomar un solo widget que se mostrará cuando se expanda.
Los expansores permanecen expandidos hasta que se hace clic de nuevo. Cuando se cambia el estado
de un expansor, se emite la señal de "activación".
Un expansor se puede expandir o contraer mediante programación pasando Verdadero o Falso a
Gtk.Expander.set_expanded(). Tenga en cuenta que al hacerlo, se emitirá la señal de
"activación".
Se puede agregar más de un widget, como un Gtk.Labely Gtk.Button, agregándolos a un
archivo Gtk.Box.
10.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class ExpanderExample(Gtk.Window):
def __init__(self):
super().__init__(title="Expander Demo")
self.set_size_request(350, 100)
text_expander = Gtk.Expander(
label="This expander displays additional information"
)
text_expander.set_expanded(True)
vbox.add(text_expander)
msg = """
This message is quite long, complicated even:
- It has a list with a sublist:
- of 3 elements;
- taking several lines;
- with indentation.
"""
details = Gtk.Label(label=msg)
text_expander.add(details)
expander_hbox = Gtk.HBox()
widget_expander.add(expander_hbox)
expander_hbox.add(Gtk.Label(label="Text message"))
expander_hbox.add(Gtk.Button(label="Click me"))
self.show_all()
win = ExpanderExample()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
11. ProgressBar
El Gtk.ProgressBarnormalmente se utiliza para mostrar el progreso de una operación de larga
duración. Proporciona una pista visual de que el procesamiento está en marcha. Se
Gtk.ProgressBarpuede utilizar en dos modos diferentes: modo de porcentaje y modo de
actividad .
Cuando una aplicación se puede determinar la cantidad de necesidades de cualquier tipo de
intervención (por ejemplo, leer un número fijo de bytes de un archivo) y puede controlar el progreso, se
puede utilizar el Gtk.ProgressBaren modo de porcentaje y el usuario ve una barra de crecimiento
que indica el porcentaje de la obra que se ha completado. En este modo, la aplicación debe llamar
Gtk.ProgressBar.set_fraction()periódicamente para actualizar la barra de progreso,
pasando un flotador entre 0 y 1 para proporcionar el nuevo valor porcentual.
Cuando una aplicación no tiene una forma precisa de saber la cantidad de trabajo por hacer, puede usar
el modo de actividad , que muestra la actividad mediante un bloque que se mueve hacia adelante y
hacia atrás dentro del área de progreso. En este modo, la aplicación debe llamar
Gtk.ProgressBar.pulse()periódicamente para actualizar la barra de progreso. También puede
elegir el tamaño del paso, con el Gtk.ProgressBar.set_pulse_step()método.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
class ProgressBarWindow(Gtk.Window):
def __init__(self):
super().__init__(title="ProgressBar Demo")
self.set_border_width(10)
self.progressbar = Gtk.ProgressBar()
vbox.pack_start(self.progressbar, True, True, 0)
if new_value > 1:
new_value = 0
self.progressbar.set_fraction(new_value)
win = ProgressBarWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
12. Spinner
El Gtk.Spinnermuestra una animación giratoria del tamaño de un icono. A menudo se utiliza como
alternativa a GtkProgressBarpara mostrar una actividad indefinida, en lugar del progreso real.
12.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class SpinnerAnimation(Gtk.Window):
def __init__(self):
super().__init__(title="Spinner")
self.set_border_width(3)
self.connect("destroy", Gtk.main_quit)
self.spinner = Gtk.Spinner()
self.grid = Gtk.Grid()
self.grid.add(self.button)
self.grid.attach_next_to(
self.spinner, self.button, Gtk.PositionType.BOTTOM, 1, 2
)
self.grid.set_row_homogeneous(True)
self.add(self.grid)
self.show_all()
if button.get_active():
self.spinner.start()
self.button.set_label("Stop Spinning")
else:
self.spinner.stop()
self.button.set_label("Start Spinning")
myspinner = SpinnerAnimation()
Gtk.main()
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
class SpinnerWindow(Gtk.Window):
def __init__(self, *args, **kwargs):
super().__init__(title="Spinner Demo")
self.set_border_width(10)
self.spinner = Gtk.Spinner()
mainBox.pack_start(self.spinner, True, True, 0)
self.label = Gtk.Label()
mainBox.pack_start(self.label, True, True, 0)
self.entry = Gtk.Entry()
self.entry.set_text("10")
mainBox.pack_start(self.entry, True, True, 0)
self.timeout_id = None
self.connect("destroy", self.on_SpinnerWindow_destroy)
def on_buttonStart_clicked(self, widget, *args):
""" Handles "clicked" event of buttonStart. """
self.start_timer()
def start_timer(self):
""" Start the timer. """
self.buttonStart.set_sensitive(False)
self.buttonStop.set_sensitive(True)
# time out will check every 250 miliseconds (1/4 of a second)
self.counter = 4 * int(self.entry.get_text())
self.label.set_label("Remaining: " + str(int(self.counter / 4)))
self.spinner.start()
self.timeout_id = GLib.timeout_add(250, self.on_timeout, None)
win = SpinnerWindow()
win.show_all()
Gtk.main()
• Clasificación de datos
• Filtrar datos
13.1. El modelo
Cada uno Gtk.TreeViewtiene un asociado Gtk.TreeModel, que contiene los datos mostrados por
TreeView. Cada uno Gtk.TreeModelpuede ser utilizado por más de uno Gtk.TreeView. Por
ejemplo, esto permite mostrar y editar los mismos datos subyacentes de 2 formas diferentes al mismo
tiempo. O las 2 vistas pueden mostrar diferentes columnas de los mismos datos del modelo, de la
misma manera que 2 consultas SQL (o "vistas") pueden mostrar diferentes campos de la misma tabla de
base de datos.
Aunque teóricamente puede implementar su propio modelo, normalmente usará las clases de modelo
Gtk.ListStoreo Gtk.TreeStore. Gtk.ListStorecontiene filas simples de datos y cada fila
no tiene hijos, mientras que Gtk.TreeStorecontiene filas de datos y cada fila puede tener filas
secundarias.
Al construir un modelo, debe especificar los tipos de datos para cada columna que contiene el modelo.
store = Gtk.ListStore(str, str, float)
Esto crea un almacén de listas con tres columnas, dos columnas de cadena y una columna flotante.
La adición de datos al modelo se realiza mediante Gtk.ListStore.append()o
Gtk.TreeStore.append(), según el tipo de modelo que se haya creado.
Para un Gtk.ListStore:
treeiter = store.append(["The Art of Computer Programming",
"Donald E. Knuth", 25.46])
Para un Gtk.TreeStore, debe especificar una fila existente a la que agregar la nueva fila, usando a
Gtk.TreeIter, o Ninguno para el nivel superior del árbol:
treeiter = store.append(None, ["The Art of Computer Programming",
"Donald E. Knuth", 25.46])
Ambos métodos devuelven una Gtk.TreeIterinstancia, que apunta a la ubicación de la fila recién
insertada. Puede recuperar un Gtk.TreeIterllamando Gtk.TreeModel.get_iter().
Una vez que se han insertado los datos, puede recuperarlos o modificarlos mediante el índice de árbol y
de columna.
print(store[treeiter][2]) # Prints value of third column
store[treeiter][2] = 42.15
Al igual que con el listobjeto integrado de Python, puede usarlo len()para obtener el número de
filas y usar cortes para recuperar o establecer valores.
# Print number of rows
print(len(store))
# Print all but first column
print(store[treeiter][1:])
# Print last column
print(store[treeiter][-1])
# Set last two columns
store[treeiter][1:] = ["Donald Ervin Knuth", 41.99]
Tenga en cuenta que si lo usa Gtk.TreeStore, el código anterior solo iterará sobre las filas del nivel
superior, pero no los hijos de los nodos. Para iterar sobre todas las filas, use
Gtk.TreeModel.foreach().
def print_row(store, treepath, treeiter):
print("\t" * (treepath.get_depth() - 1), store[treeiter][:], sep="")
store.foreach(print_row)
Además de acceder a los valores almacenados en a Gtk.TreeModelcon el método similar a una lista
mencionado anteriormente, también es posible utilizar Gtk.TreeItero Gtk.TreePathinstancias.
Ambos hacen referencia a una fila particular en un modelo de árbol. Uno puede convertir una ruta en
un iterador llamando Gtk.TreeModel.get_iter(). Como Gtk.ListStorecontiene solo un
nivel, es decir, los nodos no tienen ningún nodo hijo, una ruta es esencialmente el índice de la fila a la
que desea acceder.
# Get path pointing to 6th row in list store
path = Gtk.TreePath(5)
treeiter = liststore.get_iter(path)
# Get value at 2nd column
value = liststore.get_value(treeiter, 1)
En el caso de Gtk.TreeStore, una ruta es una lista de índices o una cadena. La forma de cadena es
una lista de números separados por dos puntos. Cada número se refiere al desplazamiento en ese nivel.
Por lo tanto, la ruta "0" se refiere al nodo raíz y la ruta "2: 4" se refiere al quinto hijo del tercer nodo.
# Get path pointing to 5th child of 3rd row in tree store
path = Gtk.TreePath([2, 4])
treeiter = treestore.get_iter(path)
# Get value at 2nd column
value = treestore.get_value(treeiter, 1)
13.2. La vista
Si bien hay varios modelos diferentes para elegir, solo hay un widget de vista con el que lidiar.
Funciona con la lista o con la tienda de árboles. Configurar un Gtk.TreeViewno es un asunto difícil.
Necesita Gtk.TreeModelsaber de dónde recuperar sus datos, ya sea pasándolos al
Gtk.TreeViewconstructor o llamando Gtk.TreeView.set_model().
tree = Gtk.TreeView(model=store)
Una vez que el Gtk.TreeViewwidget tiene un modelo, necesitará saber cómo mostrar el modelo.
Hace esto con columnas y renderizadores de celdas. headers_visiblecontrola si muestra
encabezados de columna.
Los renderizadores de celdas se utilizan para dibujar los datos en el modelo de árbol de una manera
específica. Hay varios procesadores de celdas que vienen con GTK +, por ejemplo
Gtk.CellRendererText, Gtk.CellRendererPixbufy Gtk.CellRendererToggle.
Además, es relativamente fácil escribir un renderizador personalizado usted mismo subclasificando a
Gtk.CellRenderery agregando propiedades con GObject.Property().
Para representar más de una columna de modelo en una columna de vista, debe crear una
Gtk.TreeViewColumninstancia y usarla Gtk.TreeViewColumn.pack_start()para
agregarle las columnas del modelo.
column = Gtk.TreeViewColumn("Title and Author")
title = Gtk.CellRendererText()
author = Gtk.CellRendererText()
column.pack_start(title, True)
column.pack_start(author, True)
column.add_attribute(title, "text", 0)
column.add_attribute(author, "text", 1)
tree.append_column(column)
13.3. La selección
La mayoría de las aplicaciones no solo deberán ocuparse de mostrar datos, sino también de recibir
eventos de entrada de los usuarios. Para hacer esto, simplemente obtenga una referencia a un objeto de
selección y conéctese a la señal "cambiada".
select = tree.get_selection()
select.connect("changed", on_tree_selection_changed)
13.4. Clasificación
La clasificación es una característica importante para las vistas de árbol y es compatible con los
modelos de árbol estándar ( Gtk.TreeStorey Gtk.ListStore), que implementan la
Gtk.TreeSortableinterfaz.
13.4.1. Ordenar haciendo clic en columnas
Una columna de una Gtk.TreeViewlata que se puede ordenar fácilmente con una llamada a
Gtk.TreeViewColumn.set_sort_column_id(). Posteriormente, la columna se puede
ordenar haciendo clic en su encabezado.
Primero necesitamos un modelo simple Gtk.TreeViewy Gtk.ListStore.
model = Gtk.ListStore(str)
model.append(["Benjamin"])
model.append(["Charles"])
model.append(["alfred"])
model.append(["Alfred"])
model.append(["David"])
model.append(["charles"])
model.append(["david"])
model.append(["benjamin"])
treeView = Gtk.TreeView(model=model)
cellRenderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Title", renderer, text=0)
El siguiente paso es habilitar la clasificación. Tenga en cuenta que column_id ( 0en el ejemplo) se
refiere a la columna del modelo y no a la columna de TreeView.
column.set_sort_column_id(0)
13.5. Filtración
A diferencia de la clasificación, el filtrado no lo manejan los dos modelos que vimos anteriormente,
sino la Gtk.TreeModelFilterclase. Esta clase, como Gtk.TreeStorey Gtk.ListStore, es
una Gtk.TreeModel. Actúa como una capa entre el modelo "real" (a Gtk.TreeStoreo a
Gtk.ListStore), ocultando algunos elementos a la vista. En la práctica, proporciona
Gtk.TreeViewun subconjunto del modelo subyacente. Las instancias de
Gtk.TreeModelFilterpueden apilarse una sobre otra, para usar múltiples filtros en el mismo
modelo (de la misma manera que usaría cláusulas “Y” en una solicitud SQL). También se pueden
encadenar con Gtk.TreeModelSortinstancias.
Puede crear una nueva instancia de a Gtk.TreeModelFiltery darle un modelo para filtrar, pero la
forma más fácil es generarlo directamente desde el modelo filtrado, usando el
Gtk.TreeModel.filter_new()método.
filter = model.filter_new()
La alternativa a una función de "visibilidad" es utilizar una columna booleana en el modelo para
especificar qué filas filtrar. Elija con qué columna
Gtk.TreeModelFilter.set_visible_column().
Veamos un ejemplo completo que usa la pila Gtk.ListStore- Gtk.TreeModelFilter-
Gtk.TreeModelFilter- completa Gtk.TreeView.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
# list of tuples for each software, containing the software name, initial release,
and main programming languages used
software_list = [
("Firefox", 2002, "C++"),
("Eclipse", 2004, "Java"),
("Pitivi", 2004, "Python"),
("Netbeans", 1996, "Java"),
("Chrome", 2008, "C++"),
("Filezilla", 2001, "C++"),
("Bazaar", 2005, "Python"),
("Git", 2005, "C"),
("Linux Kernel", 1991, "C"),
("GCC", 1987, "C"),
("Frostwire", 2004, "Java"),
]
class TreeViewFilterWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Treeview Filter Demo")
self.set_border_width(10)
# creating the treeview, making it use the filter as a model, and adding
the columns
self.treeview = Gtk.TreeView(model=self.language_filter)
for i, column_title in enumerate(
["Software", "Release Year", "Programming Language"]
):
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(column_title, renderer, text=i)
self.treeview.append_column(column)
self.show_all()
win = TreeViewFilterWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
14. CellRenderers
Gtk.CellRendererLos widgets se utilizan para mostrar información dentro de widgets como
Gtk.TreeViewo Gtk.ComboBox. Trabajan en estrecha colaboración con los widgets asociados y
son muy potentes, con muchas opciones de configuración para mostrar una gran cantidad de datos de
diferentes formas. Hay siete Gtk.CellRendererwidgets que se pueden utilizar para diferentes
propósitos:
• Gtk.CellRendererText
• Gtk.CellRendererToggle
• Gtk.CellRendererPixbuf
• Gtk.CellRendererCombo
• Gtk.CellRendererProgress
• Gtk.CellRendererSpinner
• Gtk.CellRendererSpin
• Gtk.CellRendererAccel
14.1. CellRendererText
A Gtk.CellRendererTextrepresenta un texto determinado en su celda, utilizando la fuente, el
color y la información de estilo proporcionada por sus propiedades. El texto se elipsará si es demasiado
largo y la propiedad "ellipsize" lo permite.
De forma predeterminada, el texto de los Gtk.CellRendererTextwidgets no se puede editar. Esto
se puede cambiar estableciendo el valor de la propiedad "editable" en True:
cell.set_property("editable", True)
14.1.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class CellRendererTextWindow(Gtk.Window):
def __init__(self):
super().__init__(title="CellRendererText Example")
self.set_default_size(200, 200)
treeview = Gtk.TreeView(model=self.liststore)
renderer_text = Gtk.CellRendererText()
column_text = Gtk.TreeViewColumn("Text", renderer_text, text=0)
treeview.append_column(column_text)
renderer_editabletext = Gtk.CellRendererText()
renderer_editabletext.set_property("editable", True)
column_editabletext = Gtk.TreeViewColumn(
"Editable Text", renderer_editabletext, text=1
)
treeview.append_column(column_editabletext)
renderer_editabletext.connect("edited", self.text_edited)
self.add(treeview)
win = CellRendererTextWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
14.2. CellRendererToggle
Gtk.CellRendererTogglerenderiza un botón de alternancia en una celda. El botón se dibuja
como un botón de radio o de control, según la propiedad de "radio". Cuando se activa, emite la señal
"conmutada".
Como Gtk.CellRendererTogglepuede tener dos estados, activo y no activo, lo más probable es
que desee vincular la propiedad "activa" en el renderizador de celda a un valor booleano en el modelo,
haciendo que el botón de verificación refleje el estado del modelo.
14.2.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class CellRendererToggleWindow(Gtk.Window):
def __init__(self):
super().__init__(title="CellRendererToggle Example")
self.set_default_size(200, 200)
treeview = Gtk.TreeView(model=self.liststore)
renderer_text = Gtk.CellRendererText()
column_text = Gtk.TreeViewColumn("Text", renderer_text, text=0)
treeview.append_column(column_text)
renderer_toggle = Gtk.CellRendererToggle()
renderer_toggle.connect("toggled", self.on_cell_toggled)
renderer_radio = Gtk.CellRendererToggle()
renderer_radio.set_radio(True)
renderer_radio.connect("toggled", self.on_cell_radio_toggled)
self.add(treeview)
win = CellRendererToggleWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
14.3. CellRendererPixbuf
Se Gtk.CellRendererPixbufpuede usar para renderizar una imagen en una celda. Permite
renderizar un Gdk.Pixbuficono dado (establecido a través de la propiedad “pixbuf”) o un icono con
nombre (establecido a través de la propiedad “icon-name”).
14.3.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class CellRendererPixbufWindow(Gtk.Window):
def __init__(self):
super().__init__(title="CellRendererPixbuf Example")
self.set_default_size(200, 200)
treeview = Gtk.TreeView(model=self.liststore)
renderer_text = Gtk.CellRendererText()
column_text = Gtk.TreeViewColumn("Text", renderer_text, text=0)
treeview.append_column(column_text)
renderer_pixbuf = Gtk.CellRendererPixbuf()
self.add(treeview)
win = CellRendererPixbufWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
14.4. CellRendererCombo
Gtk.CellRendererComborenderiza texto en una celda como Gtk.CellRendererTextde la
que se deriva. Pero mientras que este último ofrece una entrada simple para editar el texto,
Gtk.CellRendererComboofrece un Gtk.ComboBoxwidget para editar el texto. Los valores que
se muestran en el cuadro combinado se toman de los Gtk.TreeModelespecificados en la propiedad
"modelo".
El renderizador de celda combinado se encarga de agregar un renderizador de celda de texto al cuadro
combinado y lo configura para que muestre la columna especificada por su propiedad "columna de
texto".
A Gtk.CellRendererCombopuede funcionar en dos modos. Se puede utilizar con y sin un
Gtk.Entrywidget asociado , dependiendo del valor de la propiedad "has-entry".
14.4.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class CellRendererComboWindow(Gtk.Window):
def __init__(self):
super().__init__(title="CellRendererCombo Example")
self.set_default_size(200, 200)
liststore_manufacturers = Gtk.ListStore(str)
manufacturers = ["Sony", "LG", "Panasonic", "Toshiba", "Nokia", "Samsung"]
for item in manufacturers:
liststore_manufacturers.append([item])
treeview = Gtk.TreeView(model=self.liststore_hardware)
renderer_text = Gtk.CellRendererText()
column_text = Gtk.TreeViewColumn("Text", renderer_text, text=0)
treeview.append_column(column_text)
renderer_combo = Gtk.CellRendererCombo()
renderer_combo.set_property("editable", True)
renderer_combo.set_property("model", liststore_manufacturers)
renderer_combo.set_property("text-column", 0)
renderer_combo.set_property("has-entry", False)
renderer_combo.connect("edited", self.on_combo_changed)
self.add(treeview)
win = CellRendererComboWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
14.5. CellRendererProgress
Gtk.CellRendererProgressmuestra un valor numérico como una barra de progreso en una
celda. Además, puede mostrar un texto en la parte superior de la barra de progreso.
El valor porcentual de la barra de progreso se puede modificar cambiando la propiedad "valor". De
manera similar Gtk.ProgressBar, puede habilitar el modo de actividad incrementando la
propiedad "pulso" en lugar de la propiedad "valor".
14.5.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
class CellRendererProgressWindow(Gtk.Window):
def __init__(self):
super().__init__(title="CellRendererProgress Example")
self.set_default_size(200, 200)
treeview = Gtk.TreeView(model=self.liststore)
renderer_text = Gtk.CellRendererText()
column_text = Gtk.TreeViewColumn("Text", renderer_text, text=0)
treeview.append_column(column_text)
renderer_progress = Gtk.CellRendererProgress()
column_progress = Gtk.TreeViewColumn(
"Progress", renderer_progress, value=1, inverted=2
)
treeview.append_column(column_progress)
renderer_toggle = Gtk.CellRendererToggle()
renderer_toggle.connect("toggled", self.on_inverted_toggled)
column_toggle = Gtk.TreeViewColumn("Inverted", renderer_toggle, active=2)
treeview.append_column(column_toggle)
self.add(treeview)
self.timeout_id = GLib.timeout_add(100, self.on_timeout, None)
self.liststore[self.current_iter][1] = new_value
return True
def reset_model(self):
for row in self.liststore:
row[1] = 0
self.current_iter = self.liststore.get_iter_first()
win = CellRendererProgressWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
14.6. CellRendererSpin
Gtk.CellRendererSpinrenderiza texto en una celda como Gtk.CellRendererTextde la que
se deriva. Pero mientras que este último ofrece una entrada sencilla para editar el texto,
Gtk.CellRendererSpinofrece un Gtk.SpinButtonwidget. Por supuesto, eso significa que el
texto debe poder analizarse como un número de punto flotante.
El rango del botón giratorio se toma de la propiedad de ajuste del renderizador de celdas, que se puede
establecer explícitamente o mapear a una columna en el modelo de árbol, como todas las propiedades
de los renderizados de celdas. Gtk.CellRendererSpintambién tiene propiedades para la
velocidad de ascenso y el número de dígitos que se mostrarán.
14.6.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class CellRendererSpinWindow(Gtk.Window):
def __init__(self):
super().__init__(title="CellRendererSpin Example")
self.set_default_size(200, 200)
treeview = Gtk.TreeView(model=self.liststore)
renderer_text = Gtk.CellRendererText()
column_text = Gtk.TreeViewColumn("Fruit", renderer_text, text=0)
treeview.append_column(column_text)
renderer_spin = Gtk.CellRendererSpin()
renderer_spin.connect("edited", self.on_amount_edited)
renderer_spin.set_property("editable", True)
adjustment = Gtk.Adjustment(
value=0,
lower=0,
upper=100,
step_increment=1,
page_increment=10,
page_size=0,
)
renderer_spin.set_property("adjustment", adjustment)
self.add(treeview)
win = CellRendererSpinWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
15. ComboBox
A Gtk.ComboBoxpermite la selección de un elemento de un menú desplegable. Son preferibles a
tener muchos botones de opción en la pantalla, ya que ocupan menos espacio. Si corresponde, puede
mostrar información adicional sobre cada elemento, como texto, una imagen, una casilla de
verificación o una barra de progreso.
Gtk.ComboBoxes muy similar a Gtk.TreeView, ya que ambos usan el patrón de vista de modelo;
la lista de opciones válidas se especifica en forma de modelo de árbol, y la visualización de las
opciones se puede adaptar a los datos del modelo mediante el uso de renderizadores de celdas . Si el
cuadro combinado contiene una gran cantidad de elementos, puede ser mejor mostrarlos en una
cuadrícula en lugar de una lista. Esto se puede hacer llamando
Gtk.ComboBox.set_wrap_width().
Para obtener una lista simple de opciones textuales, la API de vista de modelo de
Gtk.ComboBoxpuede ser un poco abrumadora. En este caso, Gtk.ComboBoxTextofrece una
alternativa sencilla. Ambos Gtk.ComboBoxy Gtk.ComboBoxTextpueden contener una entrada.
15.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class ComboBoxWindow(Gtk.Window):
def __init__(self):
super().__init__(title="ComboBox Example")
self.set_border_width(10)
name_combo = Gtk.ComboBox.new_with_model_and_entry(name_store)
name_combo.connect("changed", self.on_name_combo_changed)
name_combo.set_entry_text_column(1)
vbox.pack_start(name_combo, False, False, 0)
country_store = Gtk.ListStore(str)
countries = [
"Austria",
"Brazil",
"Belgium",
"France",
"Germany",
"Switzerland",
"United Kingdom",
"United States of America",
"Uruguay",
]
for country in countries:
country_store.append([country])
country_combo = Gtk.ComboBox.new_with_model(country_store)
country_combo.connect("changed", self.on_country_combo_changed)
renderer_text = Gtk.CellRendererText()
country_combo.pack_start(renderer_text, True)
country_combo.add_attribute(renderer_text, "text", 0)
vbox.pack_start(country_combo, False, False, True)
currencies = [
"Euro",
"US Dollars",
"British Pound",
"Japanese Yen",
"Russian Ruble",
"Mexican peso",
"Swiss franc",
]
currency_combo = Gtk.ComboBoxText()
currency_combo.set_entry_text_column(0)
currency_combo.connect("changed", self.on_currency_combo_changed)
for currency in currencies:
currency_combo.append_text(currency)
currency_combo.set_active(0)
vbox.pack_start(currency_combo, False, False, 0)
self.add(vbox)
win = ComboBoxWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
16. IconView
A Gtk.IconViewes un widget que muestra una colección de iconos en una vista de cuadrícula.
Admite funciones como arrastrar y soltar, selecciones múltiples y reordenación de elementos.
De manera similar a Gtk.TreeView, Gtk.IconViewusa a Gtk.ListStorepara su modelo. En
lugar de usar renderizadores de celdas , Gtk.IconViewrequiere que una de las columnas en su
Gtk.ListStorecontiene GdkPixbuf.Pixbufobjetos.
16.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from gi.repository.GdkPixbuf import Pixbuf
class IconViewWindow(Gtk.Window):
def __init__(self):
super().__init__()
self.set_default_size(200, 200)
self.add(iconview)
win = IconViewWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
17.1. La vista
El Gtk.TextViewes la interfaz con la que el usuario puede añadir, editar y borrar los datos textuales.
Suelen utilizarse para editar varias líneas de texto. Al crear un Gtk.TextView, contiene su propio
valor predeterminado Gtk.TextBuffer, al que puede acceder a través del
Gtk.TextView.get_buffer()método.
De forma predeterminada, se puede agregar, editar y eliminar texto del archivo Gtk.TextView.
Puede desactivar esto llamando Gtk.TextView.set_editable(). Si el texto no es editable,
normalmente también querrá ocultar el cursor de texto con
Gtk.TextView.set_cursor_visible(). En algunos casos puede resultar útil establecer la
justificación del texto con Gtk.TextView.set_justification(). El texto se puede mostrar
en el borde izquierdo, ( Gtk.Justification.LEFT), en el borde derecho (
Gtk.Justification.RIGHT), centrado ( Gtk.Justification.CENTER) o distribuido en
todo el ancho ( Gtk.Justification.FILL).
Otra configuración predeterminada del Gtk.TextViewwidget es que las líneas largas de texto
continuarán horizontalmente hasta que se ingrese una pausa. Para ajustar el texto y evitar que se salga
de los bordes de la pantalla, llame Gtk.TextView.set_wrap_mode().
17.2. El modelo
El Gtk.TextBufferes el núcleo del Gtk.TextViewwidget y se usa para contener cualquier texto
que se muestre en el Gtk.TextView. Es posible configurar y recuperar el contenido con
Gtk.TextBuffer.set_text()y Gtk.TextBuffer.get_text(). Sin embargo, la mayor
parte de la manipulación de texto se realiza con iteradores , representados por un Gtk.TextIter.
Un iterador representa una posición entre dos caracteres en el búfer de texto. Los iteradores no son
válidos indefinidamente; siempre que el búfer se modifica de una manera que afecte al contenido del
búfer, todos los iteradores pendientes se vuelven inválidos.
Debido a esto, los iteradores no se pueden usar para conservar posiciones en las modificaciones del
búfer. Para conservar una posición, utilice Gtk.TextMark. Un búfer de texto contiene dos marcas
integradas; una marca de "inserción" (que es la posición del cursor) y la marca de "selección_definida".
Ambos se pueden recuperar usando Gtk.TextBuffer.get_insert()y
Gtk.TextBuffer.get_selection_bound(), respectivamente. De forma predeterminada,
Gtk.TextMarkno se muestra la ubicación de a . Esto se puede cambiar llamando
Gtk.TextMark.set_visible().
Para insertar texto en una posición específica, utilice Gtk.TextBuffer.insert(). Otro método
útil es el Gtk.TextBuffer.insert_at_cursor()que inserta texto dondequiera que esté
posicionado el cursor. Para eliminar partes del búfer de texto, utilice
Gtk.TextBuffer.delete().
Además, Gtk.TextIterse puede utilizar para localizar coincidencias textuales en el búfer utilizando
Gtk.TextIter.forward_search()y Gtk.TextIter.backward_search(). Los índices
de inicio y finalización se utilizan como punto de partida de la búsqueda y se mueven hacia adelante o
hacia atrás según los requisitos.
17.3. Etiquetas
El texto de un búfer se puede marcar con etiquetas. Una etiqueta es un atributo que se puede aplicar a
algún rango de texto. Por ejemplo, una etiqueta puede llamarse "negrita" y hacer que el texto dentro de
la etiqueta esté en negrita. Sin embargo, el concepto de etiqueta es más general que eso; las etiquetas no
tienen por qué afectar la apariencia. En cambio, pueden afectar el comportamiento de las pulsaciones
del ratón y las teclas, "bloquear" un rango de texto para que el usuario no pueda editarlo, o muchas
otras cosas. Una etiqueta está representada por un Gtk.TextTagobjeto. Se Gtk.TextTagpuede
aplicar uno a cualquier número de rangos de texto en cualquier número de búferes.
Cada etiqueta se almacena en un archivo Gtk.TextTagTable. Una tabla de etiquetas define un
conjunto de etiquetas que se pueden usar juntas. Cada búfer tiene una tabla de etiquetas asociada; solo
las etiquetas de esa tabla de etiquetas se pueden usar con el búfer. Sin embargo, una sola tabla de
etiquetas se puede compartir entre varios búferes.
Para especificar que algún texto en el búfer debe tener un formato específico, debe definir una etiqueta
para contener esa información de formato y luego aplicar esa etiqueta a la región del texto usando
Gtk.TextBuffer.create_tag()y Gtk.TextBuffer.apply_tag():
tag = textbuffer.create_tag("orange_bg", background="orange")
textbuffer.apply_tag(tag, start_iter, end_iter)
Los siguientes son algunos de los estilos comunes que se aplican al texto:
• Color de fondo (propiedad "background")
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Pango
class SearchDialog(Gtk.Dialog):
def __init__(self, parent):
super().__init__(title="Search", transient_for=parent, modal=True)
self.add_buttons(
Gtk.STOCK_FIND,
Gtk.ResponseType.OK,
Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
)
box = self.get_content_area()
self.entry = Gtk.Entry()
box.add(self.entry)
self.show_all()
class TextViewWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="TextView Example")
self.set_default_size(-1, 350)
self.grid = Gtk.Grid()
self.add(self.grid)
self.create_textview()
self.create_toolbar()
self.create_buttons()
def create_toolbar(self):
toolbar = Gtk.Toolbar()
self.grid.attach(toolbar, 0, 0, 3, 1)
button_bold = Gtk.ToolButton()
button_bold.set_icon_name("format-text-bold-symbolic")
toolbar.insert(button_bold, 0)
button_italic = Gtk.ToolButton()
button_italic.set_icon_name("format-text-italic-symbolic")
toolbar.insert(button_italic, 1)
button_underline = Gtk.ToolButton()
button_underline.set_icon_name("format-text-underline-symbolic")
toolbar.insert(button_underline, 2)
toolbar.insert(Gtk.SeparatorToolItem(), 3)
radio_justifyleft = Gtk.RadioToolButton()
radio_justifyleft.set_icon_name("format-justify-left-symbolic")
toolbar.insert(radio_justifyleft, 4)
radio_justifycenter =
Gtk.RadioToolButton.new_from_widget(radio_justifyleft)
radio_justifycenter.set_icon_name("format-justify-center-symbolic")
toolbar.insert(radio_justifycenter, 5)
radio_justifyright = Gtk.RadioToolButton.new_from_widget(radio_justifyleft)
radio_justifyright.set_icon_name("format-justify-right-symbolic")
toolbar.insert(radio_justifyright, 6)
radio_justifyfill = Gtk.RadioToolButton.new_from_widget(radio_justifyleft)
radio_justifyfill.set_icon_name("format-justify-fill-symbolic")
toolbar.insert(radio_justifyfill, 7)
radio_justifyleft.connect(
"toggled", self.on_justify_toggled, Gtk.Justification.LEFT
)
radio_justifycenter.connect(
"toggled", self.on_justify_toggled, Gtk.Justification.CENTER
)
radio_justifyright.connect(
"toggled", self.on_justify_toggled, Gtk.Justification.RIGHT
)
radio_justifyfill.connect(
"toggled", self.on_justify_toggled, Gtk.Justification.FILL
)
toolbar.insert(Gtk.SeparatorToolItem(), 8)
button_clear = Gtk.ToolButton()
button_clear.set_icon_name("edit-clear-symbolic")
button_clear.connect("clicked", self.on_clear_clicked)
toolbar.insert(button_clear, 9)
toolbar.insert(Gtk.SeparatorToolItem(), 10)
button_search = Gtk.ToolButton()
button_search.set_icon_name("system-search-symbolic")
button_search.connect("clicked", self.on_search_clicked)
toolbar.insert(button_search, 11)
def create_textview(self):
scrolledwindow = Gtk.ScrolledWindow()
scrolledwindow.set_hexpand(True)
scrolledwindow.set_vexpand(True)
self.grid.attach(scrolledwindow, 0, 1, 3, 1)
self.textview = Gtk.TextView()
self.textbuffer = self.textview.get_buffer()
self.textbuffer.set_text(
"This is some text inside of a Gtk.TextView. "
+ "Select text and click one of the buttons 'bold', 'italic', "
+ "or 'underline' to modify the text accordingly."
)
scrolledwindow.add(self.textview)
self.tag_bold = self.textbuffer.create_tag("bold",
weight=Pango.Weight.BOLD)
self.tag_italic = self.textbuffer.create_tag("italic",
style=Pango.Style.ITALIC)
self.tag_underline = self.textbuffer.create_tag(
"underline", underline=Pango.Underline.SINGLE
)
self.tag_found = self.textbuffer.create_tag("found", background="yellow")
def create_buttons(self):
check_editable = Gtk.CheckButton(label="Editable")
check_editable.set_active(True)
check_editable.connect("toggled", self.on_editable_toggled)
self.grid.attach(check_editable, 0, 2, 1, 1)
radio_wrapchar = Gtk.RadioButton.new_with_label_from_widget(
radio_wrapnone, "Character Wrapping"
)
self.grid.attach_next_to(
radio_wrapchar, radio_wrapnone, Gtk.PositionType.RIGHT, 1, 1
)
radio_wrapword = Gtk.RadioButton.new_with_label_from_widget(
radio_wrapnone, "Word Wrapping"
)
self.grid.attach_next_to(
radio_wrapword, radio_wrapchar, Gtk.PositionType.RIGHT, 1, 1
)
self.search_and_mark(dialog.entry.get_text(), start)
dialog.destroy()
win = TextViewWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
18. Diálogos
Las ventanas de diálogo son muy similares a las ventanas estándar y se utilizan para proporcionar o
recuperar información del usuario. A menudo se utilizan para proporcionar una ventana de preferencias,
por ejemplo. La principal diferencia que tiene un cuadro de diálogo son algunos widgets
preempaquetados que distribuyen el cuadro de diálogo automáticamente. A partir de ahí, simplemente
podemos agregar etiquetas, botones, botones de verificación, etc. Otra gran diferencia es el manejo de
las respuestas para controlar cómo debe comportarse la aplicación después de interactuar con el
diálogo.
Hay varias clases de diálogo derivadas que pueden resultarle útiles. Gtk.MessageDialogse utiliza
para las notificaciones más sencillas. Pero en otras ocasiones, es posible que deba derivar su propia
clase de diálogo para proporcionar una funcionalidad más compleja.
Se puede crear un diálogo 'modal' (es decir, uno que congela el resto de la aplicación desde la entrada
del usuario) llamando Gtk.Dialog.set_modalal diálogo o estableciendo el flagsargumento del
Gtk.Dialogconstructor para incluir la Gtk.DialogFlags.MODALbandera.
Al hacer clic en un botón se emitirá una señal llamada "respuesta". Si desea bloquear la espera de que
regrese un cuadro de diálogo antes de devolver el flujo de control a su código, puede llamar
Gtk.Dialog.run(). Este método devuelve un int que puede ser un valor de
Gtk.ResponseTypeo podría ser el valor de respuesta personalizado que especificó en el
Gtk.Dialogconstructor o Gtk.Dialog.add_button().
18.1.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class DialogExample(Gtk.Dialog):
def __init__(self, parent):
super().__init__(title="My Dialog", transient_for=parent, flags=0)
self.add_buttons(
Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK
)
self.set_default_size(150, 100)
box = self.get_content_area()
box.add(label)
self.show_all()
class DialogWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Dialog Example")
self.set_border_width(6)
self.add(button)
if response == Gtk.ResponseType.OK:
print("The OK button was clicked")
elif response == Gtk.ResponseType.CANCEL:
print("The Cancel button was clicked")
dialog.destroy()
win = DialogWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
18.2. MessageDialog
Gtk.MessageDialoges una clase de conveniencia, que se utiliza para crear diálogos de mensajes
estándar y sencillos, con un mensaje, un icono y botones para la respuesta del usuario. Puede
especificar el tipo de mensaje y el texto en el Gtk.MessageDialogconstructor, así como especificar
botones estándar.
En algunos diálogos que requieren una explicación más detallada de lo que ha sucedido, se puede
agregar un texto secundario. En este caso, el mensaje principal introducido al crear el cuadro de diálogo
del mensaje se agranda y se pone en negrita. El mensaje secundario se puede configurar llamando
Gtk.MessageDialog.format_secondary_text().
18.2.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MessageDialogWindow(Gtk.Window):
def __init__(self):
super().__init__(title="MessageDialog Example")
box = Gtk.Box(spacing=6)
self.add(box)
button1 = Gtk.Button(label="Information")
button1.connect("clicked", self.on_info_clicked)
box.add(button1)
button2 = Gtk.Button(label="Error")
button2.connect("clicked", self.on_error_clicked)
box.add(button2)
button3 = Gtk.Button(label="Warning")
button3.connect("clicked", self.on_warn_clicked)
box.add(button3)
button4 = Gtk.Button(label="Question")
button4.connect("clicked", self.on_question_clicked)
box.add(button4)
dialog.destroy()
dialog.destroy()
dialog.destroy()
dialog.destroy()
win = MessageDialogWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
18.3. FileChooserDialog
El Gtk.FileChooserDialoges adecuado para usar con los elementos de menú "Archivo / Abrir" o
"Archivo / Guardar". Puede utilizar todos los Gtk.FileChoosermétodos del cuadro de diálogo del
selector de archivos, así como los de Gtk.Dialog.
• Para seleccionar un archivo para abrir, como para un comando Archivo / Abrir, use
Gtk.FileChooserAction.OPEN
• Para guardar un archivo por primera vez, como para un comando Archivo / Guardar,
use Gtk.FileChooserAction.SAVEy sugiera un nombre como "Sin título"
con Gtk.FileChooser.set_current_name().
• Para guardar un archivo con un nombre diferente, como para un comando Archivo /
Guardar como, use Gtk.FileChooserAction.SAVEy establezca el nombre de
archivo existente con Gtk.FileChooser.set_filename().
• Para elegir una carpeta en lugar de un archivo, use
Gtk.FileChooserAction.SELECT_FOLDER.
• Gtk.ResponseType.OK
• Gtk.ResponseType.YES
• Gtk.ResponseType.APPLY
Cuando el usuario haya terminado de seleccionar archivos, su programa puede obtener los nombres
seleccionados como nombres de archivo ( Gtk.FileChooser.get_filename()) o como URI (
Gtk.FileChooser.get_uri()).
Gtk.FileChooser también admite una variedad de opciones que hacen que los archivos y carpetas
sean más configurables y accesibles.
• Gtk.FileChooser.set_local_only(): Solo se pueden seleccionar
archivos locales.
• Gtk.FileChooser.set_do_overwrite_confirmation(): Si el
selector de archivos se configuró en Gtk.FileChooserAction.SAVEmodo,
presentará un cuadro de diálogo de confirmación si el usuario escribe un nombre de
archivo que ya existe.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class FileChooserWindow(Gtk.Window):
def __init__(self):
super().__init__(title="FileChooser Example")
box = Gtk.Box(spacing=6)
self.add(box)
self.add_filters(dialog)
response = dialog.run()
if response == Gtk.ResponseType.OK:
print("Open clicked")
print("File selected: " + dialog.get_filename())
elif response == Gtk.ResponseType.CANCEL:
print("Cancel clicked")
dialog.destroy()
filter_py = Gtk.FileFilter()
filter_py.set_name("Python files")
filter_py.add_mime_type("text/x-python")
dialog.add_filter(filter_py)
filter_any = Gtk.FileFilter()
filter_any.set_name("Any files")
filter_any.add_pattern("*")
dialog.add_filter(filter_any)
response = dialog.run()
if response == Gtk.ResponseType.OK:
print("Select clicked")
print("Folder selected: " + dialog.get_filename())
elif response == Gtk.ResponseType.CANCEL:
print("Cancel clicked")
dialog.destroy()
win = FileChooserWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
19. Popovers
El Gtk.Popoveres una ventana separada se utiliza para mostrar información adicional y, a menudo
se utiliza con los menús de los botones y menús de contexto. Los popovers están conectados
visualmente a un widget relacionado con un pequeño triángulo. Sus usos son similares a los de las
ventanas de diálogo con la ventaja de ser menos disruptivos y tener una conexión con el widget al que
apunta el popover.
Se puede crear un Popover con Gtk.Popover; para abrir el popover use
Gtk.Popover.popup().
19.1.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class PopoverWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Popover Demo")
self.set_border_width(10)
self.set_default_size(300, 200)
self.popover = Gtk.Popover()
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
vbox.pack_start(Gtk.ModelButton(label="Item 1"), False, True, 10)
vbox.pack_start(Gtk.Label(label="Item 2"), False, True, 10)
vbox.show_all()
self.popover.add(vbox)
self.popover.set_position(Gtk.PositionType.BOTTOM)
win = PopoverWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
19.2.1. Ejemplo
import sys
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gio, Gtk
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.set_default_size(300, 200)
button = Gtk.MenuButton(menu_model=menu)
class Application(Gtk.Application):
def __init__(self, *args, **kwargs):
super().__init__(*args, application_id="org.example.myapp", **kwargs)
self.window = None
def do_startup(self):
Gtk.Application.do_startup(self)
action = Gio.SimpleAction(name="about")
action.connect("activate", self.on_about)
self.add_action(action)
action = Gio.SimpleAction(name="quit")
action.connect("activate", self.on_quit)
self.add_action(action)
def do_activate(self):
# We only allow a single window and raise any existing ones
if not self.window:
# Windows are associated with the application
# when the last one is closed the application shuts down
self.window = AppWindow(application=self, title="Main Window")
self.window.present()
if __name__ == "__main__":
app = Application()
app.run(sys.argv)
20. Portapapeles
Gtk.Clipboardproporciona un área de almacenamiento para una variedad de datos, incluidos texto
e imágenes. El uso de un portapapeles permite que estos datos se compartan entre aplicaciones a través
de acciones como copiar, cortar y pegar. Estas acciones generalmente se realizan de tres maneras:
usando atajos de teclado, usando a Gtk.MenuItem, y conectando las funciones a los
Gtk.Buttonwidgets.
Hay varias selecciones de portapapeles para diferentes propósitos. En la mayoría de las circunstancias,
la selección nombrada CLIPBOARDse utiliza para copiar y pegar todos los días. PRIMARYes otra
selección común que almacena texto seleccionado por el usuario con el cursor.
20.1. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
class ClipboardWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Clipboard Example")
grid = Gtk.Grid()
self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
self.entry = Gtk.Entry()
self.image = Gtk.Image.new_from_icon_name("process-stop",
Gtk.IconSize.MENU)
grid.add(self.entry)
grid.attach(self.image, 0, 1, 1, 1)
grid.attach(button_copy_text, 1, 0, 1, 1)
grid.attach(button_paste_text, 2, 0, 1, 1)
grid.attach(button_copy_image, 1, 1, 1, 1)
grid.attach(button_paste_image, 2, 1, 1, 1)
button_copy_text.connect("clicked", self.copy_text)
button_paste_text.connect("clicked", self.paste_text)
button_copy_image.connect("clicked", self.copy_image)
button_paste_image.connect("clicked", self.paste_image)
self.add(grid)
win = ClipboardWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
21. Arrastrar y soltar
Nota
Las versiones de PyGObject <3.0.3 contienen un error que no permite que la función de arrastrar y
soltar funcione correctamente. Por lo tanto, se requiere una versión de PyGObject> = 3.0.3 para que
funcionen los siguientes ejemplos.
La configuración de arrastrar y soltar entre widgets consiste en seleccionar una fuente de arrastre (el
widget desde el que el usuario comienza a arrastrar) con el
Gtk.Widget.drag_source_set()método, seleccionar un destino de arrastre (el widget en el
que el usuario coloca) con el Gtk.Widget.drag_dest_set()método y luego manejar las señales
relevantes en ambos widgets.
En lugar de usar Gtk.Widget.drag_source_set()y
Gtk.Widget.drag_dest_set()algunos widgets especializados requieren el uso de funciones
específicas (como Gtk.TreeViewy Gtk.IconView).
Un arrastrar y soltar básico solo requiere que la fuente se conecte a la señal "arrastrar-obtener-datos-
obtener" y el destino para conectarse a la señal "arrastrar-datos-recibidos". Cosas más complejas, como
áreas de colocación específicas e íconos de arrastre personalizados, requerirán que se conecte a señales
adicionales e interactúe con el Gdk.DragContextobjeto que proporciona.
Si necesita más de un tipo de datos o desea hacer cosas más complejas con los datos, deberá crearlos
Gtk.TargetEntry'sutilizando el Gtk.TargetEntry.new()método.
movimiento de El icono de arrastre se mueve sobre un Permita que solo se dejen caer en
arrastre área de colocación ciertas áreas
21.4. Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GdkPixbuf
DRAG_ACTION = Gdk.DragAction.COPY
class DragDropWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Drag and Drop Demo")
hbox = Gtk.Box(spacing=12)
vbox.pack_start(hbox, True, True, 0)
self.iconview = DragSourceIconView()
self.drop_area = DropArea()
button_box = Gtk.Box(spacing=6)
vbox.pack_start(button_box, True, False, 0)
text_button = Gtk.RadioButton.new_with_label_from_widget(image_button,
"Text")
text_button.connect("toggled", self.add_text_targets)
button_box.pack_start(text_button, True, False, 0)
self.add_image_targets()
self.drop_area.drag_dest_set_target_list(targets)
self.iconview.drag_source_set_target_list(targets)
self.drop_area.drag_dest_add_text_targets()
self.iconview.drag_source_add_text_targets()
class DragSourceIconView(Gtk.IconView):
def __init__(self):
Gtk.IconView.__init__(self)
self.set_text_column(COLUMN_TEXT)
self.set_pixbuf_column(COLUMN_PIXBUF)
self.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [],
DRAG_ACTION)
self.connect("drag-data-get", self.on_drag_data_get)
if info == TARGET_ENTRY_TEXT:
text = self.get_model().get_value(selected_iter, COLUMN_TEXT)
data.set_text(text, -1)
elif info == TARGET_ENTRY_PIXBUF:
pixbuf = self.get_model().get_value(selected_iter, COLUMN_PIXBUF)
data.set_pixbuf(pixbuf)
class DropArea(Gtk.Label):
def __init__(self):
Gtk.Label.__init__(self)
self.set_label("Drop something on me!")
self.drag_dest_set(Gtk.DestDefaults.ALL, [], DRAG_ACTION)
self.connect("drag-data-received", self.on_drag_data_received)
win = DragDropWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
22. Glade y Gtk.Builder
La Gtk.Builderclase le ofrece la oportunidad de diseñar interfaces de usuario sin escribir una sola
línea de código. Esto se logra definiendo la interfaz en un archivo XML y luego cargando esa
definición de UI XML en tiempo de ejecución usando la clase Builder que crea los objetos
automáticamente. Para evitar escribir el XML manualmente, use la aplicación Glade que le permite
crear la interfaz de usuario en forma WYSIWYG (lo que ve es lo que obtiene)
Este método tiene varias ventajas:
• Se necesita escribir menos código.
• Los cambios en la interfaz de usuario se pueden ver más rápidamente, por lo que las interfaces
de usuario pueden mejorar.
• Los diseñadores sin conocimientos de programación pueden crear y editar interfaces de usuario.
• La descripción de la interfaz de usuario es independiente del lenguaje de programación
utilizado.
Todavía se requiere código para manejar los cambios de interfaz activados por el usuario, pero le
Gtk.Builderpermite concentrarse en implementar esa funcionalidad.
La segunda línea carga todos los objetos definidos en example.glade en el objeto Builder.
También es posible cargar solo algunos de los objetos. La siguiente línea agregaría solo los objetos (y
sus objetos secundarios) dados en la tupla.
# we don't really have two buttons here, this is just an example
builder.add_objects_from_file("example.glade", ("button1", "button2"))
Estos dos métodos existen también para cargar desde una cadena en lugar de un archivo. Sus nombres
correspondientes son Gtk.Builder.add_from_string()y
Gtk.Builder.add_objects_from_string()y simplemente toman una cadena XML en lugar
de un nombre de archivo.
Ahora tenemos que definir las funciones del controlador en nuestro código. El OnDestroy simplemente
debería resultar en una llamada a Gtk.main_quit(). Cuando se presiona el botón, nos gustaría
imprimir la cadena "¡Hola mundo!", Por lo que definimos el controlador de la siguiente manera
def hello(button):
print("Hello World!")
A continuación, tenemos que conectar las señales y las funciones del controlador. La forma más
sencilla de hacer esto es definir un dictado con un mapeo de los nombres a los manejadores y luego
pasarlo al Gtk.Builder.connect_signals()método.
handlers = {
"onDestroy": Gtk.main_quit,
"onButtonPressed": hello
}
builder.connect_signals(handlers)
Un enfoque alternativo es crear una clase que tenga métodos que se llamen como las señales. En
nuestro ejemplo, el último fragmento de código podría reescribirse como:
class Handler:
def onDestroy(self, *args):
Gtk.main_quit()
22.4. Ejemplo
El código final del ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class Handler:
def onDestroy(self, *args):
Gtk.main_quit()
builder = Gtk.Builder()
builder.add_from_file("builder_example.glade")
builder.connect_signals(Handler())
window = builder.get_object("window1")
window.show_all()
Gtk.main()
22,5. Gtk.Template
Gtk.WidgetClasspermite que los archivos de definición de la interfaz de usuario se utilicen para
extender un widget, PyGObject proporciona Gtk.Template como una forma de acceder a esto desde
Python.
El archivo de definición de IU usado en el ejemplo necesita un pequeño cambio para incluir un
elemento <template> :
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<template class="window1" parent="GtkWindow">
<signal name="destroy" handler="onDestroy" swapped="no"/>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">button</property>
<property name="use-action-appearance">False</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="use-action-appearance">False</property>
<signal name="pressed" handler="onButtonPressed" swapped="no"/>
</object>
</child>
</template>
</interface>
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
@Gtk.Template(filename="template_example.ui")
class Window1(Gtk.Window):
__gtype_name__ = "window1"
@Gtk.Template.Callback()
def onDestroy(self, *args):
Gtk.main_quit()
@Gtk.Template.Callback()
def onButtonPressed(self, button):
print("Hello World!")
window = Window1()
window.show()
Gtk.main()
23. Objetos
GObject es el tipo fundamental que proporciona los atributos y métodos comunes para todos los tipos
de objetos en GTK +, Pango y otras bibliotecas basadas en GObject. La GObject.GObjectclase
proporciona métodos para la construcción y destrucción de objetos, métodos de acceso a la propiedad y
soporte de señales.
Esta sección presenta algunos aspectos importantes sobre la implementación de GObject en Python.
class MyObject(GObject.GObject):
def __init__(self):
GObject.GObject.__init__(self)
23.2. Señales
Las señales conectan eventos arbitrarios específicos de la aplicación con cualquier número de oyentes.
Por ejemplo, en GTK +, cada evento de usuario (pulsación de tecla o movimiento del mouse) se recibe
del servidor X y genera un evento GTK + bajo la forma de una emisión de señal en una instancia de
objeto determinada.
Cada señal se registra en el sistema de tipos junto con el tipo en el que se puede emitir: se dice que los
usuarios del tipo se conectan a la señal en una instancia de tipo dada cuando registran una función para
ser invocada en la emisión de la señal. Los usuarios también pueden emitir la señal por sí mismos o
detener la emisión de la señal desde dentro de una de las funciones conectadas a la señal.
GObject.SIGNAL_RUN_FIRSTindica que esta señal invocará al manejador del método del objeto (
do_my_signal()aquí) en la primera etapa de emisión. Las alternativas son
GObject.SIGNAL_RUN_LAST(el manejador de método se invocará en la tercera etapa de emisión)
e GObject.SIGNAL_RUN_CLEANUP(invocar el manejador de método en la última etapa de
emisión).
La segunda parte, Noneindica el tipo de retorno de la señal, por lo general None.
(int,)indica los argumentos de la señal, aquí, la señal solo tomará un argumento, cuyo tipo es int.
Los tipos de argumentos requeridos por la señal se declaran como una secuencia, aquí es una tupla de
un elemento.
Las señales se pueden emitir usando GObject.GObject.emit():
my_obj.emit("my_signal", 42) # emit the signal "my_signal", with the
# argument 42
23.3. Propiedades
Una de las buenas características de GObject es su mecanismo genérico get / set para las propiedades
de los objetos. Cada clase heredada GObject.GObjectpuede definir nuevas propiedades. Cada
propiedad tiene un tipo que nunca cambia (por ejemplo, str, float, int…). Por ejemplo, se utilizan
Gtk.Buttoncuando hay una propiedad de "etiqueta" que contiene el texto del botón.
Algunas propiedades también tienen funciones dedicadas a ellas, llamadas getter y setter. Para la
propiedad "etiqueta" de un botón, hay dos funciones para obtenerlas y configurarlas,
Gtk.Button.get_label()y Gtk.Button.set_label().
class MyObject(GObject.GObject):
Las propiedades también pueden ser de solo lectura, si desea que algunas propiedades sean legibles
pero no de escritura. Para hacerlo, puede agregar algunos indicadores a la definición de propiedad, para
controlar el acceso de lectura / escritura. Las banderas son
GObject.ParamFlags.READABLE(solo acceso de lectura para código externo),
GObject.ParamFlags.WRITABLE(solo acceso de escritura),
GObject.ParamFlags.READWRITE(público):
foo = GObject.Property(type=str, flags = GObject.ParamFlags.READABLE) # not
writable
bar = GObject.Property(type=str, flags = GObject.ParamFlags.WRITABLE) # not
readable
También puede definir nuevas propiedades de solo lectura con un nuevo método decorado con
GObject.Property:
from gi.repository import GObject
class MyObject(GObject.GObject):
def __init__(self):
GObject.GObject.__init__(self)
@GObject.Property
def readonly(self):
return 'This is read-only.'
Puede obtener esta propiedad usando:
my_object = MyObject()
print(my_object.readonly)
print(my_object.get_property("readonly"))
@GObject.Property
def prop(self):
'Read only property.'
return 1
@GObject.Property(type=int)
def propInt(self):
'Read-write integer property.'
return self.value
@propInt.setter
def propInt(self, value):
self.value = value
También hay una forma de definir valores mínimos y máximos para números, utilizando una forma más
detallada:
from gi.repository import GObject
class MyObject(GObject.GObject):
__gproperties__ = {
"int-prop": (int, # type
"integer prop", # nick
"A property that contains an integer", # blurb
1, # min
5, # max
2, # default
GObject.ParamFlags.READWRITE # flags
),
}
def __init__(self):
GObject.GObject.__init__(self)
self.int_prop = 2
my_object.connect("notify::foo", on_notify_foo)
Tenga en cuenta que debe usar el nombre de la propiedad canónica cuando se conecte a las señales de
notificación, como se explica en GObject.Object.signals.notify(). Por ejemplo, para una
propiedad de Python foo_bar_baz , se conectaría a la señal notificar :: foo-bar-baz usando
my_object = MyObject()
my_object.connect("notify::foo-bar-baz", on_notify_foo_bar_baz)
23.4. API
clase GObject. GObject
get_property ( nombre_propiedad )
Emitir señal nombre_señal . Deben seguir los argumentos de la señal, por ejemplo, si su
señal es de tipo (int,), debe emitirse con:
self.emit(signal_name, 42)
freeze_notify ( )
Este método congela todas las señales de "notificación ::" (que se emiten cuando se cambia
cualquier propiedad) hasta thaw_notify()que se llama al método.
with an_object.freeze_notify():
# Do your work here
...
thaw_notify ( )
Descongele todas las señales de "notificación ::" que fueron congeladas por
freeze_notify().
handler_block ( handler_id )
Bloquea un controlador de una instancia para que no se llame durante ninguna emisión de
señal a menos que handler_unblock()se llame para ese handler_id . Por tanto,
"bloquear" un gestor de señales significa desactivarlo temporalmente, un gestor de señales
debe desbloquearse exactamente la misma cantidad de veces que se bloqueó antes para
volver a activarse.
with an_object.handler_block(handler_id):
# Do your work here
...
handler_unblock ( handler_id )
__gsignals__
Cada elemento del diccionario es una nueva señal. La clave es el nombre de la señal. El
valor es una tupla, con la forma:
(GObject.SIGNAL_RUN_FIRST, None, (int,))
__gproperties__
El valor es una tupla que describe la propiedad. El número de elementos de esta tupla
depende de su primer elemento, pero la tupla siempre contendrá al menos los siguientes
elementos:
La longitud absoluta de la tupla depende del tipo de propiedad (el primer elemento de la
tupla). Así tenemos las siguientes situaciones:
GObject. SIGNAL_RUN_FIRST
Invoque el controlador de método de objeto en la primera etapa de emisión.
GObject. SIGNAL_RUN_LAST
GObject. SIGNAL_RUN_CLEANUP
GObject.ParamFlags. READABLE
La propiedad es legible.
GObject.ParamFlags. WRITABLE
GObject.ParamFlags. READWRITE
24. Aplicación
Gtk.Application abarca muchas tareas repetitivas que necesita una aplicación moderna, como el
manejo de múltiples instancias, activación de D-Bus, apertura de archivos, análisis de línea de
comandos, inicio / apagado, administración de menús, administración de ventanas y más.
24.1. Comportamiento
Gio.Actiones una forma de exponer cualquier tarea individual que realiza su aplicación o widget
por un nombre. Estas acciones se pueden deshabilitar / habilitar en tiempo de ejecución y se pueden
activar o cambiar de estado (si contienen estado).
La razón para usar acciones es separar la lógica de la interfaz de usuario. Por ejemplo, esto permite usar
una barra de menú en OSX y un menú de engranajes en GNOME, ambos simplemente haciendo
referencia al nombre de una acción. La implementación principal de esto que utilizará es la
Gio.SimpleActionque se demostrará más adelante.
24.2. Menús
Sus menús deben estar definidos en XML usando Gio.Menuy harían referencia a las acciones
mencionadas anteriormente que usted definió. Gtk.Applicationle permite configurar un menú
mediante Gtk.Application.set_app_menu()o Gtk.Application.set_menubar(). Si
hace uso de Gio.Resourceesto, puede usar automáticamente el menú correcto según la plataforma;
de lo contrario, puede configurarlos manualmente. A continuación se muestra un ejemplo detallado.
El uso de HANDLES_OPEN hará el trabajo de simplemente tomar los argumentos del archivo por
usted y le permitirá manejarlo Gio.Application.do_open().
Si su aplicación ya está abierta, todos estos se enviarán a la instancia existente, a menos que use
NON_UNIQUE para permitir múltiples instancias.
24,4. Ejemplo
import sys
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import GLib, Gio, Gtk
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# This will be in the windows group and have the "win" prefix
max_action = Gio.SimpleAction.new_stateful(
"maximize", None, GLib.Variant.new_boolean(False)
)
max_action.connect("change-state", self.on_maximize_toggle)
self.add_action(max_action)
class Application(Gtk.Application):
def __init__(self, *args, **kwargs):
super().__init__(
*args,
application_id="org.example.myapp",
flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
**kwargs
)
self.window = None
self.add_main_option(
"test",
ord("t"),
GLib.OptionFlags.NONE,
GLib.OptionArg.NONE,
"Command line test",
None,
)
def do_startup(self):
Gtk.Application.do_startup(self)
def do_activate(self):
# We only allow a single window and raise any existing ones
if not self.window:
# Windows are associated with the application
# when the last one is closed the application shuts down
self.window = AppWindow(application=self, title="Main Window")
self.window.present()
if "test" in options:
# This is printed on the main instance
print("Test argument recieved: %s" % options["test"])
self.activate()
return 0
def on_about(self, action, param):
about_dialog = Gtk.AboutDialog(transient_for=self.window, modal=True)
about_dialog.present()
if __name__ == "__main__":
app = Application()
app.run(sys.argv)
Menús
Nota
Gtk.UIManager, Gtk.Actiony Gtk.ActionGrouphan quedado obsoletos desde GTK +
versión 3.10 y no deberían utilizarse en código recién escrito. En su lugar, utilice el marco de la
aplicación .
GTK + viene con dos tipos diferentes de menús Gtk.MenuBary Gtk.Toolbar. Gtk.MenuBares
una barra de menú estándar que contiene una o más Gtk.MenuIteminstancias o una de sus subclases.
Gtk.ToolbarLos widgets se utilizan para acceder rápidamente a las funciones de uso común de una
aplicación. Los ejemplos incluyen crear un nuevo documento, imprimir una página o deshacer una
operación. Contiene una o más instancias de Gtk.ToolItemo una de sus subclases.
Comportamiento
Aunque existen API específicas para crear menús y barras de herramientas, debe usar
Gtk.UIManagery crear Gtk.Actioninstancias. Las acciones se organizan en grupos. A
Gtk.ActionGroupes esencialmente un mapa de nombres a Gtk.Actionobjetos. Todas las
acciones que tengan sentido usar en un contexto particular deben estar en un solo grupo. Se pueden
utilizar varios grupos de acciones para una interfaz de usuario en particular. De hecho, se espera que la
mayoría de las aplicaciones no triviales hagan uso de varios grupos. Por ejemplo, en una aplicación que
puede editar varios documentos, un grupo tiene acciones globales (p. Ej. Salir, acerca de, nuevo) y un
grupo por documento contiene acciones que actúan sobre ese documento (p. Ej. Guardar, cortar / copiar
/ pegar, etc. ). Los menús de cada ventana se construirían a partir de una combinación de dos grupos de
acción.
Existen diferentes clases que representan diferentes tipos de acciones:
• Gtk.Action: Una acción que puede ser activada por un menú o un elemento de la barra de
herramientas.
• Gtk.ToggleAction: Una acción que se puede alternar entre dos estados
• Gtk.RadioAction: Una acción de la cual solo uno en un grupo puede estar activo
Tenga en cuenta que debe especificar acciones para los submenús y los elementos del menú.
Administrador de UI
Gtk.UIManagerproporciona una forma sencilla de crear menús y barras de herramientas utilizando
una descripción similar a XML .
En primer lugar, debe agregar el Gtk.ActionGroupal UI Manager con
Gtk.UIManager.insert_action_group(). En este punto también es una buena idea decirle a
la ventana principal que responda a los atajos de teclado especificados, usando
Gtk.UIManager.get_accel_group()y Gtk.Window.add_accel_group().
Luego, puede definir el diseño visible real de los menús y barras de herramientas, y agregar el diseño
de la interfaz de usuario. Esta "cadena de interfaz de usuario" utiliza un formato XML, en el que debe
mencionar los nombres de las acciones que ya ha creado. Recuerde que estos nombres son solo los
identificadores que usamos al crear las acciones. No son el texto que verá el usuario en los menús y
barras de herramientas. Proporcionamos esos nombres legibles por humanos cuando creamos las
acciones.
Finalmente, recupera el widget raíz con Gtk.UIManager.get_widget()y agrega el widget a un
contenedor como Gtk.Box.
Ejemplo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
UI_INFO = """
<ui>
<menubar name='MenuBar'>
<menu action='FileMenu'>
<menu action='FileNew'>
<menuitem action='FileNewStandard' />
<menuitem action='FileNewFoo' />
<menuitem action='FileNewGoo' />
</menu>
<separator />
<menuitem action='FileQuit' />
</menu>
<menu action='EditMenu'>
<menuitem action='EditCopy' />
<menuitem action='EditPaste' />
<menuitem action='EditSomething' />
</menu>
<menu action='ChoicesMenu'>
<menuitem action='ChoiceOne'/>
<menuitem action='ChoiceTwo'/>
<separator />
<menuitem action='ChoiceThree'/>
</menu>
</menubar>
<toolbar name='ToolBar'>
<toolitem action='FileNewStandard' />
<toolitem action='FileQuit' />
</toolbar>
<popup name='PopupMenu'>
<menuitem action='EditCopy' />
<menuitem action='EditPaste' />
<menuitem action='EditSomething' />
</popup>
</ui>
"""
class MenuExampleWindow(Gtk.Window):
def __init__(self):
self().__init__(title="Menu Example")
self.set_default_size(200, 200)
action_group = Gtk.ActionGroup(name="my_actions")
self.add_file_menu_actions(action_group)
self.add_edit_menu_actions(action_group)
self.add_choices_menu_actions(action_group)
uimanager = self.create_ui_manager()
uimanager.insert_action_group(action_group)
menubar = uimanager.get_widget("/MenuBar")
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
box.pack_start(menubar, False, False, 0)
toolbar = uimanager.get_widget("/ToolBar")
box.pack_start(toolbar, False, False, 0)
eventbox = Gtk.EventBox()
eventbox.connect("button-press-event", self.on_button_press_event)
box.pack_start(eventbox, True, True, 0)
self.popup = uimanager.get_widget("/PopupMenu")
self.add(box)
action_new = Gtk.Action(
name="FileNewStandard",
label="_New",
tooltip="Create a new file",
stock_id=Gtk.STOCK_NEW,
)
action_new.connect("activate", self.on_menu_file_new_generic)
action_group.add_action_with_accel(action_new, None)
action_group.add_actions(
[
(
"FileNewFoo",
None,
"New Foo",
None,
"Create new foo",
self.on_menu_file_new_generic,
),
(
"FileNewGoo",
None,
"_New Goo",
None,
"Create new goo",
self.on_menu_file_new_generic,
),
]
)
action_group.add_radio_actions(
[
("ChoiceOne", None, "One", None, None, 1),
("ChoiceTwo", None, "Two", None, None, 2),
],
1,
self.on_menu_choices_changed,
)
window = MenuExampleWindow()
window.connect("destroy", Gtk.main_quit)
window.show_all()
Gtk.main()