La interfaz TreeModel es implementada por todas las subclases de TreeModel y aporta métodos para:
TreeIter), una referencia temporal que apunta a una fila del modelo.TreeModel).Las clases base para el almacenamiento de datos ListStore (almacén de datos en lista) y TreeStore (almacén de datos en árbol) permiten definir y gestionar las filas y columnas de datos existentes en un modelo de árbol. Los constructores de ambos objetos precisan que el tipo de cada una de las columnas sea alguno de los siguientes:
Button,
VBox, gdk.Rectangle,
gdk.Pixbuf, etc.tipos GObject (GTypes de GTK+)
especificados bien como constantes GObject Type o como cadenas. La mayoría de GTypes son traducidos a un tipo de Python:
Por ejemplo, para crear un ListStore o
TreeStore cuyas columnas contuviesen un
gdk.Pixbuf (un tipo de imagen), un entero, una cadena y un tipo booleano habría que hacier algo así:
liststore = ListStore(gtk.gdk.Pixbuf, int, str, 'gboolean') treestore = TreeStore(gtk.gdk.Pixbuf, int, str, 'gboolean')
Una vez que se crea un almacén de datos en Lista
(ListStore) o un almacén de datos en árbol
(TreeStore) y sus columnas han sido definidas, ya
no es posible hacer en ellos cambios o modificaciones. Así mismo es importante
tener en cuenta que no existe una relación predefinida entre las columnas de
una vista de árbol (TreeView) y las columnas de su
correspondiente modelo (TreeModel). Es decir, la quinta
columna de datos de un modelo (TreeModel) puede mostrarse
en la primera columna de una determinada vista de árbol (TreeView)
y en la tercera columna en otra vista diferente. Por tanto, no es necesario preocuparse de
cómo se mostrarán los datos a la hora de crear los almacenes de datos (Stores).
Si estos dos tipos de almacenes de datos no se ajustan a las necesidades
de una aplicación es posible definir otros almacenes de datos personalizados en Python
siempre que éstos implementen la interfaz TreeModel. Retomaremos esta cuestión más
adelante en la sección dedicada a GenericTreeModel
.
Antes de que podamos hablar de la gestion de las filas de datos de un almacén
TreeStore o ListStore necesitamos
una forma de especificar a qué columna nos queremos referir. PyGTK dispone de tres
formas de indicar columnas de un modelo TreeModel rows:
un camino de árbol, un iterador TreeIter y una referencia
TreeRowReference.
Un camino de árbol es una representación mediante enteros, una
cadena o una tupla de la localización de una fila en un almacén de datos. Un valor
entero especifica la fila del nivel superior del almacén, empezando por 0. Por ejemplo,
un valor de camino de 4 especificaría la quinta fila del almacén de datos. De la misma
manera, una representación mediante una cadena resultaría "4" y la representación
como tupla (4,). Esto es suficiente para llegar a determinar cualquier fila en un almacén
de datos en lista (ListStore), pero en el caso de un árbol
(TreeStore) necesitamos poder indicar las filas hijas. Para
este caso debemos usar la representación mediante una cadena o una tupla.
Dado que un almacén en árbol (TreeStore) puede
tener una jerarquía de una profudidad arbitraria, la representación como cadena especifica
el camino desde el nivel más alto hasta la fila escogida utilizando enteros separados mediante el carácter ":". De forma similar, la representación mediante una tupla especifica el camino en
el árbol empezando desde el vértice hasta la fila como una secuencia de enteros. Como
ejemplos correctos de representaciones con cadenas de caminos tenemos: "0:2" (especifica
la fila que es la tercera hija de la primera fila) y "4:0:1" (especifica la fila que es la segunda
hija del primer hijo de la quinta fila). De forma semejante, los mismos caminos son representados
respectivamente por las tuplas (0, 2) y (4, 0, 1).
Un camino de árbol es la única manera en la que se puede hacer corresponder
una fila de una vista de árbol (TreeView) a una fila de un modelo
(TreeModel) debido a que los caminos de una y otra son iguales.
También existen otros problemas con los caminos de árbol:
ListStore o
TreeStore.PyGTK usa la representación como tupla al devolver caminos, pero acepta cualquiera de las tres formas de representar un camino. Por coherencia se debería usar la representación en forma de tupla.
Se puede obtener un camino de árbol a partir de un iterador
TreeIter utilizando el método
get_path():
path = store.get_path(iter)
donde iter es un
iterador TreeIter que apunta a una fila en el almacén y
path es la tupla que representa el camino a la fila.
Un iterador TreeIter es un objeto que aporta
una referencia transitoria a la fila de un almacén ListStore o
TreeStore. Si los contenidos del almacén cambian (generalmente
porque se ha añadido o quitado una fila) el iterador TreeIter puede
no ser ya válido. Un modelo TreeModel que dé soporte a iteradores
persistentes debe establecer la bandera gtk.TREE_MODEL_ITERS_PERSIST.
Una aplicación puede comprobar dicha bandera haciendo uso del método
get_flags().
Los iteradore TreeIter se crean utilizando alguno de los
métodos del modelo TreeModel, que son aplicables tanto a
objetos del tipo TreeStore como
ListStore:
treeiter = store.get_iter(path)
donde treeiter apunta a la fila del camino
path. La excepción ValueError se activa en el caso de que el
camino no sea válido.
treeiter = store.get_iter_first()
donde treeiter es un iterador TreeIter que apunta
a la fila en el camino (0,). treeiter será
None si el almacén está vacío.
treeiter = store.iter_next(iter)
donde treeiter es un iterador
TreeIter que apunta a la siguiente fila en el mismo nivel que
el iterador TreeIter especificado por
iter. treeiter tendrá el valor
None si no hay una fila siguiente (iter
también es invalidado).
Los siguientes métodos son de utilidad únicamente cuando se vaya a obtener un
iterador TreeIter a partir de un almacén de datos de árbol
(TreeStore):
treeiter = treestore.iter_children(parent)
donde treeiter es un iterador
TreeIter que apunta a la primera fija que desciende de la fila indicada por el iterador TreeIter indicado por
parent. treeiter será
None en caso de que no tenga descendientes.
treeiter = treestore.iter_nth_child(parent,n)
donde treeiter es un iterador
TreeIter que señala la fila hija (de índice
n) de la fila especificada por el iterador
TreeIter
parent. parent puede ser
None para obtener una fila del nivel superior
. treeiter será None si no hay descendientes.
treeiter = treestore.iter_parent(child)
donde treeiter es un
TreeIter que apunta a la fila madre de la fila especificada
por el iterador TreeIter
child. treeiter será None si no hay
descendientes.
Se puede obtener un camino a partir de un iterador
TreeIter usando el método
get_path() :
path = store.get_path(iter)
donde iter es un iterador
Treeiter que apunta a una fila del almacén, y
path es su camino expresado como tupla.
Una referencia del tipo TreeRowReference
es una referencia persistente a una fila de datos en un almacén. Mientras que el camino
(es decir, su localización) de una fila puede cambiar a medida que se añden o quitan filas al
almacén, una referencia del tipo TreeRowReference
apuntará a la misma fila de datos en tanto exista.
Las referencias TreeRowReference únicamente están disponibles a partir de la versión 2.4 de PyGTK.
Se puede crear una referencia del tipo
TreeRowReference utilizando su constructor:
treerowref = TreeRowReference(model,path)
donde model es el modelo
TreeModel que contiene la fila y
path es el camino de la fila que hay que referenciar. Si
path no es un camino válido para el modelo
model entonces se devuelve None.
Una vez que se ha creado un almacén del tipo ListStore
se han de añadir filas utilizando alguno de los métodos siguientes:
iter = append(row=None) iter = prepend(row=None) iter = insert(position,row=None) iter = insert_before(sibling,row=None) iter = insert_after(sibling,row=None)
Cada uno de estos métodos insertan una fila en una posición implícita o especificada
en el almacén ListStore. Los métodos
append() y prepend()
usan posiciones implícitas: tras la última fila y antes de la primera fila, respectivamente. El
método insert() requiere un entero
(el parámetro position) que especifica la localización en la que
se insertará la fila. Los otros dos métodos necesitan un iterador
TreeIter (sibling) que hace referencia
a una fila en el almacén ListStore ante o tras la cual se insertará
la fila.
El parámetro row especifica los datos que deberían
ser insertados en la fila tras su creación. Si
row es None o no se especifica, se crea
una fila vacía. Si row se especifica debe ser una tupla o una
lista que contenga tantos elementos como el número de columnas que posea el almacén
ListStore. Los elementos también deben coincidir con los tipos
de las correspondientes columnas del almacén ListStore.
Todos los métodos devuelven un iterador TreeIter que
apunta a la fila recién insertada. El siguiente fragmento de código ilustra la creación de
un almacén ListStore y la adición de filas de datos en él:
...
liststore = gtk.ListStore(int, str, gtk.gdk.Color)
liststore.append([0,'red',colormap.alloc_color('red')])
liststore.append([1,'green',colormap.alloc_color('green')])
iter = liststore.insert(1, (2,'blue',colormap.alloc_color('blue')) )
iter = liststore.insert_after(iter, [3,'yellow',colormap.alloc_color('blue')])
...
La adición de filas a un almacén del tipo TreeStore
es semejante a la operación sobre el tipo ListStore, salvo que
también se debe especificar una fila madre (usando un iterador
TreeIter) a la que añadir la nueva fila. Los métodos para el amacén
TreeStore son:
iter = append(parent,row=None) iter = prepend(parent,row=None) iter = insert(parent,position,row=None) iter = insert_before(parent,sibling,row=None) iter = insert_after(parent,sibling,row=None)
Si parent es None, la fila
se añadirá a las filas del nivel superior.
Cada uno de estos métodos inserta una fila en una posición implícita o
especifica da en el almacén TreeStore. Los métodos
append() y prepend()
usan posiciones implícitas: tras la última fila hija y antes de la primera fila hija, respectivamente. El método insert() requiere un entero
(el parámetro position), que especifica el lugar en el que
se insertará la fila hija. Los otros dos métodos necesitan un iterador
TreeIter (sibling), que hace referencia
a una fila hija en el almacén TreeStore ante o tras la que se
insertará la fila.
El parámetro row especifica qué datos se deben
insertar en la fila tras su creación. Si row es None
o no se especifica, entonces se crea una fila vacía. Si row
se especifica, debe ser una tupla o una lista que contenga tantos elementos como
el número de columnas que posea el almacén TreeStore.
Los elementos también deben coincidir en sus tipos con los de las correspondientes
columnas del almacén TreeStore.
Todos los métodos devuelven un iterador TreeIter que
apunta a la recién creada fila. El siguiente fragmento de código ilustra la creación de
un TreeStore y la adición de filas de datos al mismo:
...
folderpb = gtk.gdk.pixbuf_from_file('folder.xpm')
filepb = gtk.gdk.pixbuf_from_file('file.xpm')
treestore = gtk.TreeStore(int, str, gtk.gdk.Pixbuf)
iter0 = treestore.append(None, [1,'(0,)',folderpb] )
treestore.insert(iter0, 0, [11,'(0,0)',filepb])
treestore.append(iter0, [12,'(0,1)',filepb])
iter1 = treestore.insert_after(None, iter0, [2,'(1,)',folderpb])
treestore.insert(iter1, 0, [22,'(1,1)',filepb])
treestore.prepend(iter1, [21,'(1,0)',filepb])
...
Cuando los almacenes ListStore o
TreeStore contienen un gran número de filas de datos la adición
de nuevas filas puede llegar a ser muy lenta. Hay un par de cosas que se pueden hacer para
mitigar este problema:
TreeModel) de su
vista (TreeView) usando el método
set_model() con el parámetro
model puesto a None evitar la
actualización de la vista (TreeView) con cada
inserción.set_default_sort_func() con el parámetro
sort_func puesto a None.TreeRowReference en uso también es importante, puesto que
se actualiza su camino con cada adición o emilinación de filas.TreeView)
"fixed-height-mode" a TRUE, de forma que todas las filas tengan la misma
altura y se evite el cálculo individual de la altura de cada fila. Esta opción solamente
está disponible a partir de la versión 2.4 de PyGTK.Es posible eliminar una fila de datos de un almacén
ListStore usando el método
remove() :
treeiter = liststore.remove(iter)
donde iter es un iterador
TreeIter que apunta a la fila que se ha de eliminar. El iterador
devuelto TreeIter (treeiter) apunta a
la siguiente fila o no es válido si iter apunta a la última fila.
El método clear() elimina todas las filas del
almacén ListStore:
liststore.clear()
Los métodos que sirven para eliminar filas de un almacén
TreeStore son similares a los métodos equivalentes
del almacén ListStore:
result = treestore.remove(iter)
treestore.clear()
donde result es TRUE
si la fila ha sido eliminada e iter apunta a la siguiente fila válida.
En otro caso, result es
FALSE e iter es
invalidado.
Los métodos para acceder a los valores de los datos en los almacenes
ListStore y TreeStore tienen el
mismo formato. Todas las manipulaciones de datos en almacenes usan un iterador
TreeIter que especifica la fila con la que se trabaja.
Una vez obtenido, dicho iterador (TreeIter) puede usarse
para obtener los valores de la columna de una fila utilizando el método
get_value() :
value = store.get_value(iter,column)
donde iter es un iterador
TreeIter que apunta a una fila,
column es un número de columna en el almacén
store, y, value es el valor
guardado en la posición fila-columna señalada.
Para obtener los valores de varias columnas en una única llamada se debe
usar el método get() :
values = store.get(iter, column, ...)
donde iter es un iterador
TreeIter que apunta a una fila, column
es un número de columna en el almacén store, y,
... representa cero o más números de columna adicionales y
values es una tupla que contiene los valores obtenidos.
Por ejemplo, para obtener los valores de las columnas 0 y 2:
val0, val2 = store.get(iter, 0, 2)
El método get() solamente está disponible
a partir de la versión 2.4 de PyGTK.
Para establecer el valor de una columna se emplea el método
set_value() :
store.set_value(iter,column,value)
donde iter (un iterador
TreeIter) y column (un entero)
especifican la posición fila-columna en el almacén store y
column es el número de columna cuyo valor
value debe ser fijado. value debe ser
del mismo tipo de dato que la columna del almacén store.
En el caso de que se desee establecer de una sola vez el valor de más de una
columna en una fila se debe usar el método set() :
store.set(iter,...)
donde iter especifica la fila del almacén y
... es uno o más pares de número de columna - valor que indican
la columna y el valor que se va a fijar. Por ejemplo, la siguiente llamada:
store.set(iter, 0, 'Foo', 5, 'Bar', 1, 123)
establece el valor de la primera columna como 'Foo', el de la sexta columna como
'Bar' y el de la segunda columna como 123, en la fila del almacén store
especificada por el iterador iter.
Se pueden mover individualmente las filas de un almacén
ListStore usando alguno de los siguientes métodos
disponibles desde la versión 2.2 de PyGTK:
liststore.swap(a,b) liststore.move_after(iter,position) liststore.move_before(iter,position)
swap() permuta la posición de las filas a las que
hacen referencia los iteradores TreeIter a
y b. move_after() y
move_before() mueven la fila señalada por el iterador
(TreeIter) iter a una posición anterior o
posterior a la fila indicada por el iterador (TreeIter)
position. Si position tiene el valor
None, move_after() situará la fila al principio
principio del almacén, mientras que move_before() lo hará
al final del mismo.
En caso de que se desee reorganizar completamente las filas de datos de un
almacén ListStore entonces es preferible usar el siguiente
método:
liststore.reorder(new_order)
donde new_order es una lista de enteros que
especifican el nuevo orden de filas de la siguiente manera:
new_order[nuevaposición] = antiguaposición
Por ejemplo, si liststore contuviese
cuatro filas:
'one' 'two' 'three' 'four'
La llamada al método:
liststore.reorder([2, 1, 3, 0])
produciría el siguiente orden:
'three' 'two' 'four' 'one'
Estos métodos únicamente reorganizarán almacenes
ListStore no ordenados.
En el caso de querer reorganizar las filas de datos en la versión 2.0 de PyGTK es necesario recurrir a la eliminación e inserción de filas utilizando los métodos descritos en las secciones Adición de filas y Eliminación de filas.
Los métodos que se usan para reorganizar las filas de un almacén
TreeStore son semejantes a los utilizados con los almacenes
del tipo ListStore, exceptuando que los primeros únicamente
afectan a las filas hijas de una determinada fila madre. Es decir, no es posible, por ejemplo,
intercambiar filas con filas madre distintas.:
treestore.swap(a,b) treestore.move_after(iter,position) treestore.move_before(iter,position)
swap() intercambia las posiciones de las filas
hija indicadas por los iteradores (TreeIter) a y
b. a y
b deben compartir su fila madre.
move_after() y
move_before() mueven la fila indicada por el iterador
(TreeIter) iter a una posición posterior
o anterior a la fila señalada por el iterador (TreeIter)
position. iter y
position deben compartir su fila madre. Si
position tiene el valor None,
move_after() situará la fila al principio del almacén,
mientras que el método move_before() lo hará al final del mismo.
El método reorder() precisa un parámetro
adicional que especifique la fila madre cuyas filas hijas serán reordenadas:
treestore.reorder(parent,new_order)
donde new_order es una lista de enteros que
especifican el nuevo orden de filas hijas de la fila madre especificada por el iterador
(TreeIter) parent de la siguiente
manera:
new_order[nuevaposición] = antiguaposición
Por ejemplo, si treestore contuviese estas
cuatro filas:
'parent'
'one'
'two'
'three'
'four'
La llamada al método:
treestore.reorder(parent, [2, 1, 3, 0])
produciría el siguiente orden:
'parent'
'three'
'two'
'four'
'one'
Estos métodos únicamente reorganizarán almacenes
TreeStore no ordenados.
Uno de los aspectos más problemáticos de la manipulación de almacenes
ListStore y TreeStore es el trabajo con
múltiples filas, como por ejemplo, mover varias filas de una fila madre a otra, o eliminar
un conjunto de filas en función de determinados criterios. La dificultad surge de la necesidad
de utilizar un iterador TreeIter que puede no ser ya válido como
resultado de la operación que se realice. Es posible comprobar si los iteradores de unos almacenes ListStore y TreeStore con persistentes utilizando el método get_flags() y contrastando la existencia de la bandera gtk.TREE_MODEL_ITERS_PERSIST. Sin embargo, las clases apilables del tipo TreeModelFilter y
TreeModelSort no poseen iteradores
TreeIter persistentes.
Si aceptamos que los iteradores TreeIter no son
persistentes, ¿cómo movemos todas las filas hijas de una dada a otra?. Para ello tenemos
que:
No podemos confiar en que el método remove()
devuelva un iterador TreeIter correcto, por lo que simplemente
solicitaremos el iterador del primer descendiente hasta que devuelva None.
Una función posible para mover filas hijas sería:
def move_child_rows(treestore, from_parent, to_parent):
n_columns = treestore.get_n_columns()
iter = treestore.iter_children(from_parent)
while iter:
values = treestore.get(iter, *range(n_columns))
treestore.remove(iter)
treestore.append(to_parent, values)
iter = treestore.iter_children(from_parent)
return
La función anterior abarca el caso sencillo en el que se mueven todas las filas hijas
de una única fila madre, pero ¿qué ocurre si se desea elminar todas las filas del almacén
TreeStore en función de determinado criterio, por ejemplo, el
valor de la primera columna?. A primera vista, se podría pensar en la posibilidad de usar el
método foreach(), de manera que se itere sobre todas las filas
y entonces se eliminarían las que cumpliesen el criterio elegido:
store.foreach(func,user_data)
donde func es una función que es llamada por cada
fila y tiene la siguiente signatura:
def func(model,path,iter,user_data):
donde model es el almacén de datos
TreeModel, path es
el camino de una fila en el modelo model,
iter es un iterador TreeIter que apunta al camino path y user_data son los datos
aportados. Si func devuelve
TRUE entonces el método foreach() dejará
de iterar y retornará.
El problema con este enfoque es que al cambiar los contenidos del almacén
mientras se produce la iteración del método foreach() puede
dar lugar a resultados impredecibles. El uso del método foreach()
para crear y guardar referencias persistentes TreeRowReferences de las filas que van
a ser eliminadas, para posteriormente eliminar estas referencias tras la finalización del método
foreach() podría ser una estrategia adecuada, salvo que no funcionaría en las versiones 2.0 y 2.2 de PyGTK, donde no están disponibles las referencias
persistentes del tipo TreeRowReference.
Una estrategia fiable que abarca todas las variantes de PyGTK consiste en
llamar al método foreach() para reunir los caminos de las
filas que se van a eliminar y luego proceder a eliminar dichas filas en orden inverso, de
forma que se preserve la validez de los caminos en el árbol. El siguiente fragmento de código
ejemplifica esta estrategia:
...
# esta función selecciona una fila si el valor de la primera columna es >= que el valor de comparación
# data es una tupla que contiene el valor de comparación y una lista para guardar los caminos
def match_value_cb(model, path, iter, data):
if model.get_value(iter, 0) >= data[0]:
data[1].append(path)
return False # mantiene la iteración de foreach
pathlist = []
treestore.foreach(match_value_cb, (10, pathlist))
# foreach funciona en orden de llegada (FIFO)
pathlist.reverse()
for path in pathlist:
treestore.remove(treestore.get_iter(path))
...
En el caso de que se quisiese buscar en un almacén
TreeStore la primera fila que cumpliese determinado criterio,
probablemente sería preferible llevar a cabo personalmente la iteración con algo similar a:
treestore = TreeStore(str)
...
def match_func(model, iter, data):
column, key = data # data es una tupla que contiene número de columna, clave (key)
value = model.get_value(iter, column)
return value == key
def search(model, iter, func, data):
while iter:
if func(model, iter, data):
return iter
result = search(model, model.iter_children(iter), func, data)
if result: return result
iter = model.iter_next(iter)
return None
...
match_iter = search(treestore, treestore.iter_children(None),
match_func, (0, 'foo'))
La función de búsqueda search() itera recursivamente
sobre la fila (especificada por el iterador iter) y sus descendientes
y sus fijas hijas en orden de llegada, en búsqueda de una fila que tenga una columna
cuyo valor coincida con la cadena clave dada. La búsqueda termina al encontrarse
una fila.
Las clases que implementan la interfaz TreeModel
(TreeStore y
ListStore y en PyGTK 2.4 también
TreeModelSort y
TreeModelFilter) también soportan los protocolos de Python de
mapeado e iteración (protocolos mapping e iterator). El protocolo de iterador permite
usar la función de Python iter() sobre un
TreeModel o crear un iterador que sirva para iterar sobre todas
las filas superiores del TreeModel. Una característica
más útil es la de iterar utilizando la orden for o la comprensión de listas. Por
ejemplo:
...
liststore = gtk.ListStore(str, str)
...
# añadimos algunas filas al almacén liststore
...
# bucle for
for row in liststore:
# procesado de cada fila
...
# comprensión de lista que devuelve una lista de los valores de la primera columna
values = [ r[0] for r in liststore ]
...
Otras partes del protocolo de mapeado que están soportadas son el uso
de del para eliminar un fila del modelo y la obtención de un
TreeModelRow de PyGTK del modelo utilizando un valor de
clave que sea un camino o in iterador TreeIter. Por
ejemplo, las siguientes instrucciones devuelven la primera fila de un modelo
TreeModel y la instrucción final borra la primera fila hija de la
primera fila:
row = model[0] row = model['0'] row = model["0"] row = model[(0,)] i = model.get_iter(0) row = model[i] del model[(0,0)]
Además, se pueden fijar los valores en una fila existente de forma parecida a esto:
...
liststore = gtk.ListStore(str, int, object)
...
liststore[0] = ['Button', 23, gtk.Button('Label')]
Los objetos TreeModelRow de PyGTK soportan
los protocolos de Python de secuencia e iterador. Se puede obtener un iterador para
recorrer los valores de columna en una fila o utilizar la instrucción for así como la
comprensión de listas. Un TreeModelRow utiliza el número
de columna como índice para extraer un valor. Por ejemplo:
...
liststore = gtk.ListStore(str, int)
liststore.append(['Random string', 514])
...
row = liststore[0]
value1 = row[1]
value0 = liststore['0'][0]
for value in row:
print value
val0, val1 = row
...
Haciendo uso del ejemplo de la sección anterior para iterar sobre un almacén
TreeStore y localizar una fila que contenga un valor concreto, el código quedaría:
treestore = TreeStore(str)
...
def match_func(row, data):
column, key = data # data es una tupla que contiene número de columna, clave (key)
return row[column] == key
...
def search(rows, func, data):
if not rows: return None
for row in rows:
if func(row, data):
return row
result = search(row.iterchildren(), func, data)
if result: return result
return None
...
match_row = search(treestore, match_func, (0, 'foo'))
También se puede fijar el valor de una columna utilizando:
treestore[(1,0,1)][1] = 'abc'
Un TreeModelRow también soporta la instrucción
del y la conversión a listas y tuplas utilizando las funciones de Python
list() and tuple(). Tal como se ilustra en el
ejemplo superior, un objeto TreeModelRow posee el
método iterchildren(), que devuelve un iterador para
recorrer las filas hijas del objeto TreeModelRow.
Las aplicaciones pueden seguir los cambios de un modelo
TreeModel conectándose a las señales que son emitidas
por un modelo TreeModel: "row-changed" (fila modificada),
"row-deleted" (fila eliminada), "row-inserted" (fila insertada), "row-has-child-toggled" (cambio de fila tiene descendencia) y
"rows-reordered" (filas reordenadas). Estas señales son utilizadas por las vistas
TreeView para seguir los cambios en su modelo
TreeModel.
Si una aplicación se conecta a estas señales es posible que se produzcan grupos de señales al llamar algunos métodos. Por ejemplo, una llamada para añadir la primera fila a una fila madre:
treestore.append(parent, ['qwe', 'asd', 123])
causará la emisión de las siguientes señales:
parent) no tenía previamente ninguna fila hija.Nótese que no es posible obtener el orden de las fila en la retrollamada de "rows-reordered" puesto que el nuevo orden de las filas se pasa como un puntero opaco a un vector de enteros.
Consulte el Manual de Referencia de PyGTK para saber más sobre las señales de
TreeModel.
Los objetos ListStore y
TreeStore implementan la interfaz
TreeSortable que les aporta métodos para controlar la
ordenación de las filas de un modelo TreeModel. El elemento
clave de la interfaz es "sort column ID", que es un valor entero arbitrario que está referido a
una función de comparación de orden y a unos datos asociados de usuario. Dicho identificador
de orden de columna debe ser mayor o igual a cero, y se crea utilizando el siguiente
método:
treesortable.set_sort_func(sort_column_id,sort_func,user_data=None)
donde sort_column_id es un valor entero asignado
por el programador, sort_func es una función o método
utilizado para comparar filas y user_data son los datos
contextuales. sort_func tiene la siguiente signatura:
def sort_func_function(model, iter1, iter2, data) def sort_func_method(self, model, iter1, iter2, data)
donde model el el modelo
TreeModel que contiene las filas señaladas por los iteradores
TreeIter iter1 e
iter2 y data es
user_data. sort_func debería
devolver: -1 si la fila correspondiente a iter1 debe preceder a la
fila correspondiente a iter2; 0, si las filas son iguales; y, 1 si
la fila correspondiente a iter2 debe preceder a la indicada por
iter1. La función de comparación de orden debería presuponer
siempre que el orden de clasificación es ascendente (gtk.SORT_ASCENDING)
puesto que el orden de clasificación será tenido en cuenta por las implementaciones de
TreeSortable.
Puede usarse la misma función de comparación de orden para varios
identificadores de orden de columna, haciendo variar los datos de información
contextual contenidos en user_data. Por ejemplo, los datos
user_data especificados en el método
set_sort_func() podrían consistir en los índices de las
columnas de donde se extraerían los datos de clasificación.
Una vez que se ha creado un identificador de orden de columna (sort column ID) en un almacén, es posible usarla para ordenar los datos llamando al método:
treesortable.set_sort_column_id(sort_column_id,order)
donde order es el orden de clasificación, bien
gtk.SORT_ASCENDING (ascendente) o
gtk.SORT_DESCENDING (descendente).
Un identificador de orden de columna (sort_column_id) de
valor igual a -1 indica que el almacén debería utilizar la función de
comparación por defecto que se establece a través del método:
treesortable.set_default_sort_func(sort_func,user_data=None)
Es posible comprobar si un almacén tiene una función de comparación por defecto haciendo uso del método:
result = treesortable.has_default_sort_func()
que devuelve TRUEsi se ha establecido una función por defecto
para las comparaciones.
Una vez que se ha establecido un identificador de orden de columna para
un modelo TreeModel que implementa la interfaz
TreeSortable este modelo ya no puede volver al estado
original no ordenado. Es posible cambiar su función de clasificación o utilizar la función por
defecto, pero ya no es posible establecer que ese modelo
TreeModel carezca de dicha función.
Cuando se crea un objeto del tipo ListStore o
TreeStore automáticamente se establecen identificadores de orden
de columna que se corresponden con el número de índice de las columnas. Por
ejemplo, un almacén ListStore con tres columnas
tendrían tres identificadores de orden de columna (0, 1, 2) generados automáticamente.
Estos identificadores están asociados a una función de comparación interna que maneja los
tipos fundamentales:
Inicialmente, tanto los almacenes ListStore como los
TreeStore se fijan con un identificador de orden de columna igual a
-2, que indica que no se utiliza una función de ordenación y que el almacén no está ordenado. Una vez que se fija un identificador de clasificación de columna en un
ListStore o TreeStore ya no es
posible volver a establecerlo al valor -2.
En caso de que se desee mantener los identificadores de orden de columna por defecto se debe establecer su valor fuera del rango del número de columnas, tal como 1000 o más. entonces es posible cambiar entre las funciones de ordenación por defecto y las de la aplicación según sea necesario.