Ejemplo básico

Antes de seguir adelante, lo mejor es ver un ejemplo completo de un programa (básico) en GTK, de forma que puedan apreciarse claramente los pasos básicos.

   1 #include <gtk/gtk.h>
   2 
   3 /* This is a callback function. The data arguments are ignored
   4  * in this example. More on callbacks below. */
   5 void hello( GtkWidget *widget, gpointer   data )
   6 {
   7         g_print ("Hello World\n");
   8 }
   9 
  10 gint delete_event( GtkWidget *widget,
  11                    GdkEvent  *event,
  12                    gpointer   data )
  13 {
  14         /* If you return FALSE in the "delete_event" signal handler,
  15          * GTK will emit the "destroy" signal. Returning TRUE means
  16          * you don't want the window to be destroyed.
  17          * This is useful for popping up 'are you sure you want to quit?'
  18          * type dialogs. */
  19 
  20         g_print ("delete event occurred\n");
  21 
  22         /* Change TRUE to FALSE and the main window will be destroyed with
  23          * a "delete_event". */
  24 
  25         return TRUE;
  26 }
  27 
  28 /* Another callback */
  29 void destroy( GtkWidget *widget, gpointer   data )
  30 {
  31         gtk_main_quit ();
  32 }
  33 
  34 int main( int   argc, char *argv[] )
  35 {
  36         /* GtkWidget is the storage type for widgets */
  37         GtkWidget *window;
  38         GtkWidget *button;
  39 
  40         /* This is called in all GTK applications. Arguments are parsed
  41          * from the command line and are returned to the application. */
  42         gtk_init (&argc, &argv);
  43 
  44         /* create a new window */
  45         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  46 
  47         /* When the window is given the "delete_event" signal (this is given
  48          * by the window manager, usually by the "close" option, or on the
  49          * titlebar), we ask it to call the delete_event () function
  50          * as defined above. The data passed to the callback
  51          * function is NULL and is ignored in the callback function. */
  52         g_signal_connect (G_OBJECT (window), "delete_event",
  53                           G_CALLBACK (delete_event), NULL);
  54 
  55         /* Here we connect the "destroy" event to a signal handler.
  56          * This event occurs when we call gtk_widget_destroy() on the window,
  57          * or if we return FALSE in the "delete_event" callback. */
  58         g_signal_connect (G_OBJECT (window), "destroy",
  59                           G_CALLBACK (destroy), NULL);
  60 
  61         /* Sets the border width of the window. */
  62         gtk_container_set_border_width (GTK_CONTAINER (window), 10);
  63 
  64         /* Creates a new button with the label "Hello World". */
  65         button = gtk_button_new_with_label ("Hello World");
  66 
  67         /* When the button receives the "clicked" signal, it will call the
  68          * function hello() passing it NULL as its argument.  The hello()
  69          * function is defined above. */
  70         g_signal_connect (G_OBJECT (button), "clicked",
  71                           G_CALLBACK (hello), NULL);
  72 
  73         /* This will cause the window to be destroyed by calling
  74          * gtk_widget_destroy(window) when "clicked".  Again, the destroy
  75          * signal could come from here, or the window manager. */
  76         g_signal_connect_swapped (G_OBJECT (button), "clicked",
  77                                   G_CALLBACK (gtk_widget_destroy),
  78                                   G_OBJECT (window));
  79 
  80         /* This packs the button into the window (a gtk container). */
  81         gtk_container_add (GTK_CONTAINER (window), button);
  82 
  83         /* The final step is to display this newly created widget. */
  84         gtk_widget_show (button);
  85 
  86         /* and the window */
  87         gtk_widget_show (window);
  88 
  89         /* All GTK applications must have a gtk_main(). Control ends here
  90          * and waits for an event to occur (like a key press or
  91          * mouse event). */
  92         gtk_main ();
  93 
  94         return 0;
  95 }

El ejemplo paso a paso

Ahora que ya conocemos la teoría básica, explicaremos paso a paso el ejemplo mostrado en el punto anterior.

