Capítulo 1. Listas y Arboles: El widget GtkTreeView

GtkTreeView es un widget que despliega listas y árboles de una o múltiples columnas. Reemplaza los antiguos widgets de GTK+-1.2 GtkCList y GtkCTree. A pesar de que GtkTreeView es levemente mas difícil de dominar que sus predecesores, es tanto mas potente y flexible, que la mayoría de los desarrolladores no querrán perderla una vez que la conozcan.

El proposito de este capítulo no es proveer una documentación exhaustiva de GtkTreeView - Para eso se encuentrá la documentación API, que debe ser leida paralelamente a este tutorial. La idea es dar una introducción a los aspectos más comúnmente usados de GtkTreeView, y mostrar como los múltiples componentes y conceptos de GtkTreeView trabajan juntos. Además, se ha hecho un intento por dar nociones sobre modelos de arboles personalizados y manejadores de celdas personalizados, que son mencionados a menudo, pero pocas veces son explicados.

Desarrolladores en busca de una introducción rápida y sencilla que les enseñe todo lo que necesiten saber en menos de cinco párrafos no la van a encontrar aquí. En la experiencia del autor, los desarrolladores que no entiendan como la vista de arbol y el modelo trabajan juntos tendrán problemas una vez que traten de modificar los ejemplos dados, mientras que los desarrolladores que han trabajado con otros toolkits que emplean el diseño Modelo/Vista/Controlador encontrarán que la referencia API provee toda la información que necesitan saber de un modo mas condensado, de todos modos. Aquellos que no estén de acuerdo pueden irse desde luego directamente al código del ejemplo funcional.

Nótese por favor que los códigos de ejemplo en las siguientes secciones no muestran necesariamente la mejor manera de usar GtkTreeView en una situación particular. Hay diferentes formas de obtener el mismo resultado, y los ejemplos simplemente muestran esos distintos caminos, para que los desarrolladores puedan decidir cual es mas conveniente para su tarea actual.

1.1. Hello World

Para los impacientes, he aquí un pequeño programa con un GtkTreeView (que puede ser también encontrado en la sección de ejemplos del archivo treeview-tutorial.tar.gz).


/* 
 * Compilar con:
 *  gcc -o helloworld helloworld.c `pkg-config --cflags --libs gtk+-2.0`
 *
 */

#include <gtk/gtk.h>

enum
{
  COL_NAME = 0,
  COL_AGE,
  NUM_COLS
} ;


static GtkTreeModel *
create_and_fill_model (void)
{
  GtkListStore  *store;
  GtkTreeIter    iter;
  
  store = gtk_list_store_new (NUM_COLS, G_TYPE_STRING, G_TYPE_UINT);

  /* Añade una fila y la llena con datos  */
  gtk_list_store_append (store, &iter);
  gtk_list_store_set (store, &iter,
                      COL_NAME, "Heinz El-Mann",
                      COL_AGE, 51,
                      -1);
  
  /* Añade otra fila y la llena con datos */
  gtk_list_store_append (store, &iter);
  gtk_list_store_set (store, &iter,
                      COL_NAME, "Jane Doe",
                      COL_AGE, 23,
                      -1);
  
  /* ... y una tercera */
  gtk_list_store_append (store, &iter);
  gtk_list_store_set (store, &iter,
                      COL_NAME, "Joe Bungop",
                      COL_AGE, 91,
                      -1);
  
  return GTK_TREE_MODEL (store);
}

static GtkWidget *
create_view_and_model (void)
{
  GtkTreeViewColumn   *col;
  GtkCellRenderer     *renderer;
  GtkTreeModel        *model;
  GtkWidget           *view;

  view = gtk_tree_view_new ();

  /* --- Columna #1 --- */

  renderer = gtk_cell_renderer_text_new ();
  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
                                               -1,      
                                               "Name",  
                                               renderer,
                                               "text", COL_NAME,
                                               NULL);

  /* --- Columna #2 --- */

  col = gtk_tree_view_column_new();

  renderer = gtk_cell_renderer_text_new ();
  gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
                                               -1,      
                                               "Age",  
                                               renderer,
                                               "text", COL_AGE,
                                               NULL);

  model = create_and_fill_model ();

  gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);

  g_object_unref (model); /* destruir el modelo automaticamente con la vista */

  return view;
}


int
main (int argc, char **argv)
{
  GtkWidget *window;
  GtkWidget *view;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  g_signal_connect (window, "delete_event", gtk_main_quit, NULL); /* sucio */

  view = create_view_and_model ();

  gtk_container_add (GTK_CONTAINER (window), view);

  gtk_widget_show_all (window);

  gtk_main ();

  return 0;
}