Página siguiente Página anterior Índice general

12. El widget lista

ATENCIÓN: El widget GtkList ha sido reemplazado por el widget GtkCList.

El widget GtkList está diseñado para actuar como un contenedor vertical de widgets que deben ser del tipo GtkListItem.

Un widget GtkList tiene su propia ventana para recibir eventos y su propio color de fondo, que normalmente es blanco. Como es un objeto derivado directamente de GtkContainer puede tratarse utilizando la macro GTK_CONTAINER(List), ver el widget GtkContainer para obtener más información.

Debería familiarizarse con la utilización de un GList y con sus funciones relacionadas g_list_*() para ser capaz de explotar el widget GtkList hasta su límite.

Sólo hay un campo dentro de la definición de la estructura del widget GtkList que nos es de interés, y es:

struct _GtkList
{
  ...
  GList *selection;
  guint selection_mode;
  ...
}; 

El campo selection de un GtkList apunta a una lista enlazada de todos los elementos que están actualmente seleccionados, o NULL si la selección está vacia. Por lo tanto para saber quien es la actual selección debemos leer el campo GTK_LIST()->selection, pero no modificarlo ya que los campos de los que está constituido GtkList están controlados por las funciones gtk_list_*().

El selection_mode de la GtkList determina las posibilidades de selección de una GtkList y por tanto los contenidos del campo GTK_LIST()->selection. El selection_mode puede tener uno de los valores siguientes:

El valor por defecto es GTK_SELECTION_MULTIPLE.

12.1 Señales

void selection_changed( GtkList *list );

Se invocará esta señal cuando cambie el campo selection de un GtkList. Es decir, cuando un hijo de una GtkList se selecciona o deselecciona.

void select_child( GtkList   *list,
                   GtkWidget *child);

Se invoca esta señal cuando un hijo de la GtkList está siendo seleccionado. Esto ocurre principalmente en llamadas a gtk_list_select_item(), a gtk_list_select_child(), cuando se pulsa algún botón y a veces se lanza indirectamente cuando se añade o se elimina un hijo del GtkList.

void unselect_child( GtkList   *list,
                     GtkWidget *child );

Se invoca esta señal cuando un hijo del GtkList está siendo deseleccionado. Esto ocurre principalmente cuando ocurre una llamada a gtk_list_unselect_item(), gtk_list_unselect_item(), pulsaciones de botón y a veces se lanza indirectamente cuando se añade o se elimina algún hijo de la GtkList.

12.2 Funciones

guint gtk_list_get_type( void );

Devuelve el identificador de tipo `GtkList'.

GtkWidget *gtk_list_new( void );

Crea un nuevo objeto GtkList. Se devuelve el nuevo widget como un puntero a un objeto GtkWidget. Se devuelve NULL en caso de producirse algún fallo.

void gtk_list_insert_items( GtkList *list,
                            GList   *items,
                            gint     position );

Introduce elementos en la lista, comenzando en la posición position. items es una lista doblemente enlazada donde cada puntero de datos de cada nodo se supone que apunta a una nueva GtkListItem (recien creada). Los nodos GList de items son controlados por la lista.

void gtk_list_append_items( GtkList *list,
                            GList   *items);

Introduce elementos tal y como lo hace gtk_list_insert_items(), pero los mete en el final de la lista. Los nodos GList de items son controlados por la lista.

void gtk_list_prepend_items( GtkList *list,
                             GList   *items);

Introduce elementos tal y como lo hace gtk_list_insert_items(), pero los mete al principio de la lista. Los nodos GList de items son controlados por la lista.

void gtk_list_remove_items( GtkList *list,
                            GList   *items);

Elimina elementos de la lista. items es una lista doblemente enlazada donde cada puntero de datos de cada nodo se supone que apunta a un hijo directo de la lista. El ejecutar o no g_list_free(items) cuando la función termine de ejecutarse es responsabilidad del que llama a la misma. Está bajo su responsabilidad la destrucción de los elementos de la lista.

void gtk_list_clear_items( GtkList *list,
                           gint start,
                           gint end );

Elimina y destruye los elementos de la lista. Esta operación afectará a todos los widgets que se encuentren en la lista y en el rango especificado por start y end.

void gtk_list_select_item( GtkList *list,
                           gint     item );

Invoca la señal select_child para el elemento especificado mediante su posición actual en la lista.

void gtk_list_unselect_item( GtkList *list,
                             gint     item);

Invoca la señal unselect_child para un elemento especificado mediante su posición actual en la lista.

void gtk_list_select_child( GtkList *list,
                            GtkWidget *child);

Invoca la señal select_child para el hijo especificado.

void gtk_list_unselect_child( GtkList   *list,
                              GtkWidget *child);

Invoca la señal unselect_child para el hijo especificado.

gint gtk_list_child_position( GtkList *list,
                              GtkWidget *child);

Devuelve la posición de child en la lista. Se devuelve ``-1'' en caso de producirse algún error.

void gtk_list_set_selection_mode( GtkList         *list,
                                  GtkSelectionMode mode );

Pone el modo de selección, que puede ser GTK_SELECTION_SINGLE, GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE o GTK_SELECTION_EXTENDED.

GtkList *GTK_LIST( gpointer obj );

Convierte un puntero general en `GtkList *'. Para más información *Note Standard Macros::.