Aquí tenemos la función que será llamada cuando se haga "click" sobre el botón. En este ejemplo, el cuerpo de la función ignorará tanto el widget como los datos que recoge como parámetros, pero no sería difícil saber como utilizarlos. El siguiente ejemplo usará el argumento data para controlar qué botón se pulsó.

   1      static void hello( GtkWidget *widget,
   2                     gpointer   data )
   3      {
   4         g_print ("Hello World\n");
   5      }

La siguiente función de conexión es un poco especial. El gestor de ventanas emite el evento "delete_event" a la aplicación y en ese momento se llamará a la función que hemos definido con el nombre "delete_event" . Ahora podemos reaccionar de varias formas dentro de la función: podemos ignorar el evento, procesarlo o símplemente cerrar la aplicación.

El valor que devuelva esta función de conexión le permite a GTK conocer qué acción debe llevar a cabo. Si devolvemos TRUE, estamos indicando que no queremos que se emita la señal "destroy", lo que permitirá que nuestra aplicación siga ejecutándose. Si devolvemos FALSE, indicaremos que se emita la señal "destroy", evento que será recogido por nuestra función de conexión "destroy".

   1 static gboolean delete_event( GtkWidget *widget,
   2                               GdkEvent  *event,
   3                               gpointer   data )
   4 {
   5     g_print ("delete event occurred\n");
   6 
   7     return TRUE;
   8 }

Aquí tenemos otra función callback que provoca que el programa termine mediante la llamada a la función gtk_main_quit(). Esta función indica a GTK que debe salir de gtk_main cuando se le devuelva el control desde la función.

   1 static void destroy( GtkWidget *widget,
   2                      gpointer   data )
   3 {
   4     gtk_main_quit ();
   5 }

