5.Contenedos de diseño
Si bien muchos kits de herramientas GUI requieren que coloque los widgets en una ventana con precisión, utilizando el posicionamiento absoluto,GTK+ utilizada un enfoque diferente. En lugar de especificar la posicion y el tamaño de cada widget en filas, columnas y/o tablas. El tamaño de la ventana se puede determinar automaticamente, en funcion de los tamaños de los widgets estan determinados por la cantidad de texto que contiene. A su vez, los tamaños de los widgets estan determinados por la cantidad de texto que contiene o por los tamñaños minimos y maximos que especifica y/o por como ha solicitado que el espacio disponible se comparta entre conjuntos de widgets. puede perfeccionar su diseño especificado la distancia de relleno y los valores de centrado para cada uno de sus Widgets. GTK+ luego utiliza toda esta informacion para cambiar el tamaño y reposicionar todo de forma sensata y suave cuando el usuario manipula la ventana.
GTK+ organiza los widgets de forma jerarquica, utilizando contenedores. Son invisibles para el usuario final y se insertan en una ventana o se colocan entre si a los componentes de diseño. Hay dos opciones de contenedores : contenedores de un solo hijo, que son todos decendientes de Gtk.Bin
, y contenedores de varios hijos, que son decendientes de Gtk.Container
. Las más utilizadas son las cajas verticales o horizontales(Gtk.Box
) y las cuadriculas (Gtk.Grid
).
5.1. Boxes(cajas)
Los boxes(cajas) son contenedores invisibles en los que podemos empaquetar nuestros widgets. Al embalar Widgets en una caja horizontal, los objetos se insertan horizontalmente a izquierda dependiendo de si se utiliza Gtk.Box.pack_start()
o Gtk.Box.pack_end()
. En una caja vertical, los widgets se empaquetan de arriba a abajo o viceversa. Puede utilzar cualquier combinacion de cajas dentro o al lado de otras caja para crear el efecto deseado.
5.1.1. Ejemplo
Echemos un vistazo a una version ligeramentes 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):
Gtk.Window.__init__(self, 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)
def on_button1_clicked(self, widget):
print("Hello")
def on_button2_clicked(self, widget):
print("Goodbye")
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
En primer lugar, creamos un contenedor de caja horizontalmente orientado donde 6 pixeles se colocan entre los children. Esta casilla se convierte en el hijo de la ventana de nivel superior.
self.box = Gtk.Box(spacing=6)
self.add(self.box)
Posteriormente, agregamos dos botones diferentes al contenedor de la caja.
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)
Mientras que con los widgets Gtk.Box.pack_start()
se posicionan de izquierda a derecha, Gtk.Box.pack_end()
los posiciona de derecha a izquierda.
5.2.Grid(Cuadricula)
Gtk.Grid
es un cotenedor que organiza sus widgets secundarios en filas y columnas, pero no es necesario espescificar las dimensiones en el constructor. Los children se agregan usandoGtk.Grid.attach()
. Puede abarcar varias filas o columnas. Tambien es posible agragar un children junto a otro children existente, usando Gtk.Grid.attach_next_to()
.
Gtk.Grid
se puede usar como un Gtk.Box
con solo usar Gtk.Grid.add()
, que colocara los children uno junto al otro en la direccion determinada por la propiedad "orientation" (por defecto a Gtk.Orientation.HORIZONTAL
).
5.2.1 Ejemplo
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class GridWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Grid Example")
grid = Gtk.Grid()
self.add(grid)
button1 = Gtk.Button(label="Button 1")
button2 = Gtk.Button(label="Button 2")
button3 = Gtk.Button(label="Button 3")
button4 = Gtk.Button(label="Button 4")
button5 = Gtk.Button(label="Button 5")
button6 = Gtk.Button(label="Button 6")
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("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
5.3 ListBox (Cuadro de lista)
Un Gtk.ListBox
es un contenedor vertical que contiene Gtk.ListBoxRow
children. Estas filas pueden clasificarse y filtrarse de forma dinamica y los encabezados se pueden agregar dinamicamente dependiendo del contenido de la fila. Tambien permite el teclado y la navegacion del raton y la seleccion comouna lista tipica.
El uso de Gtk.ListBox
es amenudo una alternativa a Gtk.TreeView
especialmente cuando el contenido de la lista tiene un diseño mas complicado que lo que permiten un Gtk.CellRenderer
o cuando el contenido es interactivo(es decir, tiene un boton en el).
Aunque un Gtk.ListBox
debe tener solo Gtk.ListBoxRow
children, puede agregar cualquier tipo de widget a el a traves de Gtk.Container.add()
y un widget Gtk.ListBoxRow
se insertara automaticamente entre la lista y el widget.
5.3.1 Ejemplo
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class ListBoxRowWithData(Gtk.ListBoxRow):
def __init__(self, data):
super(Gtk.ListBoxRow, self).__init__()
self.data = data
self.add(Gtk.Label(data))
class ListBoxWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="ListBox Demo")
self.set_border_width(10)
box_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(box_outer)
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)
label1 = Gtk.Label("Automatic Date & Time", xalign=0)
label2 = Gtk.Label("Requires internet access", xalign=0)
vbox.pack_start(label1, True, True, 0)
vbox.pack_start(label2, True, True, 0)
switch = Gtk.Switch()
switch.props.valign = Gtk.Align.CENTER
hbox.pack_start(switch, False, True, 0)
listbox.add(row)
row = Gtk.ListBoxRow()
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
label = Gtk.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("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()
for item in items:
listbox_2.add(ListBoxRowWithData(item))
def sort_func(row_1, row_2, data, notify_destroy):
return row_1.data.lower() > row_2.data.lower()
def filter_func(row, data, notify_destroy):
return False if row.data == 'Fail' else True
listbox_2.set_sort_func(sort_func, None, False)
listbox_2.set_filter_func(filter_func, None, False)
listbox_2.connect('row-activated', lambda widget, row: print(row.data))
box_outer.pack_start(listbox_2, True, True, 0)
listbox_2.show_all()
win = ListBoxWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
5.4. Stack and StackSwicher
Un Gtk.Stack
es un cotenedor que solo muestra a uno de sus children a la vez. En contraste con Gtk.Notebook
, Gtk.Stack
no proporciona un medio para que los usuarios cambien el children visible. En su lugar, el widget Gtk.StackSwitcher
se puede utilizar con Gtk.Stack
para propocionar esta funcionalidad.
Las transiciones entre paginas se pueden animar como diapositivas o se desvanece. Esto se puede controlar con Gtk.Stack.set_transition_type()
. Estas animaciones respetan el ajuste "gtk-enable-animations".
Velocidad de transicion se puede ajustar con Gtk.Stack.set_transition_duration()
Los widget Gtk.StackSwitcher
actuá como un controlador para un Gtk.Stack
; que muestra una fila de botones para cambiar entre las diferentes páginas del widget pila asociada.
Todo el contenido de los botones proviene de las propiedades secundarias del Gtk.Stack
.
Es posible asociar varios widgets Gtk.StackSwitcher
con el mismo artilugio Gtk.Stack
.
5.4.1. Ejemplo.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class StackWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Stack Demo")
self.set_border_width(10)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(vbox)
stack = Gtk.Stack()
stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
stack.set_transition_duration(1000)
checkbutton = Gtk.CheckButton("Click me!")
stack.add_titled(checkbutton, "check", "Check Button")
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("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
5.5. HeaderBar (Barra de encabezado).
Un Gtk.HeaderBar
es similar a un Gtk.Box
horizontal, permite colocar a los children al principio o al final. Además, permite mostrar un titulo. El titulo se centrará con respecto al ancho de la caja, incluso si los Children en ambos lados ocupan diferentes cantidades de espacio.
Dado que GTK+ ahora soporta Client Side Decoration, se puede usar un Gtk.HeaderBar
en lugar de la barra de título ( que es renderizada por Window Manager).
Un Gtk.HeaderBar
normalmente se encuentra en la parte superior de una ventana y debe contener controles de uso común que afectan al contenido de abajo. Tambien proporcionan acceso a los controles de la ventana, incluyendo el botón de cierre de la ventana y el menú de la ventana.
5.5.1. Ejemplo
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gio
class HeaderBarWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, 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(Gtk.ArrowType.LEFT, Gtk.ShadowType.NONE))
box.add(button)
button = Gtk.Button()
button.add(Gtk.Arrow(Gtk.ArrowType.RIGHT, Gtk.ShadowType.NONE))
box.add(button)
hb.pack_start(box)
self.add(Gtk.TextView())
win = HeaderBarWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
5.6.FlowBox
Un Gtk.FlowBox
es un contenedor que posiciona los widgets children en secuencia según su orientación.
Por ejemplo, con la orientación horizontal, los widgets se organizaran 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.
Del mismo nodo, con la orientación vertical los widgets se organizarán de arriba a abajo, comenzando una nueva columna ala derecha cuando sea necesario. Reducir la altura requerirá más columnas, por lo que se solicitará una anchura mayor.
Los children de un Gtk.FlowBox
se pueden ordenar dinámicamente y filtrar.
Aunque un Gtk.FlowBox
debe tener sólo los children Gtk.FlowBoxChild
puede agregar cualquier tipo de widget a él a través de Gtk.Container.add()
y un widget Gtk.FlowBoxChild
se insertará automáticamente entre el cuadro y el widget.
5.6.1. Ejemplo.
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
class FlowBoxWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="FlowBox Demo")
self.set_border_width(10)
self.set_default_size(300, 250)
header = Gtk.HeaderBar(title="Flow Box")
header.set_subtitle("Sample FlowBox app")
header.props.show_close_button = True
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()
def color_swatch_new(self, str_color):
color = Gdk.color_parse(str_color)
rgba = Gdk.RGBA.from_color(color)
button = Gtk.Button()
area = Gtk.DrawingArea()
area.set_size_request(24, 24)
area.override_background_color(0, rgba)
button.add(area)
return button
def create_flowbox(self, flowbox):
colors = [
'AliceBlue',
'AntiqueWhite',
'AntiqueWhite1',
'AntiqueWhite2',
'AntiqueWhite3',
'AntiqueWhite4',
'aqua',
'aquamarine',
'aquamarine1',
'aquamarine2',
'aquamarine3',
'aquamarine4',
'azure',
'azure1',
'azure2',
'azure3',
'azure4',
'beige',
'bisque',
'bisque1',
'bisque2',
'bisque3',
'bisque4',
'black',
'BlanchedAlmond',
'blue',
'blue1',
'blue2',
'blue3',
'blue4',
'BlueViolet',
'brown',
'brown1',
'brown2',
'brown3',
'brown4',
'burlywood',
'burlywood1',
'burlywood2',
'burlywood3',
'burlywood4',
'CadetBlue',
'CadetBlue1',
'CadetBlue2',
'CadetBlue3',
'CadetBlue4',
'chartreuse',
'chartreuse1',
'chartreuse2',
'chartreuse3',
'chartreuse4',
'chocolate',
'chocolate1',
'chocolate2',
'chocolate3',
'chocolate4',
'coral',
'coral1',
'coral2',
'coral3',
'coral4'
]
for color in colors:
button = self.color_swatch_new(color)
flowbox.add(button)
win = FlowBoxWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
5.7. Notebook
El widget Gtk.Notebook
es un Gtk.Container
cuyo children hijos son páginas que se pueden cambiar entre usar etiquetas de pestañas a lo largo de un borde.
Hay muchas opciones de configuración para GtkNotebook. Entre otras cosas, puede elegir en que borde aparecen las pestañas(vea Gtk.Notebook.set_tab_pos()
) , si si hay demasiadas pestañas para encajar en el cuaderno, debe hacerse más grande o se pueden agregar flechas de desplazamiento (consulte Gtk.Notebook.set_scrollable()
) y si habrá un menú emergente que permita a los usuarios cambiar páginas (ver Gtk.Notebook.popup_enable()
, Gtk.Notebook.popup_disable()
).
5.7.1.Ejemplo
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, 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('Default Page!'))
self.notebook.append_page(self.page1, Gtk.Label('Plain Title'))
self.page2 = Gtk.Box()
self.page2.set_border_width(10)
self.page2.add(Gtk.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("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()