Trabajando con la familia GtkTreeView |
---|
El modelo GtkListStore permite almacenar los datos como un arreglo o tabla plana.
El prototipo de la función que permite crear un ListStore es como sigue:
GtkListStore* gtk_list_store_new( | n_columns, | |
...) ; |
gint | n_columns; |
| ...; |
El primer argumento indica el número de columnas y los
siguientes, indican el tipo de dato de cada columna. De esta
forma es posible indicar algún tipo definido en
GType
(tales como G_TYPE_BOOLEAN,
G_TYPE_INT, G_TYPE_FLOAT, G_TYPE_CHAR, G_TYPE_STRING, etc.)
para definir algunos de los tipos de datos comunes, o
algun otro, como GDK_TYPE_PIXBUF, para tipos de datos
especiales como imágenes.
Ejemplo 2. Creación de un modelo GtkListStore
GtkListStore *model; model = gtk_list_store_new (NUM_COLUMNS, G_TYPE_INT, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_BOOLEAN); /* Algún código para agregarlo a un widget GtkTreeView */ g_object_unref (G_OBJECT (model))
En Ejemplo 2, “Creación de un modelo GtkListStore” se
ha indicado que se desea crear un nuevo GtkListStore, el
cual constará de NUM_COLUMNS
columnas
(de acuerdo a la definición en Ejemplo 1, “Una lista enumerada típica”
corresponde a 4). Los siguientes argumentos son
los tipos de datos de cada una de las columnas. Así,
se pasarán tantos argumentos como sea el valor de
NUM_COLUMNS
.
Para efectos de ejercitación, se han indicado cuatro diferentes
tipos de datos, para mostrar distintas formas de manejo
de éstos.
Con excepción de la función
gtk_list_store_new
, todas las funciones
del tipo gtk_list_store_
reciben
como primer argumento el objeto sobre el cual se realizará
la operación indicada.
Una vez que se ha creado el modelo, es necesario problarlo con datos, en este caso es necesario realizar dos pasos:
Añadir una fila vacía
Asignar valores a la nueva fila
Para el primer paso se debe emplear alguna de las siguientes funciones, dependiendo del lugar donde se deseen añadir los datos:
void gtk_list_store_insert( | *list_store, | |
*iter, | ||
position) ; |
GtkListStore | *list_store; |
GtkTreeIter | *iter; |
gint | position; |
void gtk_list_store_insert_before( | *list_store, | |
*iter, | ||
*sibling) ; |
GtkListStore | *list_store; |
GtkTreeIter | *iter; |
GtkTreeIter | *sibling; |
void gtk_list_store_insert_after( | *list_store, | |
*iter, | ||
*sibling) ; |
GtkListStore | *list_store; |
GtkTreeIter | *iter; |
GtkTreeIter | *sibling; |
void gtk_list_store_append( | *list_store, | |
*iter) ; |
GtkListStore | *list_store; |
GtkTreeIter | *iter; |
void gtk_list_store_prepend( | *list_store, | |
*iter) ; |
GtkListStore | *list_store; |
GtkTreeIter | *iter; |
Se ha añadido una nueva variable,
&iter
, la cual es una estructura
GtkTreeIter.
GtkTreeIter es un puntero a un nodo particular. Si el modelo se analiza desde el punto de vista de una tabla, con filas y columnas, un GtkTreeIter entrega la fila.
Al usar la función
gtk_list_store_append
se ha
añadido una nueva fila al modelo, la cual se encuentra vacía.
Con el parámetro &iter
se obtiene
la posición en donde ha sido añadida.
En la nueva fila (apuntada por &iter
)
se asignan los valores de cada columna. En este caso, sólo
se ha añadido el valor a la columna COLUM_MOVE, que es
de tipo GDK_TYPE_PIXBUF. Para ello, existen la funciones
gtk_list_store_set_value
o
gtk_list_store_set
. La única
diferencia entre ambas, es que la segunda permite asignar
los valores de varias columnas a la vez.
El primer argumento es el modelo, el segundo es la fila, el tercero la columna y el cuarto el valor. El tipo de dato del valor debe ser el mismo definido para cada columna en el modelo.
Si se necesitara agregar todos los valores de inmediato,
entonces la función gtk_list_store_set
se invocaría de la siguiente manera:
gtk_list_store_set (model, &iter, COLUMN_STATE, 15, COLUMN_COMMENTS, "Trabajar con ListStore es divertido", COLUMN_MOVE, pixbuf, COLUMN_EDITABLE, TRUE, -1);
La idea es muy similar a
gtk_list_store_value
, se indica
el modelo, la fila, y luego sigue con un par de datos
que indican la columna y su respectivo valor. Finalmente,
se termina con -1
para indicar
a la función el fin de los argumentos.
Ejemplo 4. Comparación entre gtk_list_store_set_value y gtk_list_store_set
gtk_list_store_set (model, &iter, COLUMN_STATE, 15, COLUMN_COMMENTS, "Trabajar con ListStore es divertido", COLUMN_MOVE, pixbuf, COLUMN_EDITABLE, TRUE, -1); gtk_list_store_set_value (model, &iter, COLUMN_COMMENTS, "Trabajar con ListStore es divertido"); gtk_list_store_set_value (model, &iter, COLUMN_MOVE, pixbuf); gtk_list_store_set_value (model, &iter, COLUMN_EDITABLE, TRUE);
En Ejemplo 4, “
Comparación entre gtk_list_store_set_value y gtk_list_store_set
” se
muestra la misma asignación de valores a
model
realizada todas de una vez con
gtk_list_store_set
y columna por
columna a través de
gtk_list_store_value
.
El parámetro iter
indica la fila en
la cual se debe realizar la inserción, y cuyo valor se
obtuvo al llamar a alguna de las funciones de inserción de
filas.
Para cargar imágenes, se requiere definir un tipo de dato Pixbuf.
GdkPixbuf *pixbuf;
Para cargar una imagen definida en una variable, típicamente un XPM,
pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) image_xpm);
En este caso, se debe definir a priori la variable image_xpm.
Si la imagen a cargar no se encuentra definida en una variable, sino que se desea cargar desde un archivo, entonces se emplea:
pixbuf = gdk_pixbuf_new_from_file ("imagen.png", NULL);
GtkTreeIter iter; GdkPixbuf *pixbuf; /* ... */ pixbuf = gdk_pixbuf_new_from_file ("imagen.png", NULL); gtk_list_store_append (model, &iter); gtk_list_store_set_value (model, &iter, COLUMN_MOVE, pixbuf);
Para modificar un dato de una celda en
particular, se requiere conocer la fila y columna
en la cual se llevará a cabo la operación. La manera
de hacerlo es muy similar a la inserción, empleando
las funciones
gtk_list_store_set_value
o
gtk_list_store_set
de la
misma forma, la excepción es que ya no se requiere
agregar una nueva fila. Sin embargo, para poder realizar la
modificación es necesario conocer la fila
(iter
) en la cual se desea modificar
los datos.
Para eliminar una fila, se requiere conocer su posición,
la cual se obtiene a través de un GtkTreeIter, y
posteriormente llamando a
la función gtk_list_store_remove
,
la cual tiene el siguiente prototipo:
void gtk_list_store_remove (GtkListStore *list_store, GtkTreeIter *iter);
Si se quisiera eliminar la fila que se encuentra activa, se obtiene su posición y se remueve de la siguiente forma:
gtk_tree_model_get_iter (model, &iter, path); gtk_list_store_remove (model, &iter);
Como se puede notar, es muy similar a los casos
anteriores. A diferencia de la inserción,
en la edición y eliminación es necesario
indicar en forma correcta el parámetro
&iter
, ya que
en estos casos debe ser válido, de lo
contrario provocará una excepción en la
última llamada. Es por ello que se utiliza
gtk_tree_model_get_iter
,
de tal manera de obtener un puntero válido a una
fila.
También se puede apreciar que para obtener la
estructura GtkTreeIter,
se requiere de otro parámetro, GtkTreePath
path
. Un GtkTreePath
es una tupla de enteros que representan una
posición en el árbol. Por ejemplo, 1:4:41
significa "el hijo 42 del quinto hijo del
segundo hijo del nivel raíz" (no hay que
olvidar que los índices comienzan en 0).
Si se altera el contenido del árbol, un GtkTreePath
particular puede quedar apuntando a un nodo
diferente o incluso, no ser válido.
A través de un GtkTreeIter se puede obtener
un puntero a GtkTreePath, y viceversa. Por
ejemplo, si se conoce el parámetro
iter
, se puede obtener
el path de la siguiente manera:
GtkTreePath *path; path = gtk_tree_model_get_path (model, &iter); /* ... */ gtk_tree_path_free (path);
Finalmente, cuando ya no se necesite el
path
, se debe liberar
la memoria con
gtk_tree_path_free
Para obtener una referencia dura a un nodo,
se debe emplear la estructura GtkTreeRowReference
y emplear la función
gtk_tree_row_reference_new
,
la cual crea una referencia de un nodo a partir
de un GtkTreePath. Esta referencia se actualizará
automáticamente cada vez que se modifique el
modelo, de esta forma se puede apuntar siempre
al mismo nodo, independiente de las alteraciones
que sufra el modelo. Por ejemplo:
GtkTreeRowReference *nodeXY; GtkTreePath *path; path = gtk_tree_path_new_from_string ("1:2"); nodoXY = gtk_tree_row_reference_new (model, path);
Sin embargo, si la referencia (path) no existe en el
modelo model
, nodeXY
será NULL
.
<< Trabajando con modelos | El modelo GtkTreeStore >> |