Asumimos que el lector conoce la función main()... sí, como sucede con otras aplicaciones, todas las aplicaciones GTK también hacen uso de main.

   1 int main( int   argc,
   2           char *argv[] )
   3 {

El siguiente trozo de programa declara punteros a estructuras de tipo GtkWidget. Serán usadas más abajo para crear una ventana y un botón

   1     GtkWidget *window;
   2     GtkWidget *button;

Aquí tenemos de nuevo a gtk_init(). Como antes, esto inicializa el toolkit, y parsea los argumentos que encuentre en la línea de comandos. Cualquier argumento que reconozca en la línea de comandos será eliminado de la lista y de argc y argv, permitiendo a tu aplicación parsear el resto de argumentos.

   1     gtk_init (&argc, &argv);

Crear una nueva ventana es un proceso bastante directo. Se asigna memoria para la estructura GtkWidget *window de tal forma que apunte a una estructura válida. Se inicializa una nueva ventana, pero no se muestra hasta que se llame a

   1 gtk_widget_show(window)

cerca del final del program.

   1     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

Aquí tenemos dos ejemplos sobre cómo conectar un manejador de señal a un objeto, en este caso, una ventana. Aquí, las señales "delete_event" y "destroy" son capturadas y tratadas. La primera es emitida cuando usamos el gestor de ventanas para cerrar la ventan, o cuando usamos la llamada gtk_widget_destroy() pasando el widget de la ventana como el objeto a destruir. La segunda es emitida cuando, en el manejador "delete_event", devolvemos el valor FALSE. G_OBJECT y G_CALLBACK son macros que permiten realizar la conversión y comprobación de tipos de forma sencilla, además de facilitar la legibilidad del código.

   1     g_signal_connect (G_OBJECT (window), "delete_event",
   2                       G_CALLBACK (delete_event), NULL);
   3     g_signal_connect (G_OBJECT (window), "destroy",
   4                       G_CALLBACK (destroy), NULL);

La siguiente función se usa para asignar un atributo a un objeto contenedor. Lo que hacemos es ajustar la ventana para que tenga un área blanca alrededor de su perímetro de 10 pixels de ancho, donde no podrá ir ningún otro widget. Existen otras funciones similares que estudiaremos más adelante.

De nuevo, GTK_CONTAINER es una macro que permite la conversión de tipos.

   1     gtk_container_set_border_width (GTK_CONTAINER (window), 10);

La siguiente llamada crea un nuevo botón. Asigna espacio para una nueva estructura GtkWidget en memoria, la inicializa, y apunta el puntero button hacia él. Tendrá la etiqueta "Hello World" cuando sea mostrado.

   1     button = gtk_button_new_with_label ("Hello World");

Aquí haremos que el botón tenga alguna utilidad. Le asignaremos un manejador de señal de tal forma que cuando emita el evento "clicked", se llame a nuestra función hello(). El parámetro data se ignora, por lo que pasamos simplemente un NULL en esa posición a la función de conexión hello(). Obviamente, la señal "clicked" se emitirá cuando se haga click sobre el botón con el ratón.

   1     g_signal_connect (G_OBJECT (button), "clicked",
   2                       G_CALLBACK (hello), NULL);

También usaremos este botón para salir de nuestro programa. Esto ilustrará lo indicado antes sobre la señal "destroy": puede venir tanto del gestor de ventanas como de nuestro propio programa. Cuando se pulse el botón, al igual que antes, se llama primero a la función hello() y posteriormente a la función gtk_widget_destroy() en el mismo orden en el que se hayan definido las funciones callback. Puedes tener tantas funciones callback como desees, y todas será ejecutadas en el orden en el que fueron conectadas. Dado que la funcion gtk_widget_destroy() acepta únicamente un GtkWidget *widget como argumento, usaremos la función g_signal_connect_swapped() en lugar de g_signal_connect().

   1     g_signal_connect_swapped (G_OBJECT (button), "clicked",
   2                               G_CALLBACK (gtk_widget_destroy),
   3                               G_OBJECT (window));

La siguiente es una llamada a una función de empaquetamiento, que serán explicadas en el siguiente capítulo. Pero es bastante sencillo de entender. Símplemente indica a GTK que el botón debe situarse en la ventana en la que será mostrado. Obsérvese que un contenedor GTK únicamente puede contener un widget. Existen otros widgets, descritos más adelante, diseñados para albergar múltiples widgets en distintas posiciones.

   1     gtk_container_add (GTK_CONTAINER (window), button);

Ya tenemos todo dispuesto de la forma que queríamos. Con todos los manejadores de señal inicializados y el botón insertado en la ventana correctamente, sólo nos queda indicar a GTK que muestre los widgets en pantalla. El widget de la ventana se muestra el último, de tal forma que toda la ventana con todo su contenido salga al final "a escena", para evitar mostrar primero la ventana y después ver que el botón se coloca encima. Aunque con un ejemplo tan sencillo, nunca se notaría ningún efecto "raro".

   1     gtk_widget_show (button);
   2 
   3     gtk_widget_show (window);

Por supuesto, queda finalmente llamar a gtk_main() que se ejecurará en bucle, esperando eventos que vengan del servidor X y llamando a los widgets para que emitan señales cuando lleguen estos eventos.

   1     gtk_main ();

Para terminar el programa, se debe devolver 0 si todo ha ido correctamente, cuando se devuelva el control tras una llamada gtk_quit().

   1     return 0;

Ahora, cuando hagamos click con el botón del ratón en un botón GTK, el widget emitirá una señal "clicked". Para poder usar esta información, nuestro programa ha inicializado un manejador de señal para tratar este evento, que ejecutará la función que hayamos especificado. En nuestro ejemplo, cuando el botón creado sea pulsado, se llamará a a la función hello() con NULL como argumento; posteriormente, se ejecutará el siguiente manejador para esta señal. Esto llamará a gtk_widget_destroy(), pasándole el widget de la ventana como argumento, destruyéndolo. Esto provoca que la ventana emita la señal "destroy", que será interceptada, y llamará a nuestra función callback destroy(), que símplemente saldrá de GTK.

Otro posible camino de ejecución podría ser el usar el gestor de ventanas para cerrar la ventana, lo que provocará que se emita la señal "delete_event". Ésta será interceptada por nuestro manejador "delete_event". Si aquí devolvemos TRUE, la ventana seguirá como si nada hubiera ocurrido. Devolver FALSE provocará que GTK emita la señal "destroy" que por supuesto, llamará al callback "destroy", terminando la aplicación GTK.

Cómo compilar el ejemplo

Para compilar los ejemplos del capítulo sobre GTK 2.0, podemos usar la siguiente orden:

     gcc `pkg-config --cflags --libs gtk+-2.0` hello-world.c -o hello-world


Documentacion/Desarrollo/Gtk/EjemploBasico (última edición 2008-12-04 08:48:55 efectuada por localhost)