Contenedores

De Wiki GNOME Chile
Saltar a: navegación, buscar

GTK utiliza los contenedores para colocar los widgets de una forma determinada. Cuando se desarrolla una aplicación, normalmente se necesita colocar más de un widget dentro de una ventana. En el ejemplo anterior de helloworld se usa sólo un contenedor (gtk_container_add (GTK_CONTAINER (window), button);), para colocar el botón dentro de la ventana donde será mostrado. Pero, ¿qué pasa si se quiere usar más de un widget dentro de una ventana?, ¿cómo se puede controlar la posición de los widgets?

En otros sistemas gráficos (como por ejemplo MS Windows), la colocación de los widgets dentro de las ventanas se hace por medio de coordenadas relativas. Esto hace necesario un nivel de detalle a la hora de diseñar las ventanas de las aplicaciones que lo hacen indeseable. En GTK+, al igual que en todos los toolkits gráficos provinientes del mundo UNIX (Motif, QT, GTK, AWT de Java), está basado en el modelo de contenedores, donde no es necesario el uso de coordenadas. Simplemente se crean distintos tipos de contenedores (cada uno de los cuales coloca los widgets dentro de si mismo de una forma determinada) para cada caso concreto, y simplemente se colocan widgets dentro de dichos contenedores. La forma en que se metan los widgets dentro del contenedor define cómo se comportarán dichos widgets cuando la ventana contenedora cambie de tamaño.


Cajas

Existen varios tipos de contenedores que se irán explicando a lo largo de este capítulo, pero los widgets GtkHBox y GtkVBox son los más usados. GtkHBox y GtkVBox son cajas invisibles que sirven para empaquetar los widgets que se vayan a colocar dentro de una ventana u otro contenedor. Cuando se empaquetan widgets en una caja horizontal (GtkHBox) se insertan horizontalmente de izquierda a derecha o de derecha a izquierda, dependiendo de la función que se utilice después. En una caja vertical (GtkVBox) se insertan de arriba a abajo o vice versa. También se puede usar una combinación de cajas dentro o al lado de otras cajas para crear el efecto deseado.

Para crear una caja horizontal se hace una llamada a la función gtk_hbox_new(), y para cajas verticales, gtk_vbox_new(). Las funciones gtk_box_pack_start() y gtk_box_pack_end se usan para colocar los widgets dentro de las cajas creadas. La función gtk_box_pack_start coloca los widgets de arriba a abajo en una caja vertical y de izquierda a derecha en una horizontal, mientras que gtk_box_pack_end() hace lo contrario, que es colocar los widgets de abajo a arriba en una caja vertical y de derecha a izquierda en una horizontal. Usando estas funciones será posible alinear los widgets a la derecha o izquierda de la caja según se desee.

Usando estas funciones, GTK sabe en qué posición colocar los widgets y así poder cambiar el tamaño de los mismos automáticamente, cuando se cambia el tamaño del contenedor. Además cuentan con varias opciones para poder cambiar el estilo de colocación de los widgets. En la siguiente figura se muestran los 5 estilos diferentes de colocación.

Figura 1. Cinco estilos diferentes de colocación

Error al crear miniatura: No se ha podido guardar la miniatura


Cada línea contiene una caja horizontal (hbox) con varios botones. La llamada a la función gtk_box_pack es para colocar los botones en la caja horizontal.

Las dos funciones para añadir widgets a las cajas tienen la siguiente forma:


void gtk_box_pack_start (box, 
 	child, 	 
 	expand, 	 
 	fill, 	 
 	padding);
 
GtkBox    *box;
GtkWidget *child;
gboolean  expand;
gboolean  fill;
guint  	  padding;


void gtk_box_pack_end (box, 
 	child, 	 
 	expand, 	 
 	fill, 	 
 	padding);
 
GtkBox    *box;
GtkWidget *child;
gboolean  expand;
gboolean  fill;
guint  	  padding;


El primer argumento se refiere a la caja en la que se va a colocar el objeto, el segundo argumento es el objeto. Los objetos en este ejemplo son los botones, así que se colocarán los botones dentro de las cajas, pero puede ser cualquier otro widget.

El argumento expand controla que los botones se extiendan hasta rellenar todo el espacio dentro de la caja (TRUE), o que la caja se ajuste al tamaño de los botones (FALSE). Con expand con una valor de FALSE se pueden alinear los botones a la izquierda o a la derecha.

El argumento fill de las funciones gtk_box_pack controla si el espacio extra se coloca en los botones (TRUE), o como espacio extra entre cada botón (FALSE). Esto sólo tiene validez si el argumento expand está a TRUE.

El argumento padding controla el espacio añadido a cada lado del botón. En la siguiente figura se puede ver mejor el resultado.

Figura 2. Diferencias entre padding y spacing

