Los objetos TreeModelSort y
TreeModelFilter son modelos de árbol que se interponen
entre el TreeModel de base (bien un
TreeStore o un ListStore) y
el TreeView que proporciona un modelo modificado mientras
retiene la estructura original del modelo base. Estos modelos interpuestos
implementan las interfaces TreeModel y
TreeSortable pero no proporcionan ningún método para insertar
o eliminar filas del modelo. Estas se deben insertar o eliminar del almacén subyacente.
TreeModelSort proporciona un modelo cuyas filas están siempre
ordenadas, mientras que TreeModelFilter proporciona un
modelo que contiene un subconjunto de las filas del modelo base.
Si se desea, estos modelos pueden encadenarse en una sucesión arbitraria; es decir,
un TreeModelFilter podría tener un
TreeModelSort hijo, que podría tener otro
TreeModelFilter hijo, y así sucesivamente. Mientras haya un almacén
TreeStore o ListStore en el extrremo final
de la cadena, todo debería funcionar. En PyGTK 2.0 y 2.2 los objetos
TreeModelSort y TreeModelFilter no
soportan el protocolo de mapeado de Python para TreeModel.
TreeModelSort mantiene un modelo ordenado del
modelo hijo especificado en su constructor. El uso principal de un
TreeModelSort el el de proporcionar múltiples vistas de un modelo
que puedan ser ordenadas de forma distinta. Si se tienen múltiples vistas del mismo modelo
entonces cualquier actividad de ordenación se ve reflejada en todas las vistas. Al usar
un TreeModelSort el almacén base permanecen en su estado
original, mientras que los modelos ordenados absorben toda la actividad de ordenación. Para
crear un TreeModelSort se ha de usar el constructor:
treemodelsort = gtk.TreeModelSort(child_model)
donde child_model es un
TreeModel. La mayoría de los métodos de un
TreeModelSort tienen que ver con la conversión de los caminos de árbol e iteradores TreeIter desde el modelo hijo al modelo
ordenado y viceversa:
sorted_path = treemodelsort.convert_child_path_to_path(child_path) child_path = treemodelsort.convert_path_to_child_path(sorted_path)
Estos métodos de conversión de caminos devuelven None si
el camino dado no puede ser convertido en un camino del modelo ordenado o el modelo hijo
respectivamente. Los métodos de conversión de los iteradores
TreeIter son:
sorted_iter = treemodelsort.convert_child_iter_to_iter(sorted_iter,child_iter) child_iter = treemodelsort.convert_iter_to_child_iter(child_iter,sorted_iter)
Los métodos de conversión de iteradores TreeIter
duplican el argumento convertido (es tanto el valor de retorno como el primer argumento)
debido a cuestiones de compatiblidad con versiones anteriores; se deben fijar el primer
argumento como None y simplemente utilizar el valor devuelto. Por ejemplo:
sorted_iter = treemodelsort.convert_child_iter_to_iter(None, child_iter) child_iter = treemodelsort.convert_iter_to_child_iter(None, sorted_iter)
Al igual que los métodos de conversión de caminos, estos métodos devuelven
None si el TreeIter dado no puede ser
convertido.
Se puede obtener el TreeModel hijo
usando el método get_model().
Un ejemplo sencillo que utiliza un objeto
TreeModelSort es treemodelsort.py. Figura 14.9, “Ejemplo de TreeModelSort” ilustra el resultado de ejecutar el programa y añadir seis filas:
En cada una de las columnas de las ventanas se puede hacer click para
cambiar el orden de los elementos de forma independiente al de otras ventanas. Cuando se
pulsa el botón "" se añade una nueva fila al ListStore base y
la nueva fila se muestra en cada TreeView como la fila
seleccionada.
El objeto TreeModelFilter está disponible a partir de
la versión 2.4 de PyGTK y posteriores.
Un objeto TreeModelFilter proporciona varias formas
de modificar la visualización del TreeModel de base, y
permiten:
TreeIter que apunta
a la fila del modelo hijo, y datos de usuario. En ambos casos si el valor booleano es
TRUE la fila se mostrará; de otro modo, la fila quedará oculta.TreeStore.Un objeto TreeModelFilter se crea usando el método
de TreeModel:
treemodelfilter = treemodel.filter_new(root=None)
donde root es un camino de árbol en
treemodel que especifica la raiz virtual del modelo
o None si se va a usar el nodo raíz de
treemodel.
Al establecer una "raíz virtual" cuando se crea el
TreeModelFilter, se puede limitar la vista del modelo a las
filas hijas de la fila "raíz" en la jerarquía del modelo hijo. Esto, naturalmente, solamente es útil
cuando el modelo hijo está basado en un TreeStore. Por ejemplo,
si se desea proporcionar una vista parcial del contenido de una unidad de CDROM,
independiente del resto de elementos del ordenador.
Los modos de visibilidad son mútuamente excluyentes y únicamente se pueden fijar una vez. Es decir, una vez que se ha establecido una función o columna de visibilidad no puede ser cambiada y el modo alternativo no puede establecerse. El modo de visibilidad más simple extrae un valor booleano de una columna en el modelo hijo para determinar si la fila debería mostrarse. La columna de visibilidad se detemina usando:
treemodelfilter.set_visible_column(column)
donde column es el número de columna en el
TreeModel hijo, del que extraer los valores booleanos. Por
ejemplo, el siguiente fragmento de código usa los valores de la tercera columna para determinar
la visibilidad de las filas:
... treestore = gtk.TreeStore(str, str, "gboolean") ... modelfilter = treestore.filter_new() modelfilter.set_visible_column(2) ...
De esta manera, se mostrará cualquier fila de treestore
que tenga un valor TRUE en la tercera columna.
Si se tiene criterios de visibilidad más complicados, una función de visibilidad debería proporcionar suficientes posibilidades:
treemodelfilter.set_visible_func(func,data=None)
donde func es la función llamada para cada una de las
filas del modelo hijo y determinar si se debe mostrar y
data son datos de usuario pasados a
func. func debería devolver
TRUE si la fila debe ser mostrada. La signatura de
func es:
def func(model,iter,user_data)
donde model es el
TreeModel hijo, iter es un
TreeIter que apunta a una fila en
model y user_data son los datos
data entregados.
Si se hacen cambios en los criterios de visibilidad se debería hacer la llamada:
treemodelfilter.refilter()
para forzar un refiltrado de las filas del modelo hijo.
Por ejemplo, el siguiente fragmento de código ilustra el uso de un
TreeModelFilter que muestra filas en base a una comparación
entre el valor de la tercera columna y los contenidos de los datos de usuario:
...
def match_type(model, iter, udata):
value = model.get_value(iter, 2)
return value in udata
...
show_vals = ['OPEN', 'NEW', 'RESO']
liststore = gtk.ListStore(str, str, str)
...
modelfilter = liststore.filter_new()
modelfilter.set_visible_func(match_type, show_vals)
...
El programa treemodelfilter.py ilustra el uso del método
set_visible_func(). Figura 14.10, “Ejemplo de Visibilidad en TreeModelFilter” muestra el resultado de la ejecución del programa.
Conmutando los botones de la parte inferior se cambian los contenidos del
TreeView para mostrar únicamente las filas que coinciden con
uno de los botones activos.
Una función de modificación proporciona otro nivel de control sobre la visualización
en el TreeView hasta el punto en el que es posible sintetizar
una o más columnas (incluso todas), que son representadas por el
TreeModelFilter. Todavía es preciso usar un modelo hijo que
sea un almacén TreeStore o
ListStore para determinar el número de filas y la jerarquía, pero
las columnas pueden ser las que se especifiquen en el método:
treemodelfilter.set_modify_func(types,func,data=None)
donde types es una secuencia (lista or tupla)
que especifica los tipos de las columnas que se representan, func
es una función llamada para devolver el valor para una fila y columna y
data es un argumento que pasar a
func. La signatura de func
es:
def func(model,iter,column,user_data)
donde model es el
TreeModelFilter, iter es un
TreeIter que apunta a una fila del modelo,
column es el número de la columna para el que se precisa un valor y
user_data es el parámetro
data. func debe devolver un valor
que coincida con el tipo de column.
Una función de modificación es útil cuando se quiere proporcionar una columna de
datos que necesita ser generada utilizando los datos de las columnas del modelo hijo. Por
ejemplo, si se tuviese una columna que contiene fechas de nacimiento y se quisiese mostrar
una columna de edades, una función de modificación podría generar la información de edad
usando la fecha de nacimiento y la fecha actual. Otro ejemplo sería el decidir qué imagen mostrar
en base al análisis de los datos (por ejemplo, el nombre de un archivo) de una columna. Este
efecto también se puede conseguir utilizando el método
TreeViewColumn
set_cell_data_func().
Generalmente, dentro de la función de modificación, se tendrá que convertir el
TreeModelFilter TreeIter a un iterador
TreeIter del modelo hijo haciendo uso de:
child_iter = treemodelfilter.convert_iter_to_child_iter(filter_iter)
Naturalmente, también es necesario obtener el modelo hijo usando:
child_model = treemodelfilter.get_model()
Estos métodos dan acceso a la fila del modelo hijo y a sus valores para generar
el valor de la fila y columna especificadas del
TreeModelFilter. También hay un método para convertir
un TreeIter hijo a un
TreeIter de un modelo filtrado y métodos para convertir caminos
del modelo filtrado a y desde caminos de los árboles hijo:
filter_iter = treemodelfilter.convert_child_iter_to_iter(child_iter) child_path = treemodelfilter.convert_path_to_child_path(filter_path) filter_path = treemodelfilter.convert_child_path_to_path(child_path)
Naturalmente, es posible combinar los modos de visibilidad y la función de modificación
para filtrar y sintetizar columnas. Para obtener incluso un mayor control sobre la vista sería
necesario utilizar un TreeModel personalizado.