El widget GtkCList ha reemplazado al widget GtkList (que sigue estando disponible).
El widget GtkCList es un widget de una lista multicolumna que es capaz de manejar, literalmente, miles de filas de información. Cada columna puede tener (opcionalmente) un título, que puede estar activado (opcionalmente), permitiéndonos enlazar una función con la selección.
Crear un GtkCList es algo bastante sencillo, una vez que sabe como crear un widget en general. Se proporcionan al menos dos formas estándar de crearlo, la forma fácil y la forma difícil. Pero antes de crear una GtkCList, hay una cosa que debemos saber: ¿Cuántas columnas va a tener?
No todas las columnas tienen que ser visibles y pueden utilizarse para almacenar datos que estén relacionados con una cierta celda de la lista.
GtkWidget *gtk_clist_new ( gint columns );
GtkWidget *gtk_clist_new_with_titles( gint columns,
gchar *titles[] );
Esta primera aproximación al problema es muy sencilla, pero la segunda requerirá alguna explicación adicional. Cada columna puede tener un título asociado. Si utilizamos la segunda forma, deberemos proporcionar punteros al texto del título, y el número de punteros debe ser igual al número de columnas especificadas. Por supuesto, siempre podemos utilizar la primera forma de creación y añadir más tarde los títulos de forma manual.
Hay varios atributos que pueden utilizarse para alterar el aspecto de un GtkCList. Primero tenemos
void gtk_clist_set_selection_mode( GtkCList *clist,
GtkSelectionMode mode );
que, como el propio nombre indica, establece el modo de selección de la
lista GtkCList. El primer argumento es el widget GtkCList, y el
segundo especifica el modo de selección de la celda (están definidos
en gtkenums.h
). En el momento de escribir esto, estaban
disponibles los siguientes modos:
Puede que se añadan otros modos en versiones posteriores de GTK.
También tenemos
void gtk_clist_set_policy (GtkCList *clist,
GtkPolicyType vscrollbar_policy,
GtkPolicyType hscrollbar_policy);
que define que es lo que ocurre con las barras de desplazamiento. Los siguientes valores son los posibles para las barras de desplazamiento horizontal y vertical:
También podemos definir como debería ser el aspecto del borde del widget GtkCList. Esto lo podemos hacer mediante
void gtk_clist_set_border( GtkCList *clist,
GtkShadowType border );
Y los posibles valores para el segundo argumento son
Cuando cree un widget GtkCList, también obtendrá automáticamente un conjunto de botones título. Vivirán en lo alto de una ventana CList, y pueden actuar como botones normales que responden cuando se pulsa sobre ellos, o bien pueden ser pasivos, en cuyo caso no serán nada más que un título. Hay cuatro llamadas diferentes que nos ayudarán a establecer el estado de los botones título.
void gtk_clist_column_title_active( GtkCList *clist,
gint column );
void gtk_clist_column_title_passive( GtkCList *clist,
gint column );
void gtk_clist_column_titles_active( GtkCList *clist );
void gtk_clist_column_titles_passive( GtkCList *clist );
Un título activo es aquel que actua como un botón normal, y uno pasivo
es sólo una etiqueta. Las primeras dos llamadas de arriba
activarán/desactivarán el botón título correspondiente a la columna
column
, mientras que las dos llamadas siguientes
activarán/desactivarán todos los botones título que hayan en el
widget clist
que se le proporcione a la función.
Pero, por supuesto, habrá casos en el que no querremos utilizar los botones título, así que también tenemos la posibilidad de ocultarlos y de volverlos a mostrar utilizando las dos llamadas siguientes:
void gtk_clist_column_titles_show( GtkCList *clist );
void gtk_clist_column_titles_hide( GtkCList *clist );
Para que los títulos sean realmente útiles necesitamos un mecanismo que nos permita darles el valor que nosotros queramos y cambiar ese valor, y podremos hacerlo mediante
void gtk_clist_set_column_title( GtkCList *clist,
gint column,
gchar *title );
Debe llevar cuidado, ya que sólo se puede especificar el título de una
columna a la vez, por lo que si conoce todos los títulos desde el
principio, le sugiero que utilice gtk_clist_new_with_titles
(como
se describe arriba) para establecerlos adecuadamente. Le ahorrará
tiempo de programación, y hará su programa más pequeño. Hay algunos
casos donde es mejor utilizar la forma manual, y uno de ellos es
cuando no todos los títulos son texto. GtkCList nos proporciona
botones título que pueden, de hecho, incorporar un widget
entero, por ejemplo un pixmap. Todo esto se hace mediante
void gtk_clist_set_column_widget( GtkCList *clist,
gint column,
GtkWidget *widget );
que no debería necesitar de explicaciones adicionales.
Es posible cambiar la justificación de una columna, y esto se hace mediante
void gtk_clist_set_column_justification( GtkCList *clist,
gint column,
GtkJustification justification );
El tipo GtkJustification puede tomar los valores siguientes:
La siguiente función es muy importante, y debería ser un estándar para inicializar todos los widgets GtkCList. Cuando se crea la lista, los anchos de las distintas columnas se eligen para que coincidan con sus títulos, y éste es el ancho adecuado que tenemos que poner, utilizando
void gtk_clist_set_column_width( GtkCList *clist,
gint column,
gint width );
Observe que el ancho viene dado en pixeles y no en letras. Lo mismo vale para el alto de la celda en las columnas, pero como el valor por defecto es la altura del tipo de letra actual, no es algo tan crítico para la aplicación. De todas formas, la altura se cambia mediante
void gtk_clist_set_row_height( GtkCList *clist,
gint height );
De nuevo, hay que advertir que el ancho viene dado en pixeles.
También podemos ir hacia un elemento sin la intervención del usuario, sin embargo hace falta que sepamos hacia donde queremos ir. O en otras palabras, necesitamos la fila y la columna del elemento al que queremos pasar.
void gtk_clist_moveto( GtkCList *clist,
gint row,
gint column,
gfloat row_align,
gfloat col_align );
Es importante comprender bien el significado de gfloat
row_align
. Tiene un valor entre 0.0 y 1.0, donde 0.0 significa que
debemos hacer que la fila seleccionada aparezca en la alto de la
lista, mientras que 1.0 significa que la fila aparecerá en la parte de
abajo. El resto de valores entre 0.0 y 1.0 son válidos y harán que la
fila aparezca entre la parte superior y la inferior. El último
argumento, gfloat col_align
funciona igual, siendo 0.0 la
izquierda y 1.0 la derecha.
Dependiendo de las necesidades de la aplicación, puede que no tengamos que hacer un desplazamiento hacia un elemento que ya sea visible. Por tanto, ¿cómo podemos saber si ya es visible? Como siempre, hay una función que sirve para averiguarlo
GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
gint row );
El valor devuelto es uno de los siguientes:
Como puede ver, sólo nos dice si una fila es visible. Actualmente no hay ninguna forma de obtener el mismo dato para una columna. Sin embargo podemos obtener información parcial, porque si el valor devuelto es GTK_VISIBILITY_PARTIAL, entonces es que alguna parte está oculta, pero no sabemos si es la fila que está cortada por la parte de abajo de la lista, o si la fila tiene columnas que están fuera.
También podemos cambiar el color del primer y del segundo plano de una fila en particular. Esto es útil para marcar la fila seleccionada por el usuario, y las dos funciones que hay que utilizar son
void gtk_clist_set_foreground( GtkCList *clist,
gint row,
GdkColor *color );
void gtk_clist_set_background( GtkCList *clist,
gint row,
GdkColor *color );
Cuidado, ya que los colores deben estar asignados previamente en la memoria.
Podemos añadir filas de dos formas. Se pueden añadir al final de la lista utilizando
gint gtk_clist_append( GtkCList *clist,
gchar *text[] );
o podemos insertar una fila en un lugar determinado utilizando
void gtk_clist_insert( GtkCList *clist,
gint row,
gchar *text[] );
En ambas llamadas podemos proporcionar un conjunto de punteros que
serán los textos que queremos poner en las columnas. El número de
punteros debe ser igual al número de columnas en la lista. Si el
argumento text[]
es NULL, entonces no habrá texto en las columnas
de la fila. Esto sería útil, por ejemplo, si queremos añadir
pixmaps en lugar de texto (en general para cualquier cosa que
haya que hacer manualmente).
De nuevo, cuidado ya que el número de filas y de columnas comienza en 0.
Para eliminar una fila individual podemos utilizar
void gtk_clist_remove( GtkCList *clist,
gint row );
Hay también una llamada que elimina todas las filas en la lista.
Es mucho más rápido que llamar a gtk_clist_remove
una vez por
cada fila, que sería la única alternativa.
void gtk_clist_clear( GtkCList *clist );
También hay dos funciones que es conveniente utilizarlas cuando hay que hacerle muchos cambios a una lista. Son para evitar que la lista parpadee mientras es actualizada repetidamente, que puede ser muy molesto para el usuario. Por tanto es una buena idea congelar la lista, hacer los cambios, y descongelarla, que hará que la lista se actualice en la pantalla.
void gtk_clist_freeze( GtkCList * clist );
void gtk_clist_thaw( GtkCList * clist );
Una celda puede contener un pixmap, texto o ambos. Para ponerlos en las celdas, podemos utilizar las siguientes funciones.
void gtk_clist_set_text( GtkCList *clist,
gint row,
gint column,
gchar *text );
void gtk_clist_set_pixmap( GtkCList *clist,
gint row,
gint column,
GdkPixmap *pixmap,
GdkBitmap *mask );
void gtk_clist_set_pixtext( GtkCList *clist,
gint row,
gint column,
gchar *text,
guint8 spacing,
GdkPixmap *pixmap,
GdkBitmap *mask );
Son bastante sencillas de entender. Todas las llamadas tienen la
GtkCList como primer argumento, seguidas por la fila y la columna
de la celda, y seguidas por el dato que debe ponerse en la celda. El
argumento gint8 spacing
en gtk_clist_set_pixtext
es el
número de pixels entre el pixmap y el principio del
texto.
Para leer los datos que hay en una celda, podemos utilizar
gint gtk_clist_get_text( GtkCList *clist,
gint row,
gint column,
gchar **text );
gint gtk_clist_get_pixmap( GtkCList *clist,
gint row,
gint column,
GdkPixmap **pixmap,
GdkBitmap **mask );
gint gtk_clist_get_pixtext( GtkCList *clist,
gint row,
gint column,
gchar **text,
guint8 *spacing,
GdkPixmap **pixmap,
GdkBitmap **mask );
No es necesario leer todos los datos en caso de que no estemos
interesados. Cualquiera de los punteros que se supone contendrán los
valores a devolver (cualquiera excepto el clist
) pueden ser
NULL. Por lo que si sólo queremos leer el texto de una celda que es de
tipo pixtext
, deberíamos hacer lo siguiente, suponiendo que
clist
, row
y column
ya existan:
gchar *mytext;
gtk_clist_get_pixtext(clist, row, column, &mytext, NULL, NULL, NULL);
Hay una rutina más que está relacionada con lo que está dentro
de una celda de una clist
, y es
GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
gint row,
gint column );
que devuelve el tipo de datos que hay en la celda. El valor devuelto es uno de los siguientes
También hay una función que nos permite especificar la indentación de
un celda (horizontal o vertical). El valor de la indentación es del
tipo gint
, viene dado en pixeles, y puede ser positivo o
negativo.
void gtk_clist_set_shift( GtkCList *clist,
gint row,
gint column,
gint vertical,
gint horizontal );
Con una GtkCList es posible poner un puntero a datos en una fila. Este puntero no será visible al usuario, pero puede serle útil al programador.
De nuevo, las funciones son lo suficientemente autoexplicativas
void gtk_clist_set_row_data( GtkCList *clist,
gint row,
gpointer data );
void gtk_clist_set_row_data_full( GtkCList *clist,
gint row,
gpointer data,
GtkDestroyNotify destroy );
gpointer gtk_clist_get_row_data( GtkCList *clist,
gint row );
gint gtk_clist_find_row_from_data( GtkCList *clist,
gpointer data );
También hay funciones que nos permiten forzar la (de)selección de una fila. Son
void gtk_clist_select_row( GtkCList *clist,
gint row,
gint column );
void gtk_clist_unselect_row( GtkCList *clist,
gint row,
gint column );
Y también una función que tomará las coordenadas x e y (por ejemplo, recibidas del ratón), mirará en la lista y devolverá la fila y la columna que les corresponden.
gint gtk_clist_get_selection_info( GtkCList *clist,
gint x,
gint y,
gint *row,
gint *column );
Cuando detectemos algo interesante, como por ejemplo el movimiento del ratón, o una pulsación en cualquier lugar de la lista, podemos leer las coordenadas del ratón y encontrar en que elemento de la lista se encuentra. ¿Engorroso? Afortunadamente, hay una forma más sencilla de hacer las cosas...
Como con el resto de widgets, hay unas cuantas señales que podemos utilizar. El widget GtkCList está derivado del widget GtkContainer, y por tanto tiene las mismas señales que éste, pero además añade las siguientes:
select_row
- Esta señal enviará la siguiente información,
en este orden: GtkCList *clist, gint row, gint column, GtkEventButton
*event
unselect_row
- Cuando el usuario deselecciona una fila, se
activará esta señal. Envia la misma información que select_row
click_column
- Envia GtkCList *clist, gint columnPor tanto si queremos conectar una llamada a select_row
, la
llamada se deberá declarar como
void select_row_callback(GtkWidget *widget,
gint row,
gint column,
GdkEventButton *event,
gpointer data);
La llamada se conectará, como siempre, con
gtk_signal_connect(GTK_OBJECT( clist),
"select_row"
GTK_SIGNAL_FUNC(select_row_callback),
NULL);
/* principio del ejemplo clist clist.c */
#include <gtk/gtk.h>
#include <glib.h>
/* Aquí tenemos algunos prototipos de las funciones de llamada */
void button_add_clicked( GtkWidget *button, gpointer data);
void button_clear_clicked( GtkWidget *button, gpointer data);
void button_hide_show_clicked( GtkWidget *button, gpointer data);
void selection_made( GtkWidget *clist, gint row, gint column,
GdkEventButton *event, gpointer data);
gint main (int argc, gchar *argv[])
{
GtkWidget *window;
GtkWidget *vbox, *hbox;
GtkWidget *clist;
GtkWidget *button_add, *button_clear, *button_hide_show;
gchar *titles[2] = {"Ingredients","Amount"};
gtk_init(&argc, &argv);
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_usize(GTK_WIDGET(window), 300, 150);
gtk_window_set_title(GTK_WINDOW(window), "GtkCList Example");
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(gtk_main_quit),
NULL);
vbox=gtk_vbox_new(FALSE, 5);
gtk_container_border_width(GTK_CONTAINER(vbox), 5);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show(vbox);
/* Crear el GtkCList. Para este ejemplo utilizaremos 2 columnas */
clist = gtk_clist_new_with_titles( 2, titles);
/* Cuando se hace una selección, queremos saber algo acerca de
* ella. La función de llamada utilizada es selection_made, y su
* código lo podemos encontrar más abajo */
gtk_signal_connect(GTK_OBJECT(clist), "select_row",
GTK_SIGNAL_FUNC(selection_made),
NULL);
/* No es necesario ponerle sombra al borde, pero es bonito :) */
gtk_clist_set_border(GTK_CLIST(clist), GTK_SHADOW_OUT);
/* Lo que sí que es importante, es poner el ancho de las columnas
* ya no tendrán el valor correcto en caso contrario. Recuerde que
* las columnas se numeran desde el 0 en adelante (hasta el 1 en
* este caso).
*/
gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
/* Scollbars _only when needed_ */
gtk_clist_set_policy(GTK_CLIST(clist), GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
/* Añade el widget GtkCList a la caja vertical y lo muestra. */
gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
gtk_widget_show(clist);
/* Crea los botones y los añade a la ventana. Ver la parte del
* tutorial sobre botones para ver más ejemplos y comentarios
* acerca de todo esto.
*/
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
gtk_widget_show(hbox);
button_add = gtk_button_new_with_label("Add List");
button_clear = gtk_button_new_with_label("Clear List");
button_hide_show = gtk_button_new_with_label("Hide/Show titles");
gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
/* Conectar nuestras funciones de llamada a los tres botones */
gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
GTK_SIGNAL_FUNC(button_add_clicked),
(gpointer) clist);
gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
GTK_SIGNAL_FUNC(button_clear_clicked),
(gpointer) clist);
gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
GTK_SIGNAL_FUNC(button_hide_show_clicked),
(gpointer) clist);
gtk_widget_show(button_add);
gtk_widget_show(button_clear);
gtk_widget_show(button_hide_show);
/* Ahora hemos terminado el interface y sólo nos queda mostrar la
* ventana y entrar en el bucle gtk_main.
*/
gtk_widget_show(window);
gtk_main();
return 0;
}
/* El usuario pulsó el botón "Add List". */
void button_add_clicked( GtkWidget *button, gpointer data)
{
int indx;
/* Algo tonto que añadir a la lista. 4 filas con 2 columnas cada
* una
*/
gchar *drink[4][2] = {{"Milk", "3 Oz"},
{"Water", "6 l"},
{"Carrots", "2"},
{"Snakes", "55"}};
/* Aquí hacemos la adición del texto. Se hace una vez por cada
* fila.
*/
for( indx=0; indx < 4; indx++)
gtk_clist_append( (GtkCList*) data, drink[indx]);
return;
}
/* El usuario pulsó el botón "Clear List" */
void button_clear_clicked( GtkWidget *button, gpointer data)
{
/* Borrar la lista utilizando gtk_clist_clear. Esto es mucho más
* rápido que llamar a gtk_clist_remove una vez por cada fila.
*/
gtk_clist_clear((GtkCList*) data);
return;
}
/* El usuario pulsó el botón "Hide/Show titles". */
void button_hide_show_clicked( GtkWidget *button, gpointer data)
{
/* Una bandera para recordar el estado. 0 = actualmente visible */
static short int flag = 0;
if (flag == 0)
{
/* Oculta los títulos y pone la bandera a 1 */
gtk_clist_column_titles_hide((GtkCList*) data);
flag++;
}
else
{
/* Muestra los títulos y pone la bandera a 0 */
gtk_clist_column_titles_show((GtkCList*) data);
flag--;
}
return;
}
/* Se llegamos aquí, entonces el usuario ha seleccionado una fila de
* la lista.
*/
void selection_made( GtkWidget *clist, gint row, gint column,
GdkEventButton *event, gpointer data)
{
gchar *text;
/* Obtiene el texto que se ha almacenado en la fila y columna
* sobre las que se ha pulsado. Lo recibiremos como un puntero en
* el argumento text.
*/
gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
/* Imprime alguna información sobre la fila seleccionada */
g_print("You selected row %d. More specifically you clicked in column %d, and the text in this cell is %s\n\n", row, column, text);
return;
}
/* final del ejemplo */