Error al crear miniatura: No se ha podido guardar la miniatura


Para crear una caja, las funciones tienen el siguiente formato:


GtkWidget * gtk_hbox_new (homogenous, 	 
 	spacing);

gboolean  homogenous;
gint  	  spacing;


GtkWidget * gtk_vbox_new (homogenous, 	 
 	spacing);

gboolean homogenous;
gint  	 spacing;


El argumento homogeneous controla si cada botón dentro de la caja tiene el mismo tamaño (la misma anchura en una hbox y la misma altura en una vbox). Si este argumento está a TRUE, las funciones de gtk_box_pack() funcionan como si el argumento expand estuviera siempre a TRUE.

El argumento spacing controla el espacio añadido entre los botones. La figura anterior muestra el resultado y la diferencia con el argumento padding de las funciones gtk_box_pack().


Ejemplo de uso de cajas

El código que se muestra a continuación es el usado para crear las figuras mostradas anteriormente.


#include <stdio.h>
#include <stdlib.h>
#include "gtk/gtk.h"

gint delete_event( GtkWidget *widget,
                   GdkEvent  *event,
                   gpointer   data )
{
        gtk_main_quit ();
        return FALSE;
}

/* Crea una hbox con botones con etiquetas.
 * Se muestran todos los widgets (gtk_widget_show()) a excepción de la caja. */
GtkWidget *make_box( gboolean homogeneous,
                     gint     spacing,
                     gboolean expand,
                     gboolean fill,
                     guint    padding )
{
        GtkWidget *box;
        GtkWidget *button;
        char padstr[80];

        /* Crea una hbox con los parámetros establecidos
         * para homogeneous y spacing */
        box = gtk_hbox_new (homogeneous, spacing);

        /* Crea una serie de botones con etiqueta */
        button = gtk_button_new_with_label ("gtk_box_pack");
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);

        button = gtk_button_new_with_label ("(box,");
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);

        button = gtk_button_new_with_label ("button,");
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);

        /* Crea un botón con etiqueta dependiendo del valor del parámetro
         * expand. */
        if (expand == TRUE)
                button = gtk_button_new_with_label ("TRUE,");
        else
                button = gtk_button_new_with_label ("FALSE,");

        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);

        /* Lo mismo con el botón de "expand"
         * pero esta vez de la forma abreviada. */
        button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);

        sprintf (padstr, "%d);", padding);

        button = gtk_button_new_with_label (padstr);
        gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
        gtk_widget_show (button);

        return box;
}