GtkListClass *GTK_LIST_CLASS( gpointer class);

Convierte un puntero general en `GtkListClass *'. Para más información *Note Standard Macros::.

gint GTK_IS_LIST( gpointer obj);

Determina si un puntero general se refiere a un objeto `GtkList'. Para más información, *Note Standard Macros::.

12.3 Ejemplo

A continuación tenemos un programa ejemplo que muestra los cambios de la selección de un GtkList, y le deja ``arrestar'' elementos de la lista en una prisión, seleccionándolos con el botón derecho del ratón.

/* principio del ejemplo list list.c */

/* incluye los ficheros de cabecera de gtk+
 * incluye stdio.h, que necesitamos para la función printf()
 */
#include        <gtk/gtk.h>
#include        <stdio.h>

/* ésta es nuestra cadena de identificación para almacenar datos en la
 * lista de elementos
 */
const   gchar   *list_item_data_key="list_item_data";


/* prototipos para los manejadores de señal que vamos a conectar con
 * el widget GtkList
 */
static  void    sigh_print_selection    (GtkWidget      *gtklist,
                                         gpointer       func_data);
static  void    sigh_button_event       (GtkWidget      *gtklist,
                                         GdkEventButton *event,
                                         GtkWidget      *frame);


/* función principal donde se establece el interface con el usuario */

