Las columnas de vista de árbol (TreeViewColumn) y los
Visualizadores o Intérpretes de Celda (CellRenderer) colaboran
en la visualización de una columna de datos de una vista de árbol
(TreeView). La clase
TreeViewColumn proporciona el título de columna y un espacio
vertical para que los CellRenderer muestren una porción de los datos
de los que contiene el almacén del TreeView. Un
CellRenderer maneja la visualización de los datos de cada fila
y columna dentro de los confines de una TreeViewColumn. Una
TreeViewColumn puede contener más de un
CellRenderer para proporcionar una visualización de fila similar a la
de una HBox. Un uso habitual con múltiples
CellRenderer es la combinación de un Visualizador de Imágenes en
Celda (CellRendererPixbuf) y un Visuallizador de Texto en Celda
(CellRendererText) en la misma columna.
El ejemplo Figura 14.2, “TreeViewColumns con CellRenderers” muestra un ejemplo que ilustra
la composición de dos TreeViewColumn, una con dos
CellRenderer y la otra con uno sólo:
La aplicación de cada CellRenderer se indica mediante
un color de fondo diferenciado: amarillo en el caso de un
CellRendererPixbuf, cian para un
CellRendererText, y rosa para el otro
CellRendererText. Hay que resaltar que el
CellRendererPixbuf y el primer
CellRendererText están en la misma columna, encabezada con el
texto "Pixbuf and Text". El color de fondo del
CellRendererText que muestra "Print File" es el color predeterminado
que muestra el área de la aplicación en una fila.
Figura 14.2, “TreeViewColumns con CellRenderers” se creó con el programa treeviewcolumn.py.
El tipo del CellRenderer que se necesita para cada caso
viene determinado por el tipo de visualización requerida por los datos del modelo de árbol usado.
PyGTK posee tres CellRenderer predefinidos:
| visualiza imágenes de píxeles (pixbuf) que pueden haber sido creadas por el programa, o tratarse de una imagen de serie predefinida. |
| visualiza cadenas de texto, así como números que pueden ser convertidos en cadenas (enteros, reales y booleanos incluidos). |
| visualiza un valor booleano como un botón biestado o como un botón de exclusión |
Las propiedades de un CellRenderer determinan
la forma en que se visualizarán los datos:
| "mode" | Lectura-Escritura | El modo de edición del
CellRenderer. Es uno de estos:
gtk.CELL_RENDERER_MODE_INERT (inerte),
gtk.CELL_RENDERER_MODE_ACTIVATABLE (activable) o
gtk.CELL_RENDERER_MODE_EDITABLE (editable) |
| "visible" | Lectura-Escritura | Si es TRUE se muestra la celda. |
| "xalign" | Lectura-Escritura | La fracción de espacio libre a la izquierda de la celda dentro del intervalo 0.0 a 1.0. |
| "yalign" | Lectura-Escritura | La fracción de espacio libre sobre la celda dentro del intervalo 0.0 a 1.0. |
| "xpad" | Lectura-Escritura | La cantidad de margen a la derecha e izquierda de la celda. |
| "ypad" | Lectura-Escritura | La cantidad de margen sobre y bajo la celda. |
| "width" | Lectura-Escritura | La anchura fija de la celda. |
| "height" | Lectura-Escritura | La altura fija de la celda. |
| "is-expander" | Lectura-Escritura | Si es TRUE la fila tiene descendientes (hijas) |
| "is-expanded" | Lectura-Escritura | Si es TRUE la fila tiene descendientes y se expande para
mostrarlas. |
| "cell-background" | Escritura | El color de fondo de la celda indicada como cadena. |
| "cell-background-gdk" | Lectura-Escritura | El color de fondo indicado como gtk.gdk.Color. |
| "cell-background-set" | Lectura-Escritura | Si es TRUE el color de fondo de la celda lo determina este
visualizador |
Las propiedades anteriores están disponibles para todas las subclases de
CellRenderer. Pero los distintos tipos de
CellRenderer también tienen propiedades exclusivas.
Los CellRendererPixbuf tienen estas propiedades:
| "pixbuf" | Lectura-Escritura | El pixbuf que se visualizará (es anulada por "stock-id") |
| "pixbuf-expander-open" | Lectura-Escritura | Pixbuf para el expansor cuando está desplegado. |
| "pixbuf-expander-closed" | Lectura-Escritura | Pixbuf para el expansor cuando está cerrado. |
| "stock-id" | Lectura-Escritura | El stock ID del icono de serie que se visualizará. |
| "stock-size" | Read-Write | El tamaño del icono representado. |
| "stock-detail" | Lectura-Escritura | Detalle de visualización que se proporcionará al motor de temas. |
Los CellRendererText tienen un gran número de propiedades
que tratan fundamentalmente con la especificación de estilos:
| "text" | Lectura-Escritura | Texto que se visualizará. |
| "markup" | Lectura-Escritura | Texto con marcas que se visualizará. |
| "attributes" | Lectura-Escritura | Una lista de atributos de estilo que se aplicarán al texto del visualizador. |
| "background" | Escritura | Color de fondo, como cadena de texto. |
| "foreground" | Escritura | Color de primer plano, como cadena de texto. |
| "background-gdk" | Lectura-Escritura | Color de fondo, como gtk.gdk.Color |
| "foreground-gdk" | Lectura-Escritura | Color de primer plano, como gtk.gdk.Color |
| "font" | Lectura-Escritura | Descripción de la fuente, como cadena de texto. |
| "font-desc" | Lectura-Escritura | Descripción de la fuente, como pango.FontDescription.
|
| "family" | Lectura-Escritura | Nombre de la familia de la fuente, p.e. Sans, Helvetica, Times, Monospace. |
| "style" | Lectura-Escritura | Estilo de fuente. |
| "variant" | Lectura-Escritura | Variante de la fuente. |
| "weight" | Lectura-Escritura | Peso de la fuente. |
| "stretch" | Lectura-Escritura | Estirado de la fuente. |
| "size" | Lectura-Escritura | Tamaño de la fuente. |
| "size-points" | Lectura-Escritura | Tamaño de la fuente en puntos. |
| "scale" | Lectura-Escritura | Factor de escala de la fuente. |
| "editable" | Lectura-Escritura | Si es TRUE el texto puede ser cambiado por el usuario. |
| "strikethrough" | Lectura-Escritura | Si es TRUE se tacha el texto |
| "underline" | Lectura-Escritura | Estilo de subrayado del texto. |
| "rise" | Lectura-Escritura | Elevación del texto por encima de la línea base (o por debajo si el valor es negativo) |
| "language" | Lectura-Escritura | El idioma del texto, como código ISO. Pango puede utilizarlo como pista al representar el texto. Si no se entiende este parámetro... probablemente es que no se necesita. Solamente disponible a partir de GTK+ 2.4. |
| "single-paragraph-mode" | Lectura-Escritura | Si es TRUE, se deja todo el texto en un único párrafo. Solamente
disponible a partir de GTK+ 2.4. |
| "background-set" | Lectura-Escritura | Si es TRUE se aplica el color de fondo. |
| "foreground-set" | Lectura-Escritura | Si es TRUE se aplica el color de primer plano. |
| "family-set" | Lectura-Escritura | Si es TRUE se aplica la familia de la fuente. |
| "style-set" | Lectura-Escritura | Si es TRUE se aplica el estilo de la fuente. |
| "variant-set" | Lectura-Escritura | Si es TRUE se aplica la variante de la fuente. |
| "weight-set" | Lectura-Escritura | Si es TRUE se aplica el peso de la fuente. |
| "stretch-set" | Lectura-Escritura | Si es TRUE se aplica el estirado de la fuente. |
| "size-set" | Lectura-Escritura | Si es TRUE se aplica el tamaño de fuente. |
| "scale-set" | Lectura-Escritura | si es TRUE se escala la fuente. |
| "editable-set" | Lectura-Escritura | Si es TRUE se aplica la editabilidad del texto. |
| "strikethrough-set" | Lectura-Escritura | Si es TRUE se aplica el tachado. |
| "underline-set" | Lectura-Escritura | Si es TRUE se aplica el subrayado de texto. |
| "rise-set" | Lectura-Escritura | Si es TRUE se aplica la elevación del texto. |
| "language-set" | Lectura-Escritura | Si es TRUE se aplica el idioma usado para mostrar el texto. A partir
de GTK+ 2.4. |
Casi cada una de las propiedades de CellRendererText
posee una propiedad booleana asociada (con el suffijo "-set") que indica si se aplica dicha
propiedad. Esto permite fijar globalmente una propiedad y activar o desactivar su aplicación
selectivamente.
Los CellRendererToggle poseen las siguientes
propiedades:
| "activatable" | Lectura-Escritura | Si es TRUE, el botón biestado se puede activar. |
| "active" | Lectura-Escritura | Si es TRUE, el botón está activo. |
| "radio" | Lectura-Escritura | Si es TRUE, se dibuja el botón como un botón de exclusión. |
| "inconsistent" | Lectura-Escritura | Si es TRUE, el botón está en un estado inconsistente. A partir
de GTK+ 2.2. |
Las propiedades se pueden fijar para todas las filas utilizando el método
gobject.set_property(). Véase el programa treeviewcolumn.py
como ejemplo del uso de este método.
Un atributo asocia una columna de un modelo de árbol a una propiedad de un
CellRenderer. El
CellRenderer fija la propiedad en función del valor de una columna
de la fila antes de representar la celda. Esto permite personalizar la visualización de la celda
utilizando los datos del modelo de árbol. Se puede añadir un atributo al conjunto actual con:
treeviewcolumn.add_attribute(cell_renderer,attribute,column)
donde la propiedad especificada por attribute se fija para
el cell_renderer en la columna
column. Por ejemplo:
treeviewcolumn.add_attribute(cell, "cell-background", 1)
establece el fondo del CellRenderer al color indicado
por la cadena de la segunda columna del almacén de datos.
Para eliminar todos los atributos y establecer varios atributos nuevos de una vez se usa:
treeviewcolumn.set_attributes(cell_renderer, ...)
donde los atributos de cell_renderer se
determinan mediante pares clave-valor: propiedad=columna. Por ejemplo, en el caso de un
CellRendererText:
treeviewcolumn.set_attributes(cell, text=0, cell_background=1, xpad=3)
indica, para cada fila, el texto en la primera columna, el color de fondo en la segunda y el margen horizontal desde la cuarta columna. Véase el programa treeviewcolumn.py para ver ejemplos del uso de estos métodos.
Los atributos de un CellRenderer se pueden
limpiar utilizando:
treeviewcolumn.clear_attributes(cell_renderer)
Si no es suficiente el uso de atributos para cubrir nuestras necesidades,
también es posible indicar una función que será llamada en cada fila y que determine las
propiedades del CellRenderer utilizando:
treeviewcolumn.set_cell_data_func(cell_renderer,func,data=None)
donde func tiene la signatura:
def func(column, cell_renderer, tree_model, iter, user_data)
donde column es la
TreeViewColumn
que contiene el visualizador cell_renderer,
tree_model es el almacén de datos e
iter es un iterador TreeIter que apunta a
una fila en tree_model. user_data
es el valor de data que se pasó a
set_cell_data_func().
En func se establecen las propiedades que se deseen
para cell_renderer. Por ejemplo, el siguiente fragmento de código
establece la propiedad de texto de manera que muestre los objetos de PyGTK como una
cadena de identificación ID.
...
def obj_id_str(treeviewcolumn, cell_renderer, model, iter):
pyobj = model.get_value(iter, 0)
cell.set_property('text', str(pyobj))
return
...
treestore = gtk.TreeStore(object)
win = gtk.Window()
treeview = gtk.TreeView(treestore)
win.add(treeview)
cell = CellRendererText()
tvcolumn = gtk TreeViewColumn('Object ID', cell)
treeview.append_column(tvcolumn)
iter = treestore.append(None, [win])
iter = treestore.append(iter, [treeview])
iter = treestore.append(iter, [tvcolumn])
iter = treestore.append(iter, [cell])
iter = treestore.append(None, [treestore])
...
El resultado debería ser algo como Figura 14.3, “Función de Datos de Celda”:
Otro posible uso de la función de datos de celda es el control del formato de
visualización de un texto numérico, p.e. un valor real. Un
CellRendererText hará una conversión de forma automática del
valor real a una cadena, pero con el formato predeterminado "%f".
Con funciones de datos de celda se pueden generar incluso los datos de las celdas
a partir de datos externos. Por ejemplo, el programa filelisting.py
usa un almacén ListStore con una única columna que contiene
una lista de nombres de archivos. La TreeView muestra columnas
que incluyen una imagen pixbuf, el nombre de archivo y su tamaño, modo y fecha del último
cambio. Los datos son generados por las siguientes funciones de datos de celda:
def file_pixbuf(self, column, cell, model, iter):
filename = os.path.join(self.dirname, model.get_value(iter, 0))
filestat = statcache.stat(filename)
if stat.S_ISDIR(filestat.st_mode):
pb = folderpb
else:
pb = filepb
cell.set_property('pixbuf', pb)
return
def file_name(self, column, cell, model, iter):
cell.set_property('text', model.get_value(iter, 0))
return
def file_size(self, column, cell, model, iter):
filename = os.path.join(self.dirname, model.get_value(iter, 0))
filestat = statcache.stat(filename)
cell.set_property('text', filestat.st_size)
return
def file_mode(self, column, cell, model, iter):
filename = os.path.join(self.dirname, model.get_value(iter, 0))
filestat = statcache.stat(filename)
cell.set_property('text', oct(stat.S_IMODE(filestat.st_mode)))
return
def file_last_changed(self, column, cell, model, iter):
filename = os.path.join(self.dirname, model.get_value(iter, 0))
filestat = statcache.stat(filename)
cell.set_property('text', time.ctime(filestat.st_mtime))
return
Estas funciones obtienen la información de los archivos utilizando el nombre, extraen los datos necesarios y establecen las propiedades de celda 'text' o 'pixbuf' con los datos. Figura 14.4, “Ejemplo de Listado de Archivos Utilizando Funciones de Datos de Celda” muestra el programa de ejemplo en acción:
Un CellRendererText puede utilizar etiquetas de marcado
de Pango (estableciendo la propiedad "markup") en vez de una cadena de texto sencilla
para codificar diversos atributos de texto y proporcionar una visualización rica, con múltiples
cambios de estilos de fuente. Véase la referencia Pango
Markup en el Manual de Referencia de PyGTK
para obtener más detalles sobre el lenguaje de marcado de Pango.
El siguiente fragmento de código ilustra el uso de la propiedad "markup":
...
liststore = gtk.ListStore(str)
cell = gtk.CellRendererText()
tvcolumn = gtk.TreeViewColumn('Pango Markup', cell, markup=0)
...
liststore.append(['<span foreground="blue"><b>Pango</b></span> markup can'
' change\n<i>style</i> <big>size</big>, <u>underline,'
<s>strikethrough</s></u>,\n'
'and <span font_family="URW Chancery L"><big>font family '
'e.g. URW Chancery L</big></span>\n<span foreground="red">red'
' foreground and <span background="cyan">cyan background</span></span>'])
...
produce un resultado semejante a Figura 14.5, “Etiquetas de Marcado para CellRendererText”:
Si se crean etiquetas de marcado sobre la marcha es preciso tener cuidado y sustituir
los caracteres con especial significado en el lenguaje de marcas: "<",
">", "&". La función de la biblioteca de Python
cgi.escape() permite hacer estas conversiones básicas.
Las celdas CellRendererText pueden hacerse editalbes
de forma que una usuaria pueda editar los contenidos de la celda que seleccione haciendo
clic en ella o pulsando las teclas Return,
Enter, Space o Shift+Space. Se hace
editable un CellRendererText en todas sus filas estableciendo su
propiedad "editable" a TRUE de la siguiente manera:
cellrenderertext.set_property('editable', True)
Se pueden establecer individualmente celdas editables añadiendo un atributo a la
TreeViewColumn utilizando un
CellRendererText parecido a:
treeviewcolumn.add_attribute(cellrenderertext, "editable", 2)
que establece que el valor de la propiedad "editable" se indica en la tercera columna del almacén de datos.
Una vez que la edición de la celda termina, la aplicación debe gestionar la señal "edited" para obtener el nuevo texto y establecer los datos asociados del almacén de datos. De otro modo, el valor de la celda recuperará su valor inicial. La signatura del manejador de llamada de la señal "edited" es:
def edited_cb(cell,path,new_text,user_data)
donde cell es el
CellRendererText, path es el camino de
árbol (como cadena) a la fila que contiene la celda editada,
new_text es el texto editado y
user_data son datos de contexto. Puesto que se necesita el
TreeModel para usar el camino
path y establecer new_text en el
almacén de datos, probablemente se quiera pasar el TreeModel como
user_data en el método
connect():
cellrenderertext.connect('edited', edited_cb, model)
Si se tienen dos o más celdas editables en una fila, se podría pasar el número de
columna del TreeModel como parte de los datos adicionales
user_data así como el modelo
TreeModel:
cellrenderertext.connect('edited', edited_cb, (model, col_num))
Así, se puede establecer el nuevo texto en el manejador de la señal "edited"
de una forma parecida al siguiente ejemplo que usa un almacén de lista
ListStore:
def edited_cb(cell, path, new_text, user_data):
liststore, column = user_data
liststore[path][column] = new_text
return
Los botones de CellRendererToggle se pueden hacer
activables estableciendo la propiedad "activatable" como
TRUE. De forma parecida a la celdas editables de
CellRendererText la propiedad "activatable" se puede fijar
para un conjunto completo de celdas con CellRendererToggle
utilizando el método set_property() o individualmente en algunas
celdas añadiendo un atributo a la columna TreeViewColumn
que contiene el CellRendererToggle.
cellrenderertoggle.set_property('activatable', True)
treeviewcolumn.add_attribute(cellrenderertoggle, "activatable", 1)
La creación de botones individuales biestado se puede deducir de los valores
de una columna de un TreeModel añadiendo un atributo de
manera similar a este ejemplo:
treeviewcolumn.add_attribute(cellrenderertoggle, "active", 2)
Se debe conectar a la señal "toggled" para disponer de notificación de las pulsaciones del usuario en los botones biestado, de manera que la aplicación pueda modificar los valores del almacén de datos. Por ejemplo:
cellrenderertoggle.connect("toggled", toggled_cb, (model, column))
La retrollamada tiene la signatura:
def toggled_cb(cellrenderertoggle,path,user_data)
donde path es el camino de árbol, como cadena, que apunta
a la fila que contiene el botón biestado que ha sido pulsado. Es recomendable pasar el
TreeModel y, tal vez, el índice de la columna como parte de los
datos de usuario user_data para proporcionar el contexto necesario
para establecer los valores del almacén de datos. Por ejemplo, la aplicación puede
conmutar los valores del almacén de datos, así:
def toggled_cb(cell, path, user_data):
model, column = user_data
model[path][column] = not model[path][column]
return
Si la aplicación desea mostrar los botones biestado como botones de exclusión y que únicamente uno de ellos esté activo, tendrá que recorrer los datos del almacén para desactivar el botón de exclusión activo y posteriormente activar el botón biestado. Por ejemplo:
def toggled_cb(cell, path, user_data):
model, column = user_data
for row in model:
row[column] = False
model[path][column] = True
return
usa la estrategia "vaga" de poner todos los valores a FALSE
antes de fijar el valor TRUE en la fila especificada en
path.
El programa cellrenderer.py
ilustra la utilización de celdas CellRendererText editables y de celdas
CellRendererToggle activables en un almacén
TreeStore.
1 #!/usr/bin/env python
2 # vim: ts=4:sw=4:tw=78:nowrap
3 """ Demonstration using editable and activatable CellRenderers """
4 import pygtk
5 pygtk.require("2.0")
6 import gtk, gobject
7
8 tasks = {
9 "Buy groceries": "Go to Asda after work",
10 "Do some programming": "Remember to update your software",
11 "Power up systems": "Turn on the client but leave the server",
12 "Watch some tv": "Remember to catch ER"
13 }
14
15 class GUI_Controller:
16 """ The GUI class is the controller for our application """
17 def __init__(self):
18 # establecer la ventana principal
19 self.root = gtk.Window(type=gtk.WINDOW_TOPLEVEL)
20 self.root.set_title("CellRenderer Example")
21 self.root.connect("destroy", self.destroy_cb)
22 # Obtener el modelo y vincularlo a la vista
23 self.mdl = Store.get_model()
24 self.view = Display.make_view( self.mdl )
25 # Añadir la vista a la ventana principal
26 self.root.add(self.view)
27 self.root.show_all()
28 return
29 def destroy_cb(self, *kw):
30 """ Destroy callback to shutdown the app """
31 gtk.main_quit()
32 return
33 def run(self):
34 """ run is called to set off the GTK mainloop """
35 gtk.main()
36 return
37
38 class InfoModel:
39 """ The model class holds the information we want to display """
40 def __init__(self):
41 """ Sets up and populates our gtk.TreeStore """
42 self.tree_store = gtk.TreeStore( gobject.TYPE_STRING,
43 gobject.TYPE_BOOLEAN )
44 # colocar los datos globales de la gente en la lista
45 # formamos un árbol simple.
46 for item in tasks.keys():
47 parent = self.tree_store.append( None, (item, None) )
48 self.tree_store.append( parent, (tasks[item],None) )
49 return
50 def get_model(self):
51 """ Returns the model """
52 if self.tree_store:
53 return self.tree_store
54 else:
55 return None
56
57 class DisplayModel:
58 """ Displays the Info_Model model in a view """
59 def make_view( self, model ):
60 """ Form a view for the Tree Model """
61 self.view = gtk.TreeView( model )
62 # configuramos el visualizador de celda de texto y permitimos
63 # la edición de las celdas.
64 self.renderer = gtk.CellRendererText()
65 self.renderer.set_property( 'editable', True )
66 self.renderer.connect( 'edited', self.col0_edited_cb, model )
67
68 # Se configura el visualizador de botones biestado y permitimos que se
69 # pueda cambiar por el usuario.
70 self.renderer1 = gtk.CellRendererToggle()
71 self.renderer1.set_property('activatable', True)
72 self.renderer1.connect( 'toggled', self.col1_toggled_cb, model ) 73
74 # Conectamos la columna 0 de la visualización con la columna o de nuestro modelo
75 # El visualizador mostrará lo que haya en la columna 0
76 # de nuestro modelo.
77 self.column0 = gtk.TreeViewColumn("Name", self.renderer, text=0) 78
79 # El estado de activación del modelo se vincula a la segunda columna
80 # del modelo. Así, cuando el modelo dice True entonces el botón
81 # se mostrará activo, es decir, encendido.
82 self.column1 = gtk.TreeViewColumn("Complete", self.renderer1 )
83 self.column1.add_attribute( self.renderer1, "active", 1)
84 self.view.append_column( self.column0 )
85 self.view.append_column( self.column1 )
86 return self.view
87 def col0_edited_cb( self, cell, path, new_text, model ):
88 """
89 Called when a text cell is edited. It puts the new text
90 in the model so that it is displayed properly.
91 """
92 print "Change '%s' to '%s'" % (model[path][0], new_text)
93 model[path][0] = new_text
94 return
95 def col1_toggled_cb( self, cell, path, model ):
96 """
97 Sets the toggled state on the toggle button to true or false.
98 """
99 model[path][1] = not model[path][1]
100 print "Toggle '%s' to: %s" % (model[path][0], model[path][1],)
101 return
102
103 if __name__ == '__main__':
104 Store = InfoModel()
105 Display = DisplayModel()
106 myGUI = GUI_Controller()
107 myGUI.run()
El programa proporcional celdas editables en la primera columna y celdas activables
en la segunda columna. Las líneas 64-66 crean un CellRendererText
editable y conectan la señal "edited" a la retrollamada
col0_edited_cb() (líneas 87-94), que cambia el valor en la columna
correspondiente de la fila en el almacén de árbol
TreeStore. De la misma manera, las líneas 70-72 crean un
CellRendererToggle activable y conectan la señal "toggled"
a la retrollamada col1_toggled_cb() (líneas 95-101) para cambiar
el valor de la fila correspondiente. Cuando se modifica una celada editable o activable se
muestra un mensaje para indicar cuál ha sido el cambio.
Figura 14.6, “Celdas Editables y Activables” ilustra el programa cellrenderer.py en ejecución.