int main( int   argc,
          char *argv[])
{
        GtkWidget *window;
        GtkWidget *button;
        GtkWidget *box1;
        GtkWidget *box2;
        GtkWidget *separator;
        GtkWidget *label;
        GtkWidget *quitbox;
        int which;


        gtk_init (&argc, &argv);

        if (argc != 2) {
                fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
                /* Esto finaliza GTK y sale con un estatus de 1. */
                exit (1);
        }

        which = atoi (argv[1]);

        /* Crea una ventana */
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

        /* Simpre se debe conectar la señal delete_event a la ventana
         * principal, para así poder cerrarla.  */
        g_signal_connect (G_OBJECT (window), "delete_event",
                          G_CALLBACK (delete_event), NULL);
        gtk_container_set_border_width (GTK_CONTAINER (window), 10);

        /* Crea una caja vertical (vbox) para colocar las cajas horizontales dentro.
         * Esto permite colocar las cajas horizontales llenas de botones una
         * encima de la otra dentro de la caja vertical (vbox). */
        box1 = gtk_vbox_new (FALSE, 0);

        /* Muestra una de las Figuras de arriba. */
        switch (which) {
        case 1:
                /* crea una etiqueta. */
                label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");

                /* Alínea la etiqueta a la izquierda.  Se hablará más adelante de esta
                 * función. */
                gtk_misc_set_alignment (GTK_MISC (label), 0, 0);

                /* Coloca la etiqueta dentro de la caja vertical (vbox box1).  Los
                 * widgets que se añaden a una vbox se colocan, por orden, uno
                 * encima del otro. */
                gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);

                /* Muestra la etiqueta */
                gtk_widget_show (label);

                /* Llamada a la función make box, para crear un hbox con
                 * una serie de botones - homogeneous = FALSE, spacing = 0,
                 * expand = FALSE, fill = FALSE, padding = 0 */
                box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                /* Llamada a la función make box, para crear otra hbox con
                 * una serie de botones - homogeneous = FALSE, spacing = 0,
                 * expand = TRUE, fill = FALSE, padding = 0 */
                box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                /* Los argumentos son: homogeneous, spacing, expand, fill, padding */
                box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                /* Crea un separador, se verán más adelante,
                 * aunque son bastante sencillos. */
                separator = gtk_hseparator_new ();

                /* Coloca el separador en una vbox. Todos estos
                 * widgets han sido colocados en una vbox, así que estarán
                 * ordenados verticalmente. */
                gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
                gtk_widget_show (separator);

                /* Crea otra etiqueta y la muestra. */
                label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
                gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
                gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
                gtk_widget_show (label);

                /* Los argumentos son: homogeneous, spacing, expand, fill, padding */
                box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                /* Los argumentos son: homogeneous, spacing, expand, fill, padding */
                box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                /* Otro separador. */
                separator = gtk_hseparator_new ();
                /* Los tres últimos argumentos de gtk_box_pack_start son:
                 * expand, fill, padding. */
                gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
                gtk_widget_show (separator);

                break;

        case 2:

                /* Crea una etiqueta, box1 es una
                 * vbox que ya ha sido creada    */
                label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
                gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
                gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
                gtk_widget_show (label);

                /* Los argumentos son: homogeneous, spacing, expand, fill, padding */
                box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                /* Los argumentos son: homogeneous, spacing, expand, fill, padding */
                box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                separator = gtk_hseparator_new ();
                /* Los tres últimos argumentos de gtk_box_pack_start son:
                 * expand, fill, padding. */
                gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
                gtk_widget_show (separator);

                label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
                gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
                gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
                gtk_widget_show (label);

                /* Los argumentos son: homogeneous, spacing, expand, fill, padding */
                box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                /* Los argumentos son: homogeneous, spacing, expand, fill, padding */
                box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                separator = gtk_hseparator_new ();
                /* Los tres últimos argumentos de gtk_box_pack_start son: expand, fill, padding. */
                gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
                gtk_widget_show (separator);
                break;

        case 3:

                /* Esto demuestra la capacidad de gtk_box_pack_end() para
                 * alinear a la derecha los widgets. Primero, se crea una caja. */
                box2 = make_box (FALSE, 0, FALSE, FALSE, 0);

                /* Crea una etiqueta colocada al final. */
                label = gtk_label_new ("end");
                /* Coloca la etiqueta usando gtk_box_pack_end(), así que se situa a la
                 * derecha de la hbox creada con la llamada a make_box(). */
                gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
                /* Show the label. */
                gtk_widget_show (label);

                /* Coloca box2 dentro de box1 (vbox) */
                gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
                gtk_widget_show (box2);

                /* Crea un separador. */
                separator = gtk_hseparator_new ();
                /* Establece las medidas del separador, una anchura de 400 pixels por 5 pixels
                 * de altura. La hbox que se creó anteriormente también tendrá 400 pixels de
                 * anchura,y la etiqueta "end" se separa de las otras etiquetas en la
                 * hbox. */
                gtk_widget_set_size_request (separator, 400, 5);
                /* coloca el separador en la vbox (box1) */
                gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
                gtk_widget_show (separator);
        }

        /* Crea otra hbox.. (se pueden crear tantas cajas como se necesiten) */
        quitbox = gtk_hbox_new (FALSE, 0);

        /* Crea el botón para salir del programa. */
        button = gtk_button_new_with_label ("Quit");

        /* Establece la señal para terminar el programa cundo se pulsa el botón ("quit") */
        g_signal_connect_swapped (G_OBJECT (button), "clicked",
                                  G_CALLBACK (gtk_main_quit),
                                  G_OBJECT (window));
        /* Coloca el botón en la hbox (quitbox).
         * Los 3 últimos argumentos de gtk_box_pack_start son:
         * expand, fill, padding. */
        gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
        /* Coloca la hbox (quitbox) en la vbox (box1) */
        gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);

        /* Coloca la vbox (box1), la cual contiene ahora todos los widgets, en la
         * ventana principal. */
        gtk_container_add (GTK_CONTAINER (window), box1);

        /* Se muestra todo lo restante */
        gtk_widget_show (button);
        gtk_widget_show (quitbox);

        gtk_widget_show (box1);
        /* Se muestra la ventana en último lugar, así todo se muestra a la vez. */
        gtk_widget_show (window);

        /* La función principal. */
        gtk_main ();

        /* El control vuelve aquí cuando se llama a gtk_main_quit(), pero no cuando
         * se usa exit(). */

        return 0;
}


Cajas de botones

Uno de los usos más comunes que se le dan a las cajas citadas en el apartado anterior es para agrupar botones. Al ser esta una tarea muy común, GTK incluye las cajas de botones (Gtk?ButtonBox).

Las cajas de botones son una utilidad que permite crear grupos de botones de una forma rápida y sencilla. Estas cajas de botones pueden ser horizontales o verticales.

Las siguientes funciones son para crear una caja de botones horizontal y vertical.

Herramientas personales
Espacios de nombres

Variantes
Acciones
Navegación
Herramientas