gint main (int argc, gchar *argv[])
{                                  
    GtkWidget       *separator;
    GtkWidget       *window;
    GtkWidget       *vbox;
    GtkWidget       *scrolled_window;
    GtkWidget       *frame;
    GtkWidget       *gtklist;
    GtkWidget       *button;
    GtkWidget       *list_item;
    GList           *dlist;
    guint           i;
    gchar           buffer[64];
    
    
    /* inicializar gtk+ (y consecuentemente gdk) */

    gtk_init(&argc, &argv);
    
    
    /* crear una ventana donde meter todos los widgets y conectar
     * gtk_main_quit() con el evento "destroy" de la ventana para
     * poder controlar los eventos de cerrado de ventana del
     * administrador de ventanas
     */
    window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
    gtk_signal_connect(GTK_OBJECT(window),
                       "destroy",
                       GTK_SIGNAL_FUNC(gtk_main_quit),
                       NULL);
    
    
    /* dentro de la ventana necesitamos una caja para alinear los
     * widgets verticalmente */
    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);
    
    /* Ésta es la ventana con barras de desplazamiento donde meteremos
     * el widget GtkList */
    scrolled_window=gtk_scrolled_window_new(NULL, NULL);
    gtk_widget_set_usize(scrolled_window, 250, 150);
    gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
    gtk_widget_show(scrolled_window);
    
    /* crear el widget GtkList
     * conectar la función manipuladora de señal
     * sigh_print_selection() a la señal "selection_changed" del
     * GtkList para imprimir los elementos seleccionados cada vez que
     * cambie la selección */
    gtklist=gtk_list_new();
    gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
    gtk_widget_show(gtklist);
    gtk_signal_connect(GTK_OBJECT(gtklist),
                       "selection_changed",
                       GTK_SIGNAL_FUNC(sigh_print_selection),
                       NULL);
    
    /* creamos una "Prisión" donde meteremos una lista de elementos ;)
     */
    frame=gtk_frame_new("Prison");
    gtk_widget_set_usize(frame, 200, 50);
    gtk_container_border_width(GTK_CONTAINER(frame), 5);
    gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
    gtk_container_add(GTK_CONTAINER(vbox), frame);
    gtk_widget_show(frame);
    
    /* conectamos el manipulador de señal sigh_button_event() al
     * GtkList que manejará la lista de elementos "arrestados"
     */
    gtk_signal_connect(GTK_OBJECT(gtklist),
                       "button_release_event",
                       GTK_SIGNAL_FUNC(sigh_button_event),
                       frame);
    
    /* crear un separador
     */
    separator=gtk_hseparator_new();
    gtk_container_add(GTK_CONTAINER(vbox), separator);
    gtk_widget_show(separator);
    
    /* crear finalmente un botón y conectar su señal "clicked" con la
     * destrucción de la ventana
     */
    button=gtk_button_new_with_label("Close");
    gtk_container_add(GTK_CONTAINER(vbox), button);
    gtk_widget_show(button);
    gtk_signal_connect_object(GTK_OBJECT(button),
                              "clicked",
                              GTK_SIGNAL_FUNC(gtk_widget_destroy),
                              GTK_OBJECT(window));
    
    
    /* ahora creamos 5 elementos de lista, teniendo cada uno su propia
     * etiqueta y añadiéndolos a la GtkList mediante
     * gtk_container_add() también consultaremos la cadena de texto de
     * la etiqueta y la asociaremos con la list_item_data_key para
     * cada elemento de la lista
     */
    for (i=0; i<5; i++) {
        GtkWidget       *label;
        gchar           *string;
        
        sprintf(buffer, "ListItemContainer with Label #%d", i);
        label=gtk_label_new(buffer);
        list_item=gtk_list_item_new();
        gtk_container_add(GTK_CONTAINER(list_item), label);
        gtk_widget_show(label);
        gtk_container_add(GTK_CONTAINER(gtklist), list_item);
        gtk_widget_show(list_item);
        gtk_label_get(GTK_LABEL(label), &string);
        gtk_object_set_data(GTK_OBJECT(list_item),
                            list_item_data_key,
                            string);
    }
    /* aquí, estamos creando otras 5 etiquetas, esta vez utilizaremos
     * gtk_list_item_new_with_label() para la creación
     * no podemos consultar la cadena de texto de la etiqueta ya que
     * no tenemos el puntero de etiquetas y por tanto lo único que
     * haremos será asociar el list_item_data_key de cada elemento de
     * la lista con la misma cadena de texto. Para añadirlo a la lista
     * de elementos los pondremos en lista doblemente enlazada
     * (GList), y entonces los añadimos mediante una simple llamada a
     * gtk_list_append_items()
     * como utilizamos g_list_prepend() para poner los elementos en la
     * lista doblemente enlazada, su orden será descendente (en vez de
     * ascendente como cuando utilizamos g_list_append())
     */
    dlist=NULL;
    for (; i<10; i++) {
        sprintf(buffer, "List Item with Label %d", i);
        list_item=gtk_list_item_new_with_label(buffer);
        dlist=g_list_prepend(dlist, list_item);
        gtk_widget_show(list_item);
        gtk_object_set_data(GTK_OBJECT(list_item),
                            list_item_data_key,
                            "ListItem with integrated Label");
    }
    gtk_list_append_items(GTK_LIST(gtklist), dlist);
    
    /* finalmente queremos ver la ventana, ¿verdad? ;)
     */
    gtk_widget_show(window);
    
    /* y nos metemos en el bucle de eventos de gtk
     */
    gtk_main();
    
    /* llegaremos aquí después de que se llame a gtk_main_quit(), lo
     * que ocurre si se destruye la ventana
     */
    return 0;
}

/* éste es el manejador de señal que se conectó a los eventos de
 * pulsar/soltar de los botones de la GtkList
 */
void
sigh_button_event       (GtkWidget      *gtklist,
                         GdkEventButton *event,
                         GtkWidget      *frame)
{
    /* sólo hacemos algo si el tercer botón (el botón derecho) se
     * levanta
     */
    if (event->type==GDK_BUTTON_RELEASE &&
        event->button==3) {
        GList           *dlist, *free_list;
        GtkWidget       *new_prisoner;
        
        /* sacar la lista de elementos que están actualmente
         * seleccionados y que serán nuestro próximos prisioneros ;)
         */
        dlist=GTK_LIST(gtklist)->selection;
        if (dlist)
                new_prisoner=GTK_WIDGET(dlist->data);
        else
                new_prisoner=NULL;
        
        /* buscar por elementos de la lista ya encarcelados, los
         * volveremos a poner en la lista, recordar que hay que
         * eliminar la lista doblemente enlazada que devuelve
         * gtk_container_children()
         */
        dlist=gtk_container_children(GTK_CONTAINER(frame));
        free_list=dlist;
        while (dlist) {
            GtkWidget       *list_item;
            
            list_item=dlist->data;
            
            gtk_widget_reparent(list_item, gtklist);
            
            dlist=dlist->next;
        }
        g_list_free(free_list);
        
        /* si tenemos un nuevo prisionero, lo eliminamos de la GtkList
         * y lo ponemos en el marco "Prisión". Primero tenemos que
         * deseleccionarlo
         */
        if (new_prisoner) {
            GList   static_dlist;
            
            static_dlist.data=new_prisoner;
            static_dlist.next=NULL;
            static_dlist.prev=NULL;
            
            gtk_list_unselect_child(GTK_LIST(gtklist),
                                    new_prisoner);
            gtk_widget_reparent(new_prisoner, frame);
        }
    }
}

/* éste es el manipulador de señal que se llama si GtkList emite la
 * señal "selection_changed"
 */
void
sigh_print_selection    (GtkWidget      *gtklist,
                         gpointer       func_data)
{
    GList   *dlist;
    
    /* sacar la lista doblemente enlazada de los elementos
     * seleccionados en GtkList, ¡recuerde que hay que tratarla como
     * de solo lectura!
     */
    dlist=GTK_LIST(gtklist)->selection;
    
    /* si no hay elementos seleccionados no queda nada por hacer
     * excepto informar al usuario
     */
    if (!dlist) {
        g_print("Selection cleared\n");
        return;
    }
    /* Bien, conseguimos una selección y la imprimimos
     */
    g_print("The selection is a ");
    
    /* obtenemos la lista de elementos de la lista doblemente enlazada
     * y entonces consultamos los datos asociados con la
     * list_item_data_key que acabamos de imprimir
     */
    while (dlist) {
        GtkObject       *list_item;
        gchar           *item_data_string;
        
        list_item=GTK_OBJECT(dlist->data);
        item_data_string=gtk_object_get_data(list_item,
                                             list_item_data_key);
        g_print("%s ", item_data_string);
        
        dlist=dlist->next;
    }
    g_print("\n");
}
/* fin del ejemplo */

12.4 El widget GtkListItem

El widget GtkListItem está diseñado para comportarse como un contenedor que tiene un hijo, proporcionando funciones para la selección/deselección justo como las necesitan los hijos del widget GtkList.

Un GtkListItem tiene su propia ventana para recibir eventos y tiene su propio color de fondo, que normalmente es blanco.

Como está derivado directamente de un GtkItem, puede tratarse como tal utilizando la macro GTK_ITEM(ListItem), ver el widget GtkItem para más detalles. Normalmente un GtkListItem sólo tiene una etiqueta para identificar, por ejemplo, el nombre de un fichero dentro de una GtkList -- por lo tanto se proporciona la función gtk_list_item_new_with_label(). Se puede conseguir el mismo efecto creando un GtkLabel, poniendo su alineación a xalign=0 e yalign=0.5 y seguido de una adición al contenedor GtkListItem.

Nadie le obliga a meter un GtkLabel en un GtkListItem, puede meter un GtkVBox o un GtkArrow, etc...

12.5 Señales

Un GtkListItem no crea por sí misma nuevas señales, pero hereda las señales de un GtkItem. Para más información *Note GtkItem::.

12.6 Funciones

guint gtk_list_item_get_type( void );

Devuelve el identificador de tipo `GtkListItem'.

GtkWidget *gtk_list_item_new( void );

Crea un nuevo objeto GtkListItem. Se devuelve el nuevo widget como un puntero a un objeto GtkWidget. Se devuelve NULL en caso de producirse algún error.

GtkWidget *gtk_list_item_new_with_label( gchar *label );

Crea un nuevo objeto GtkListItem, con una sola GtkLabel como único hijo. Se devuelve el nuevo widget como un puntero a un objeto GtkWidget. Se devuelve NULL en caso de producirse algún error.

void gtk_list_item_select( GtkListItem *list_item );

Esta función es, básicamente, un recubrimiento de una llamada a gtk_item_select (GTK_ITEM (list_item)), y emitirá la señal select. Para más información *Note GtkItem::.

void gtk_list_item_deselect( GtkListItem *list_item );

Esta función es, básicamente, un recubrimiento de una llamada a gtk_item_deselect (GTK_ITEM (list_item)), y emitirá la señal deselect. Para más información *Note GtkItem::.

GtkListItem *GTK_LIST_ITEM( gpointer obj );

Convierte un puntero general a `GtkListItem *'. Para más información *Note Standard Macros::.

GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );

Convierte un puntero general a `GtkListItemClass *'. Para más información *Note Standard Macros::.

gint GTK_IS_LIST_ITEM( gpointer obj );

Determina si un puntero general se refiere a un puntero `GtkListItem'. Para más información *Note Standard Macros::.

12.7 Ejemplo

Para ver un ejemplo de todo esto, mire el que de GtkList, que también cubre la utilización un GtkListItem.


Página siguiente Página anterior Índice general