2.

Comenzando
Por supuesto lo primero que hay que hacer es descargar las fuentes de GTK e instalarlas. La última versión siempre se puede obtener de ftp.gtk.org (en el directorio /pub/gtk). En http://www.gtk.org/ hay más información sobre GTK. Para configurar GTK hay que usar GNU autoconf. Una vez descomprimido se pueden obtener las opciones usando ./configure --help. El código de GTK además contiene las fuentes completas de todos los ejemplos usados en este manual, así como los makefiles para compilarlos. Para comenzar nuestra introducción a GTK vamos a empezar con el programa más sencillo posible. Con él vamos a crear una ventana de 200x200 pixels que sólo se puede destruir desde el shell.
/* principio del ejemplo base base.c */ #include <gtk/gtk.h> int main (int argc, char *argv[]) { GtkWidget *ventana; gtk_init (&argc, &argv); ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_show (ventana); gtk_main (); return 0; } /* final del ejemplo */

Puede compilar el programa anterior con gcc tecleando:
gcc base.c -o base `gtk-config --cflags --libs`

El significado de la extraña opción de compilación se explica más adelante. Todo programa que use GTK debe llamar a gtk/gtk.h donde se declaran todas las variables, funciones, estructuras, etc. que serán usadas en el programa. La siguiente línea:
gtk_init (&argc, &argv);

Llama a la función gtk_init (gint *argc, gchar *** argv) responsable de `arrancar' la biblioteca y de establecer algunos parámetros (como son los colores y los visuales por defecto), llama a gdk_init (gint *argc, gchar *** argv) que inicializa la biblioteca para que pueda utilizarse, establece los controladores de las señales y comprueba los argumentos pasados a la aplicación desde la línea de comandos, buscando alguno de los siguientes: • • • • • • • • • --gtk-module --g-fatal-warnings --gtk-debug --gtk-no-debug --gdk-debug --gdk-no-debug --display --sync --no-xshm

• •

--name --class

En el caso de que encuentre alguno lo quita de la lista, dejando todo aquello que no reconozca para que el programa lo utilice o lo ignore. Así se consigue crear un conjunto de argumentos que son comunes a todas las aplicaciones basadas en GTK. Las dos líneas de código siguientes crean y muestran una ventana.
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_show (ventana);

El argumento GTK_WINDOW_TOPLEVEL especifica que queremos que el gestor de ventanas decore y sitúe la ventana. En lugar de crear una ventana de tamaño 0 x 0 toda ventana sin hijos por defecto es de 200 x 200, con lo que se consigue que pueda ser manipulada. La función gtk_widget_show() le comunica a GTK que hemos acabado de especificar los atributos del widget, y que por tanto puede mostrarlo. La última línea comienza el proceso del bucle principal de GTK.
gtk_main ();

Otra llamada que siempre está presente en cualquier aplicación es gtk_main(). Cuando el control llega a ella, GTK se queda dormido esperando a que suceda algún tipo de evento de las X (como puede ser pulsar un botón), que pase el tiempo necesario para que el usuario haga algo, o que se produzcan notificaciones de IO de archivos. En nuestro caso concreto todos los eventos serán ignorados.

2.1 Programa «Hola Mundo» en GTK
El siguiente ejemplo es un programa con un widget (un botón). Simplemente es la versión de GTK del clásico «hola mundo».
/* comienzo del ejemplo holamundo */ #include <gtk/gtk.h> /* Ésta es una función respuesta (callback). Sus argumentos son ignorados por en este ejemplo */ void hello (GtkWidget *widget, gpointer data) { g_print ("Hola mundo\n"); } gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) { /* si se devuelve FALSE al administrador de llamadas * "delete_event", GTK emitirá la señal de destrucción * "destroy". Esto es útil para diálogos emergentes del * tipo: ¿Seguro que desea salir? g_print ("Ha ocurrido un evento delete\n"); /* Cambiando TRUE por FALSE la ventana se destruirá con * "delete_event"*/ return (TRUE); } /* otra respuesta */ void destroy (GtkWidget *widget, gpointer data) { gtk_main_quit (); }

int main (int argc, char *argv[]) { /* GtkWidget es el tipo de almacenamiento usado para los * widgets */ GtkWidget *ventana; GtkWidget *boton; /* En cualquier aplicación hay que realizar la siguiente * llamada. Los argumentos son tomados de la línea de comandos * y devueltos a la aplicación. */ gtk_init (&argc, &argv); /* creamos una ventana nueva */ ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL); /* Cuando la ventana recibe la señal "delete_event" (emitida * por el gestor de ventanas, normalmente mediante la opción * 'close', o en la barra del título) hacemos que llame a la * función delete_event() tal y como ya hemos visto. Los datos * pasados a la función de respuesta son NULL, y serán ignorados. */ gtk_signal_connect (GTK_OBJECT (ventana), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL); /* Aquí conectamos el evento "destroy" con el administrador de * señales. El evento se produce cuando llamamos a * gtk_widget_destroy() desde la ventana o si devolvemos 'FALSE' * en la respuesta "delete_event". */ gtk_signal_connect (GTK_OBJECT (ventana), "destroy", GTK_SIGNAL_FUNC (destroy), NULL); /* establecemos el ancho del borde de la ventana. */ gtk_container_border_width (GTK_CONTAINER (ventana), 10); /* creamos un botón nuevo con la etiqueta "Hola mundo" */ boton = gtk_button_new_with_label ("Hola mundo"); /* Cuando el botón recibe la señal "clicked" llama a la * función hello() pasándole NULL como argumento. (La * función ya ha sido definida arriba). */ gtk_signal_connect (GTK_OBJECT (boton), "clicked", GTK_SIGNAL_FUNC (hello), NULL); /* Esto hará que la ventana sea destruida llamando a * gtk_widget_destroy(ventana) cuando se produzca "clicked". Una * vez mas la señal de destrucción puede provenir del gestor * de ventanas o de aquí. */ gtk_signal_connect_object (GTK_OBJECT (boton), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (ventana)); /* Ahora empaquetamos el botón en la ventana (usamos un gtk * container ). */ gtk_container_add (GTK_CONTAINER (ventana), boton); /* El último paso es representar el nuevo widget... */ gtk_widget_show (boton); /* y la ventana */ gtk_widget_show (ventana); /* Todas las aplicaciones basadas en GTK deben tener una llamada * gtk_main() ya que el control termina justo aquí y debe * esperar a que suceda algún evento */

como por ejemplo la señal «toggled» de un botón de selección (botón toggle). aunque la terminología es la misma. gtk-config --cflags dará una lista con los directorios donde el compilador debe buscar ficheros «include». el tercero es la función a la que queremos que se llame cuando se `cace' la señal y el cuarto los datos que queremos pasarle a esta función. En nuestro ejemplo sólo hemos usado g_print(). (Conviene destacar que las señales de GTK no son iguales que las de los sistemas UNIX. como por ejemplo la pulsación de un botón. que contiene diversas funciones. Es usada por GTK para diferentes cosas. El control se transfiere mediante «señales». que ya viene (y se instala) con la biblioteca. Es muy útil porque `conoce' que opciones son necesarias para compilar programas que usen gtk. GtkSignalFunc func. el wrapper de Xlib. Esto se hace usando una función como: gint gtk_signal_connect( GtkObject *objeto. La biblioteca Xext (-lXext) contiene código para pixmaps de memoria compartida y otras extensiones. La biblioteca GDK (-lgdk). La biblioteca matemática (-lm). La función especificada en el tercer argumento se denomina «función de respuesta» y debe tener la forma siguiente: . La biblioteca glib (-lglib). return 0. Para que un botón haga algo crearemos un controlador que se encarga de recoger las señales y llamar a la función apropiada. Hay que destacar que las comillas simples en la orden de compilación son absolutamente necesarias. gchar *nombre. Así es como GTK proporciona la mayor parte de su utilidad. La biblioteca Xlib (-lX11) que es usada por GDK.2 Compilando Hello World Para compilar el ejemplo hay que usar: gcc -Wall -g helloworld. como por ejemplo «destroy» y hay señales que son específicas de cada widget. momento en el cual se transfiere el control a la función adecuada.3 Teoría de señales y respuestas Antes de profundizar en holamundo vamos a discutir las señales y las respuestas.gtk_main (). la biblioteca de widgets que se encuentra encima de GDK. 2. Esto quiere decir que GTK «duerme» en gtk_main hasta que se recibe un evento. gpointer datos_func ). el segundo el nombre de la señal que queremos `cazar'.) Cuando sucede un evento. A su vez gtk-config --libs nos permite saber las bibliotecas que el compilador intentará enlazar y dónde buscarlas. Las bibliotecas que se enlazan normalmente son: • • • • • • La biblioteca GTK (-lgtk). GTK está construida encima de glib por lo que simpre se usará. GTK es un toolkit (conjunto de herramientas) gestionadas mediante eventos. Vea la sección glib para más detalles. se «emitirá» la señal apropiada por el widget pulsado. Donde el primer argumento es el widget que emite la señal. } /* final del ejemplo*/ 2. Hay un conjunto de señales que todos los widgets heredan.c -o hello_world `gtk-config --cflags` \ `gtk-config --libs` Usamos el programa gtk-config.

o simplemente terminar la aplicación. gint delete_event(GtkWidget *widget. estamos diciendo que no queremos que se emita la señal «destroy» y por lo tanto queremos que nuestra aplicación siga ejecutándose. Sin embargo no es normal establecer una respuesta para gtk_signal_connect_object. gpointer datos_respuesta ). el «delete_event» ocurre cuando el gestor de ventanas envía este evento a la aplicación. y el segundo un puntero a los datos pasados a la función tal y como hemos visto en el último argumento a gtk_signal_connect(). En el ejemplo ignoramos tanto el widget como la información. Por ejemplo. void hello (GtkWidget *widget. Si devolvemos TRUE. Ésta es la función respuesta a la que se llamará cuando se pulse el botón. El valor devuelto en esta respuesta le permite a GTK saber que tiene que hacer. GtkObject *slot_object ). En lugar de ello llamamos a una función de GTK que acepte un widget o un objeto como un argumento. Donde. el objeto es un widget. Aquí podemos decidir que hacemos con estos eventos. GtkSignalFunc func. ya que algunas señales específicas pueden generar diferentes parámetros de llamada. Muchas funciones de GTK sólo aceptan un puntero a un GtkWidget como argumento. Donde el primer argumento será un puntero al widget que emitió la señal. tal y como se vio en el ejemplo hola mundo. la función de respuesta debe ser de la forma: void callback_func( GtkObject *object ). la señal de GtkCList «select_row» proporciona los parámetros fila y columna. El siguiente ejemplo usará la información que recibe como argumento para decirnos que botón fue presionado.4 Aclaración de Hello World Ahora que conocemos la teoría vamos a aclarar las ideas estudiando en detalle el programa helloworld. . Los podemos ignorar. un puntero a un objeto GTK. dar algún tipo de respuesta. --> 2. por regla general. gpointer data) { g_print ("Hello World\n"). lo que hará que se ejecute nuestro manejador de señal de «destroy».void callback_func( GtkWidget *widget. Otra llamada usada en el ejemplo del hola mundo es: gint gtk_signal_connect_object( GtkObject *objeto. Por tanto cuando usemos esta función para conectar señales. gtk_signal_connect_object() es idéntica a gtk_signal_connect() excepto en que la función de llamada sólo usa un argumento. GdkEvent *event. } La siguiente respuesta es un poco especial. Conviene destacar que la declaración de la función de respuesta debe servir sólo como guía general. por lo que tendrá que usar gtk_signal_connect_object() con estas funciones. decimos que se emita «destroy». gpointer data) { g_print ("delete event occured\n"). pero no es difícil usarlos. ¿Para qué sirve tener dos funciones para conectar señales? Simplemente para permitir que las funciones de respuesta puedan tener un número diferente de argumentos. gchar *nombre. mientras que probablemente tenga que suministrarle información adicional a sus funciones. Si devolvemos FALSE.

ventana que no se mostrará hasta que llamemos a gtk_widget_show (ventana) hacia el final del programa. NULL). } Con el siguiente ejemplo presentamos otra función de respuesta que hace que el programa salga llamando a gtk_main_quit(). que se utilizarán más adelante para crear una ventana y un botón. GtkWidget *boton. Hay funciones similares que serán tratadas con más detalle en la sección Estableciendo los atributos de los <em/widgets/ De nuevo. char *argv[]) Las líneas siguientes declaran un puntero a una estructura del tipo GtkWidget. int main (int argc.return (TRUE). &argv). La siguiente llamada crea un nuevo botón. 10). La siguiente función establece un atributo a un objeto contenedor (discutidos luego). de modo que la aplicación recibirá el resto. Simplemente reservamos memoria para la estructura GtkWindow *ventana. Todas las aplicaciones GTK también tienen una función de este tipo. void destroy (GtkWidget *widget. "destroy". Así conseguimos manejar los dos casos con una simple llamada a la función destroy () (definida arriba) pasándole NULL como argumento y ella acabará con la aplicación por nosotros. Su etiqueta será: "Hola mundo". la ventana. con lo que ya tenemos una nueva ventana. la inicializa y hace que el puntero boton apunte a esta estructura. Cualquier argumento que sea reconocido será borrado de la lista de argumentos. GTK_CONTAINER es una macro que se encarga de la conversión entre tipos gtk_container_border_width (GTK_CONTAINER (ventana). En este caso le pone a la ventana un área negra de 10 pixels de ancho donde no habrán widgets. GtkWidget *ventana. GTK_SIGNAL_FUNC (destroy). gtk_signal_connect (GTK_OBJECT (ventana). Aquí tenemos un ejemplo de como conectar un manejador de señal a un objeto. gtk_init (&argc. La señal a cazar será «destroy». en este caso. Ahora vamos a crear una ventana. Esta señal se emite cuando utilizamos el administrador de ventanas para matar la ventana (y devolvemos TRUE en el manejador «delete_event»). También aumentan la legibilidad del código. Con esta función le decimos a GTK que salga de la rutina gtk_main() cuando vuelva a estar en ella. . o cuando usamos llamamos a gtk_widget_destroy() pasándole el widget que representa la ventana como argumento. y una aplicación GTK no va a ser menos. Reserva espacio en la memoria para una nueva estructura del tipo GtkWidget. ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL). GTK_OBJECT y GTK_SIGNAL_FUNC son macros que realizan la comprobación y transformación de tipos por nosotros. } Como el lector probablemente ya sabe toda aplicación debe tener una función main(). Como antes arranca el conjunto de herramientas y filtra las opciones introducidas en la línea de órdenes. gpointer data) { gtk_main_quit (). Aquí tenemos otra vez a gtk_init.

Conviene destacar que un contenedor GTK sólo puede contener un widget. De todas formas con un ejemplo tan simple nunca se notaría cual es el orden de aparición. GTK_SIGNAL_FUNC (hola). gtk_signal_connect (GTK_OBJECT (boton). boton). al igual que arriba. Los datos adicionales serán ignorados. sólo nos queda pedirle a GTK que muestre todos los widgets en pantalla. return 0. en vez de ver aparecer la ventana. utilizaremos gtk_signal_connect_object() en lugar de gtk_signal_connect(). y después ver aparecer el botón. Así aclararemos cómo es posible que la señal «destroy» sea emitida tanto por el gestor de ventanas como por nuestro programa. pero si devolvemos FALSE GTK emitirá la señal «destroy» que. Si en la función manejadora «delete_event» devolvemos TRUE la ventana se quedará como si nada hubiese ocurrido. que saldrá de GTK. GTK_SIGNAL_FUNC (gtk_widget_destroy).1 Tipos de datos . El widget ventana será el último en mostrarse queremos que aparezca todo de golpe. Se usa para decirle a GTK que el botón debe estar en la ventana dónde será mostrado. para ello enlazamos el botón con el manejador de señales para que cuando emita la señal «clicked». por lo que simplemente le pasaremos NULL a la función respuesta. Como la función gtk_widget_destroy() sólo acepta un GtkWidget como argumento. Las funciones respuesta serán ejecutadas en el orden en que sean conectadas. Existen otros widgets (descritos después) que sirven para contener y establecer la disposición de varios widgets de diferentes formas. Obviamente se emitirá la señal «clicked» cuando pulsemos en el botón con el ratón. Ahora hacemos que el botón sea útil. Esto hace que la ventana emita la señal «destroy». lo que destruye al widget. y que llama a nuestra función respuesta destroy(). Ahora ya tenemos todo bien organizado. "clicked". Para que podamos usar la información el programa activa el gestor de eventos que al recibir la señal llama a la función que hemos elegido. Por último el `return' final que devuelve el control cuando gtk_quit() sea invocada. Cuando pulsemos el botón del ratón el widget emite la señal correspondiente «clicked». Así conseguimos que se llame a la función gtk_widget_destroy() con el widget asociado a la ventana como argumento. En nuestro ejemplo cuando pulsamos el botón se llama a la función hello() con NULL como argumento y además se invoca al siguiente manipulador de señal. 3. que es cazada. Cuando el botón es pulsado. se llama a la primera función respuesta hello() y después se llamará a esta función. XXX Ahora vamos a usar el botón para terminar nuestro programa. Llamamos a gtk_main() que espera hasta que el servidor X le comunique que se ha producido algún evento para emitir las señales apropiadas. gtk_widget_show (boton). se llame a nuestra función hola(). GTK_OBJECT (ventana)). La siguiente llamada sirve para empaquetar (más detalles luego). por supuesto. NULL). gtk_main (). Esto emitirá «delete_event» que hará que se llame a nuestra función manejadora correspondiente. gtk_container_add (GTK_CONTAINER (ventana). que simplemente sale de GTK.boton = gtk_button_new_with_label ("Hola mundo"). Como todos los controladores de las señales ya están en su sitio. gtk_widget_show (ventana). y el botón está situado en la ventana donde queremos que esté. Avanzando 3. llamará a la función respuesta «destroy». gtk_signal_connect_object (GTK_OBJECT (boton). "clicked". Otra posibilidad es usar el gestor de ventanas para acabar con la aplicación.

h> /* Nuestra respuesta mejorada.Existen algunos detalles de los ejemplos anteriores que hay que aclarar. Probablemente el lector se haya dado cuenta de que se puede usar GtkWidget cuando la función llama a un GtkObject. Esto es debido a que GTK está orienta a objetos y un widget es un GtkObject. gpointer func_data ). Tal y como ya vimos podemos tener tantas funciones de respuesta por seÑal y objeto como sean necesarias. /* principio del ejemplo helloworld2 */ #include <gtk/gtk. gchar. que puede ver por ahí son typedefs a int y a char respectivamente. Esta etiqueta nos permite eliminar la función respuesta de la lista usando: void gtk_signal_disconnect( GtkObject *object. Por lo tanto podemos desconectar un manejador de señal pasándole a la función anterior el widget del que queremos desconectar y la etiqueta o id devuelta por una de las funciones signal_connect. Todas las definiciones son muy intuitivas y se encuentran definidas en glib/glib.h (que se incluye desde gtk. bien sea un Alpha de 64 bits o un i386 de 32. gpointer data) { gtk_main_quit ().*/ void callback (GtkWidget *widget. Esta llamada es bastante auto explicativa. gint id ). etc. 3. También introduciremos los widgets usados para empaquetar. } .%s was pressed\n". 3. Podemos darnos cuenta de que el valor devuelto es del tipo gint.h). GdkEvent *event. } /* otra respuesta*/ void delete_event (GtkWidget *widget. (char *) data). Los tipos gint. Simplemente quitamos todos los controladores de señales del objeto que pasamos como primer argumento. Sirven para que no haya que tener en cuenta el tamaño de cada uno de ellos a la hora de hacer cálculos. Vamos a mejorar el ejemplo para obtener una visión más amplia sobre el manejo de señales y respuestas.3 Un Hello World mejorado. Este valor es una etiqueta que identifica a la función de respuesta.2 Más sobre el manejo de señales Si estudiamos en mayor profundidad la declaración de gtk_signal_connect: gint gtk_signal_connect( GtkObject *object. GtkSignalFunc func. Otra función que se usa para quitar desconectar todos los controladores de un objeto es: void gtk_signal_handlers_destroy( GtkObject *object ). y cada una de ellas se ejecutará en el mismo orden en el que fueron enlazadas. Un buen ejemplo es gint32 que es un entero de 32 bits independientemente de la plataforma. Los argumentos de la función se * imprimen en el stdout. gchar *name. gpointer data) { g_print ("Hello again .

La caja no se ve realmente. GtkWidget *boton. */ gtk_signal_connect (GTK_OBJECT (boton). /* creamos una nueva ventana*/ ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL). boton. El * procedimiento de empaquetamiento se describe en detalle en la * sección correspondiente. */ gtk_widget_show(boton). /* Cada vez que el botón sea pulsado llamamos a la función * "callback" con un puntero a "botón 1" como argumento. caja1). 0). */ boton = gtk_button_new_with_label ("Botón 1").int main (int argc. TRUE. (gpointer) "botón 1"). Los argumentos introducidos a la aplicación*/ gtk_init (&argc. GTK_SIGNAL_FUNC (delete_event). /* Establecemos el ancho del borde de la ventana. gtk_box_pack_start(GTK_BOX(caja1). */ caja1 = gtk_hbox_new(FALSE. /* Llamamos a la misma función de respuesta pero con diferente * argumento: un puntero a "botón 2". TRUE. 10). "¡Hola botones!"). */ gtk_box_pack_start(GTK_BOX(caja1). "clicked". TRUE. NULL). /* Siempre se debe realizar este paso. /* Establecemos el controlador para la llamada delete_event que * termina la aplicación inmediatamente. GtkWidget *caja1. 0).*/ gtk_container_border_width (GTK_CONTAINER (ventana). char *argv[]) { /* GtkWidget es el tipo de almacenamiento usado para los wigtes*/ GtkWidget *ventana. "delete_event". sólo * sirve para introducir los widgets. (gpointer) "botón 2"). GTK_SIGNAL_FUNC (callback). /* ponemos la caja en la ventana principal */ gtk_container_add (GTK_CONTAINER (ventana). &argv). /* Esta llamada está presente en todas las aplicaciones basadas * en GTK. . boton. /* Esta función es nueva. */ gtk_signal_connect (GTK_OBJECT (boton). */ gtk_signal_connect (GTK_OBJECT (ventana). Sirve para decirle a GTK * que los preparativos del botón ya se han finalizado y que * por tanto puede ser mostrado. TRUE. */ boton = gtk_button_new_with_label ("Botón 2"). /* Creamos un nuevo botón con la etiqueta "Botón 1". /* hacemos lo mismo para crear un segundo botón. /* En lugar de gtk_container_add empaquetamos el botón en la * caja invisible. "clicked". GTK_SIGNAL_FUNC (callback). pone como título de la ventana * "¡Hola botones!"*/ gtk_window_set_title (GTK_WINDOW (ventana). 0). que a su vez ha sido empaquetado en la * ventana. /* Creamos una caja donde empaquetaremos los widgets.

Probablemente ya se habrá dado cuenta de que no hay una forma sencilla para terminar el programa. Nosotros usaremos gtk_box_pack_start() en la mayoria de nuestros ejemplos. 4. De hecho. Éstas son widgets invisibles que pueden contener nuestros widgets de dos formas diferentes. pero se recomienda mostrar la ventana la última * para que todo aparezca de golpe. 4. Usando estas funciones podemos ir metiendo widgets con una justificación a la izquierda o a la derecha y además podemos mezclarlas de cualquier manera para conseguir el efecto deseado./* El orden en que mostramos los botones no es realmente * importante. Pero cuando cuando se quiere poner más de un widget en una ventana. ¿Cómo podemos controlar donde aparecerá el widget?. Como puede imaginarse. */ gtk_widget_show(boton). Un objeto puede ser otro contenedor o un widget.1 Empaquetamiento usando cajas Normalmente para empaquetar se usan cajas. Intente cambiar el tamaño de la ventana y observe el comportamiento.*/ gtk_main (). Nuestro primer ejemplo sólo usaba un widget por lo que usábamos la función gtk_container_add para «empaquetar» el widget en la ventana. Su comportamiento es un poco diferente y debe ser usado para ventanas intermedias (cuadros de diálogo). incluyendo el widget botón (button) (aunque normalmente lo único que meteremos dentro será una etiqueta de texto). horizontal o verticalmente. Hay muchas opciones y no es obvio como encajan unas con otras. Las funciones usadas para introducir objetos dentro son gtk_box_pack_start() y gtk_box_pack_end(). Pero en la práctica sólo hay cinco estilos diferentes. se debe usar el gestor de ventanas o la línea de comandos para ello. por ejemplo. } /* final del ejemplo*/ Compile el programa usando los mismos argumentos que en el ejemplo anterior. Debido a esta flexibilidad el empaquetamiento puede ser confuso al principio. este método nos da una gran flexibilidad a la hora de colocar y crear widgets. Aquí es donde entra el empaquetamiento. Al hacerlo de la primera forma los objetos son insertados de izquierda a derecha o al revés (dependiendo de que llamada se use). Widgets usados para empaquetar Al crear una aplicación normalmente se quiere que haya más de un widget por ventana. También puede resultar interesante probar las diferentes opciones de gtk_box_pack_start() mientras lee la siguiente sección. Lo mismo ocurre en los verticales (de arriba a bajo o al revés). . Mediante el uso de estas funciones le decimos a GTK dónde queremos situar nuestros widgets. gtk_widget_show (ventana). muchos widgets son contenedores. Para crear una caja horizontal llamamos a gtk_hbox_new() y para las verticales gtk_vbox_new(). return 0. La segunda lo hará al revés. gtk_widget_show(caja1). existe otra definición bastante útil: gtk_widow_new() . 4. Un buen ejercicio para el lector es introducir un tercer botón que termine el programa. y GTK podrá. Se pueden usar tantas cajas como se quieran para conseguir cualquier tipo de efecto. cambiarles el tamaño de forma automática y hacer otras cosas de utilidad. Como última nota.GTK_WINDOW_DIALOG.2 Detalles de la cajas. La primera llenará de arriba a abajo o de izquierda a derecha. También hay unas cuantas opciones que tienen que ver con la forma en la que los widgets serán empaquetados. tal y como ya hemos visto. /* Esperamos en gtk_main a que comience el espectáculo.

los widgets se expandirán para llenar toda la caja. . Puede que el lector se esté haciendo la siguiente pregunta: ¿Cúal es la diferencia entre espaciar (establecido cuando se crea la caja) y rellenar (determinado cuando se empaquetan los elementos)? El espaciado se añade entre objetos. gint spacing). Eso sí. Al crear una nueva ventana la función debe ser parecida a esta: GtkWidget *gtk_hbox_new (gint homogeneous. y podemos conseguir el mismo efecto utilizando sólo una de las funciones gtk_box_pack_start o pack_end. Sólo tiene efecto si el argumento de expansión también es TRUE. el segundo el objeto. El argumento fill de gtk_box controla si el espacio extra se mete dentro de los objetos (TRUE) o como relleno extra (FALSE). Poniendo FALSE en expand podremos hacer que nuestros widgets tengan una justaficación a la derecha o a la izquierda. La llamada a gtk_box_pack es una manera de conseguir empaquetar cada uno de los botones dentro de la caja. el argumento expand de las rutinas gtk_box_pack siempre estará activado. El primer argumento es la caja dónde se empaqueta. ya que estamos empaquetando botones dentro de las cajas. En caso contrario. gint expand. Si se activa. gint padding ). Por ahora el objeto será un botón. La siguiente figura debe aclarar la cuestión. Esta es la declaración de la función gtk_box_pack_start: void gtk_box_pack_start( GtkBox *box. El argumento expand de gtk_box_pack_start() y de gtk_box_pack_end() controla si los widgets son expandidos en la caja para rellenar todo el espacio de la misma (TRUE) o si por el contrario no se usa el espacio extra dentro de la caja (FALSE).Cada línea contiene una caja horizontal (hbox) con diferentes botones. El argumento homogeneous (tanto para gtk_hbox_new como para gtk_vbox_new) controla si cada objeto en la caja tiene el mismo tamaño (anchura en una hbox o altura en una vbox). gint fill. y el rellenado se hace en cada parte de cada objeto. GtkWidget *hijo. cada uno de ellos se empaqueta de la misma forma que el resto (se llama con los mismos argumentos a gtk_box_pack_start()).

boton = gtk_button_new_with_label ("(box. gint expand. gint padding) { GtkWidget *box. } /* Hacemos una hbox llena de etiquetas de botón. /* crear una serie de botones */ boton = gtk_button_new_with_label ("gtk_box_pack")."). Los argumentos * para las variables que estamos interesados son pasados a esta * función. padding). else boton = gtk_button_new_with_label ("FALSE.Estudiemos el código usado para crear las imágenes anteriores. gpointer data) { gtk_main_quit (). expand. fill.3 Programa demostración de empaquetamiento /* principio del ejemplo packbox packbox."). fill. boton = gtk_button_new_with_label ("boton. gtk_widget_show (boton). char padstr[80]. GdkEvent *event. boton.h> #include "gtk/gtk. boton. /* Este botón llevará por etiqueta el valor de expand */ if (expand == TRUE) boton = gtk_button_new_with_label ("TRUE.c */ #include <stdio. . /* creamos una nueva caja con los argumentos homogeneous y * spacing */ box = gtk_hbox_new (homogeneous. gtk_box_pack_start (GTK_BOX (box). boton. gint fill. gtk_widget_show (boton). padding). No mostramos la caja. expand. expand."). gint spacing. Con los comentarios no debería de haber ningún problema para entenderlo. GtkWidget *boton. */ GtkWidget *make_box (gint homogeneous. gtk_box_pack_start (GTK_BOX (box). gtk_widget_show (boton).h" void delete_event (GtkWidget *widget. 4. pero hacemos todo lo que * queremos."). padding). fill. spacing). gtk_box_pack_start (GTK_BOX (box).

padding).". NULL). gtk_widget_show (boton). } which = atoi (argv[1]). where num is 1. sprintf (padstr. return box. "%d). boton. 10). expand. fill. fill. /* Aclaramos cúal es el ejemplo a mostrar. "usage: packbox num. Se corresponde con * las imágenes anteriores. /* Creamos una caja vertical donde empaquetaremos las cajas * horizontales. */ etiqueta = gtk_label_new ("gtk_hbox_new (FALSE. fill. /* Este es el mismo caso que el de arriba. gtk_box_pack_start (GTK_BOX (box). */ caja1 = gtk_vbox_new (FALSE.gtk_box_pack_start (GTK_BOX (box). boton. /* hacemos limpieza en GTK y devolvemos el valor de 1 */ gtk_exit (1). pero más compacto */ boton = gtk_button_new_with_label (fill ? "TRUE. char *argv[]) { GtkWidget *ventana. Esto es muy importante para que el * comportamiento de la ventana sea intuitivo. gtk_widget_show (boton). if (argc != 2) { fprintf (stderr. GtkWidget *caja2. 2. Así podemos apilar las cajas horizontales * llenas con botones una encima de las otras. "delete_event". gtk_widget_show (boton). padding). GtkWidget *caja1. /* Alineamos la etiqueta a la izquierda.\n"). padding). boton. GtkWidget *separator. padding). int which."). */ ."). boton = gtk_button_new_with_label (padstr). expand. 0)." : "FALSE. GtkWidget *quitbox. /* Creamos la ventana */ ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL). /* Siempre hay que conectar la señal de destrucción con la * ventana principal. expand. gtk_box_pack_start (GTK_BOX (box). &argv). gtk_container_border_width (GTK_CONTAINER (ventana). GtkWidget *etiqueta. Está función * será discutida en detalle en la sección de los * atributos de los widgets. */ gtk_signal_connect (GTK_OBJECT (ventana). GTK_SIGNAL_FUNC (delete_event). 0). GtkWidget *boton. or 3. } int main (int argc. */ switch (which) { case 1: /* creamos una nueva etiqueta. /* ¡No olvidar la siguiente llamada! */ gtk_init (&argc.

0). TRUE. . /* un nuevo separador */ separator = gtk_hseparator_new (). gtk_widget_show (caja2). /* Los argumentos son: homogeneous. spacing = 0. /* creamos una nueva etiqueta y la mostramos */ etiqueta = gtk_label_new ("gtk_hbox_new (TRUE. break. FALSE. /* Los tres últimos argumentos son: expand. FALSE. gtk_widget_show (separator). /* Empaquetamos la etiqueta en la caja vertical (vbox * caja1). 0). 0). /* Llamad a la función para hacer cajas * homogeneous = FALSE. etiqueta. gtk_widget_show (caja2)."). spacing. TRUE. pero son bastante sencillos. spacing. gtk_widget_show (caja2). FALSE. 0). expand = FALSE. 0. spacing. FALSE. 0. FALSE. FALSE. 0). Siempre hay que recordar que los widgets añadidos a * una vbox serán empaquetados uno encimo de otro. * padding */ caja2 = make_box (TRUE. TRUE. gtk_box_pack_start (GTK_BOX (caja1). Los widgets serán * apilados verticalmente. /* Los argumentos son: homogeneous. expand = FALSE. 0). fill. expand. /* mostramos la etiqueta. FALSE. 0. */ gtk_widget_show (etiqueta). fill. FALSE. 0). gtk_widget_show (caja2). FALSE. FALSE. TRUE. caja2. gtk_box_pack_start (GTK_BOX (caja1). 0. FALSE. padding = 0 */ caja2 = make_box (FALSE. padding. gtk_widget_show (separator). FALSE. separator. 0). Los argumentos * son homogenous = FALSE. 0). gtk_misc_set_alignment (GTK_MISC (etiqueta). gtk_box_pack_start (GTK_BOX (caja1). 0). caja2. 5). /* Los argumentos son: homogeneous. 0). 0. FALSE. */ separator = gtk_hseparator_new (). caja2. caja2. gtk_box_pack_start (GTK_BOX (caja1). separator. 5). TRUE. 0). expand. */ gtk_box_pack_start (GTK_BOX (caja1). TRUE. 0). gtk_widget_show (caja2). Más tarde aprenderemos más cosas * sobre ellos. FALSE. * padding */ caja2 = make_box (FALSE. FALSE. /* llamada a la función que hace las cajas. 0. * padding */ caja2 = make_box (TRUE. FALSE. FALSE. FALSE. * fill = FALSE. fill = FALSE. caja2. TRUE. 0. 0). /* empaquetamos el separador el la vbox. 0). /* creamos un separador. FALSE. gtk_widget_show (etiqueta). gtk_box_pack_start (GTK_BOX (caja1).gtk_misc_set_alignment (GTK_MISC (etiqueta). */ gtk_box_pack_start (GTK_BOX (caja1). fill. * padding = 0 */ caja2 = make_box (FALSE. etiqueta. */ gtk_box_pack_start (GTK_BOX (caja1). FALSE. fill. gtk_box_pack_start (GTK_BOX (caja1). TRUE. expand.

etiqueta. FALSE. FALSE. /* Los argumentos son: homogeneous. . 5). FALSE. FALSE. fill. separator. FALSE. TRUE. /* mostrar la etiqueta */ gtk_widget_show (etiqueta). gtk_box_pack_start (GTK_BOX (caja1). 0). expand. caja2. spacing. por lo que se * sitúa en el lado derecho de la hbox. FALSE. 0. 0). /* Los argumentos son: expand. spacing. FALSE. FALSE. spacing. /* Los argumentos son: homogeneous. gtk_widget_show (caja2). 0.*/ gtk_box_pack_end (GTK_BOX (caja2). TRUE. 0). /* Los argumentos son: homogeneous. fill. gtk_widget_show (caja2). /* Los argumentos son: expand. 0. 0). 0). padding. /* Los argumentos son: homogeneous. 0. TRUE. gtk_widget_show (caja2). gtk_box_pack_start (GTK_BOX (caja1). * padding */ caja2 = make_box (FALSE. break. caja2. * padding */ caja2 = make_box (FALSE. FALSE. 0). separator. gtk_box_pack_start (GTK_BOX (caja1). FALSE. caja2. separator = gtk_hseparator_new (). 0). gtk_widget_show (etiqueta). expand. */ gtk_box_pack_start (GTK_BOX (caja1). gtk_box_pack_start (GTK_BOX (caja1). FALSE. 0. FALSE. TRUE.case 2: /* Nueva etiqueta */ etiqueta = gtk_label_new ("gtk_hbox_new (FALSE. 0). * padding */ caja2 = make_box (FALSE. 0). FALSE. caja2. 0). FALSE. expand. FALSE. spacing. fill. gtk_misc_set_alignment (GTK_MISC (etiqueta). case 3: /* Con esto demostramos como hay que usar gtk_box_pack_end () * para conseguir que los widgets esten alineados a la izquierda. */ gtk_box_pack_start (GTK_BOX (caja1). TRUE. /* la última etiqueta*/ etiqueta = gtk_label_new ("end"). TRUE. 0). gtk_misc_set_alignment (GTK_MISC (etiqueta). 0). 5). 10). padding. expand. FALSE. etiqueta. */ caja2 = make_box (FALSE. gtk_widget_show (caja2). gtk_widget_show (etiqueta). fill. 10). TRUE. FALSE."). fill. 10. gtk_widget_show (separator)."). 10). FALSE. fill. gtk_box_pack_start (GTK_BOX (caja1). FALSE. TRUE. etiqueta. FALSE. * padding */ caja2 = make_box (FALSE. /* la empaquetamos usando gtk_box_pack_end(). gtk_widget_show (separator). separator = gtk_hseparator_new (). gtk_box_pack_start (GTK_BOX (caja1). 0). 10. etiqueta = gtk_label_new ("gtk_hbox_new (FALSE.

quitbox. /* * * * Establecemos la señal de destrucción de la ventana. gtk_widget_show (separator). gtk_widget_show (caja1). */ gtk_main (). /* el separador para la parte de abajo. 400. */ gtk_container_add (GTK_CONTAINER (ventana). gtk_widget_show (caja2). 0)./* empaquetamos caja2 en caja1 */ gtk_box_pack_start (GTK_BOX (caja1). /* Empaquetamos el separador creado al principio de main() en * la vbox (caja1). GTK_OBJECT (ventana)). */ gtk_widget_show (ventana).. GTK_SIGNAL_FUNC (gtk_main_quit). FALSE. separator. /* El programa llega aquí cuando se llama a gtk_main_quit(). Si no establecemos estos * parámetros todos los widgets en la hbox serán * empaquetados tan juntos como se pueda. /* mostramos todo aquello que faltaba por mostrar */ gtk_widget_show (boton). Recuerde que emitirá la señal de "destroy" que a su vez será procesada por el controlador de señales. /* por supuesto tenemos una función main. */ boton = gtk_button_new_with_label ("Quit"). /* El botón de salida. */ return 0. gtk_widget_show (quitbox). TRUE. 5).*/ gtk_widget_set_usize (separator. padding. */ gtk_box_pack_start (GTK_BOX (caja1). La hbox también tendrá 400 * pixels de largo y la etiqueta "end" estará separada de * las demás etiquetas en la hbox. "clicked". 0). * los tres últimos argumentos de gtk_box_pack_start * son:expand. recordar que podemos crear tantas como * queramos. caja2. /* Así se determina el tamaño del separador a 400 pixels * de largo por 5 de alto. FALSE.. /* Si mostramos la ventana lo último todo aparece de golpe. /* Empaquetamos el botón en la caja de salida (quitbox). FALSE. */ gtk_box_pack_start (GTK_BOX (caja1). FALSE. 5). } /* final del ejemplo*/ 4. caja1). } /* Creamos otra hbox. * pero no cuando se llama a gtk_exit(). fill. 0). */ quitbox = gtk_hbox_new (FALSE. */ separator = gtk_hseparator_new (). */ gtk_signal_connect_object (GTK_OBJECT (boton). tal y como ya hemos visto. FALSE. /* empaquetamos la vbox (caja1) que ya contiene todos los widgets * en la ventana principal.4 Empaquetamiento usando tablas .

Existe otra forma de empaquetar: usando tablas. Estas pueden llegar a ser extremadamente útiles. Usando tablas creamos una cuadrícula donde podemos poner los widgets. Estos pueden ocupar tanto espacio como queramos. La primera función que conviene estudiar es gtk_table_new:
GtkWidget *gtk_table_new( gint rows, gint columns, gint homogeneous );

Como es lógico el primer argumento es el número de filas y el segundo el de columnas. El tercero establece el tamaño de las celdas de la tabla. Si es TRUE se fuerza a que el tamaño de las celdas sea igual al de la celda mayor. Con FALSE se establece el ancho de toda una columna igual al de la celda más ancha de esa columna, y la altura de una fila será la de la celda más alta de esa fila. El número de filas y columnas varía entre 0 y n, donde n es el número especificado en la llamada a gtk_table_new. Así si se especifica columnas = 2 y filas = 2 la apariencia será parecida a:
0 1 2 0+----------+----------+ | | | 1+----------+----------+ | | | 2+----------+----------+

Conviene destacar que el origen de coordenadas se sitúa en la esquina superior izquierda. Para situar un widget en una ventana se usa la siguiente función:
void gtk_table_attach( GtkTable *table, GtkWidget *hijo, gint left_attach, gint right_attach, gint top_attach, gint bottom_attach, gint xoptions, gint yoptions, gint xpadding, gint ypadding );

El primer argumento (table) es el nombre de la tabla y el segundo (hijo) el widget que quiere poner en la tabla. Los argumentos left_attach, right_attach especifican donde se pone el widget y cuantas cajas se usan. Por ejemplo, supongamos que queremos poner un botón que sólo ocupe la esquina inferior izquierda en nuestra tabla 2x2. Los valores serán left_attach = 1, right_attach = 2, top_attach = 2, top_attach = 1, bottom_attach = 2. Supongamos que queremos ocupar toda la fila de nuestra tabla 2x2, usaríamos left_attach = 0, right_attach = 2, top_attach = 0, bottom_attach = 1. Las opciones xoptions e yoptions son usadas para especificar como queremos el empaquetamiento y podemos utilizar multiples opciones simultaneamente con OR. Las opciones son: •

GTK_FILL - Si el relleno es más grande que el widget, y se especifica GTK_FILL, el widget se expandirá ocupando todo el espacio disponible.

GTK_SHRINK - En el caso de que hayamos dejado espacio sin usar cuando el usuario reajuste el tamaño de la ventana los widgets normalmente serán empujados al fondo de la ventana y desaparecerán. Si especifica GTK_SHRINK los widgets se reducirán con la tabla. GTK_EXPAND - Mediante esta opción la tabla se expande usando todo el espacio libre de la ventana.

El relleno es igual que con las cajas. Simplemente se crea una zona vacía alrededor del widget (el tamaño se especifica en pixels). gtk_table_attach() tiene MUCHAS opciones. Asi que hay un atajo:
void gtk_table_attach_defaults( GtkTable *table, GtkWidget *widget, gint left_attach, gint right_attach, gint top_attach, gint bottom_attach );

Las opciones X e Y se ponen por defecto a GTK_FILL | GTK_EXPAND, y el relleno X e Y se pone a 0. El resto de los argumentos son identicos a la función anterior. Existen otras funciones como gtk_table_set_row_spacing() y gtk_table_set_col_spacing(), que sirven para especificar el espaciado entre las columnas/filas en la columna/fila que queramos.
void gtk_table_set_row_spacing( GtkTable *table, gint row, gint spacing );

y
void gtk_table_set_col_spacing ( GtkTable *table, gint column, gint spacing );

Conviene destacar que el espaciado se sitúa a la derecha de la columna y debajo de la fila. Tambien se puede forzar que el espaciado sea el mismo para las filas y/o las columnas:
void gtk_table_set_row_spacings( GtkTable *table, gint spacing );

y
void gtk_table_set_col_spacings( GtkTable *table, gint spacing );

Usando estas funciones las últimas fila y columna no estarán espaciadas.

4.5 Ejemplo de empaquetamiento mediante tablas.
Haremos una ventana con tres botones en una tabla 2x2. Los dos primeros botones ocuparán la fila de arriba, mientras que el tercero (de salida) ocupará toda la fila de abajo. El resultado es el siguiente:

Este es el código:
/* principio del ejemplo table table.c */ #include <gtk/gtk.h> /* La respuesta, que además se imprime en stdout. */ void callback (GtkWidget *widget, gpointer data) { g_print ("Hello again - %s was pressed\n", (char *) data); } /* Con esta otra respuesta terminamos el programa. */ void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) { gtk_main_quit (); } int main (int argc, char *argv[]) { GtkWidget *ventana; GtkWidget *boton; GtkWidget *table; gtk_init (&argc, &argv); ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (ventana), "Table"); gtk_signal_connect (GTK_OBJECT (ventana), "delete_event", GTK_SIGNAL_FUNC (delete_event), NULL); gtk_container_border_width (GTK_CONTAINER (ventana), 20); table = gtk_table_new (2, 2, TRUE); gtk_container_add (GTK_CONTAINER (ventana), table); boton = gtk_button_new_with_label ("botón 1"); gtk_signal_connect (GTK_OBJECT (boton), "clicked", GTK_SIGNAL_FUNC (callback), (gpointer) "botón 1"); gtk_table_attach_defaults (GTK_TABLE(table), boton, 0, 1, 0, 1); gtk_widget_show (boton); boton = gtk_button_new_with_label ("botón 2"); gtk_signal_connect (GTK_OBJECT (boton), "clicked", GTK_SIGNAL_FUNC (callback), (gpointer) "botón 2"); gtk_table_attach_defaults (GTK_TABLE(table), boton, 1, 2, 0, 1); gtk_widget_show (boton);

Mostrar el widget usando gtk_widget_show(). 2). 2. NULL). boton. 5. 4. Esto significa que siempre se puede usar un widget como argumento de una función (que acepte un objeto. Establecer los atributos del widget. GTK_SIGNAL_FUNC (delete_event). 0.boton = gtk_button_new_with_label ("Quit"). return 0. y que por lo tanto puede mostrarse. El hijo de un widget no se muestra hasta que lo hace la propia ventana (que en este caso es un widget padre) mediante gtk_widget_show().Una de las diferentes formas de crear un widget. } /* final del ejemplo */ 5. claro) realizando la conversión de tipo GTK_OBJECT(). gtk_widget_show (ventana). Por ejemplo: . gtk_widget_show (table). Se puede usar gtk_widget_hide para hacer que desaparezca. pero se recomienda mostrar al final la ventana para que todo aparezca de golpe. para usarlas sólo hay que mirar la declaración de la función. 3.1 Conversión de tipos GTK usa un sistema de conversión de tipos mediante macros que comprueban si se puede realizar la conversión y en caso afirmativo la hacen. gtk_main (). Aparecerán mucho en los ejemplos. Tal y como se puede ver en el árbol de clases (situado un poco más adelante) todos los widgets derivan de la clase base GtkObject. Mediante esta última llamada GTK `sabe' que hemos acabado de establecer los atributos del widget. 5. Las más comunes son: • • • • • • GTK_WIDGET(widget) GTK_OBJECT(object) GTK_SIGNAL_FUNC(function) GTK_CONTAINER(container) GTK_WINDOW(ventana) GTK_BOX(box) Todas son usadas para cambiar de tipo los argumentos de una función. (Todas serán explicadas en esta sección). Estudio general de los widgets Los pasos generales a la hora de crear un widget son: 1. Empaquetar el widget en un contenedor usando las llamadas apropiadas. Usar gtk_*_new . como gtk_container_add() o gtk_box_pack_start(). gtk_table_attach_defaults (GTK_TABLE(table). "clicked". 2. gtk_signal_connect (GTK_OBJECT (boton). 1. El orden en el que se muestran los widgets no es importante. gtk_widget_show (boton). Connectar todas las señales y los eventos a los controladores apropiados.

5. por lo que se recomienda echar un vistazo a los archivos de cabecera de GTK. Cualquiera puede ser usado junto con la macro GTK_CONTAINER como argumento a funciones en forma de puntero. Hemos hecho que el botón pase a ser un objeto y que se cambie el puntero a la función a una función respuesta. Desgraciadamente estas macros no son descritas en detalle en el tutorial. En la práctica es posible aprender a manejar un widget leyendo las declaraciones de las funciones. por lo que unos pueden derivar de otros (la mayoría lo hace de GtkContainer).gtk_signal_connect( GTK_OBJECT(boton). GTK_SIGNAL_FUNC(callback_function). "clicked". callback_data). Muchos widgets son contenedores.2 Árbol formado por los widgets A continuación se detallan todas las ramas del árbol que forman los widgets. GtkObject +GtkWidget | +GtkMisc | | +GtkLabel | | | +GtkAccelLabel | | | `GtkTipsQuery | | +GtkArrow | | +GtkImage | | `GtkPixmap | +GtkContainer | | +GtkBin | | | +GtkAlignment | | | +GtkFrame | | | | `GtkAspectFrame | | | +GtkButton | | | | +GtkToggleButton | | | | | `GtkCheckButton | | | | | `GtkRadioButton | | | | `GtkOptionMenu | | | +GtkItem | | | | +GtkMenuItem | | | | | +GtkCheckMenuItem | | | | | | `GtkRadioMenuItem | | | | | `GtkTearoffMenuItem | | | | +GtkListItem | | | | `GtkTreeItem | | | +GtkWindow | | | | +GtkColorSelectionDialog | | | | +GtkDialog | | | | | `GtkInputDialog | | | | +GtkDrawWindow | | | | +GtkFileSelection | | | | +GtkFontSelectionDialog | | | | `GtkPlug | | | +GtkEventBox | | | +GtkHandleBox | | | +GtkScrolledWindow | | | `GtkViewport | | +GtkBox | | | +GtkButtonBox | | | | +GtkHButtonBox | | | | `GtkVButtonBox | | | +GtkVBox | | | | +GtkColorSelection | | | | `GtkGammaCurve | | | `GtkHBox | | | +GtkCombo .

GtkAlignment GtkArrow GtkBin GtkBox GtkImage GtkItem GtkLabel GtkPixmap GtkScrolledWindow GtkSeparator GtkTable GtkAspectFrame GtkFrame . En la sección El widget EventBox se pueden encontrar más detalles sobre su uso.| | | `GtkStatusbar | | +GtkCList | | | `GtkCTree | | +GtkFixed | | +GtkNotebook | | | `GtkFontSelection | | +GtkPaned | | | +GtkHPaned | | | `GtkVPaned | | +GtkLayout | | +GtkList | | +GtkMenuShell | | | +GtkMenuBar | | | `GtkMenu | | +GtkPacker | | +GtkSocket | | +GtkTable | | +GtkToolbar | | `GtkTree | +GtkCalendar | +GtkDrawingArea | | `GtkCurve | +GtkEditable | | +GtkEntry | | | `GtkSpinButton | | `GtkText | +GtkRuler | | +GtkHRuler | | `GtkVRuler | +GtkRange | | +GtkScale | | | +GtkHScale | | | `GtkVScale | | `GtkScrollbar | | +GtkHScrollbar | | `GtkVScrollbar | +GtkSeparator | | +GtkHSeparator | | `GtkVSeparator | +GtkPreview | `GtkProgress | `GtkProgressBar +GtkData | +GtkAdjustment | `GtkTooltips `GtkItemFactory 5. Si se quieren capturar eventos se tendrá que utilizar GtkEventBox.3 Widgets sin ventanas Los siguientes widgets no tienen ventanas asociadas.

etiqueta. 3). &style->bg[GTK_STATE_NORMAL]. FALSE.c */ #include <gtk/gtk. mask). Estudiemos un ejemplo de gtk_button_new para crear un botón con una imagen y una etiqueta. 0). } . primero se crea una nueva caja y luego se empaquetan los objetos que se quieran mediante gtk_box_pack_start. FALSE. etiqueta = gtk_label_new (label_text). return (caja1). pixmapwid.c). GtkWidget *pixmapwid. /* principio del ejemplo buttons buttons.GtkVBox GtkHBox GtkVSeparator GtkHSeparator Vamos a continuar la explicación describiendo cada uno de los widgets mediante ejemplos. 6. gchar *label_text) { GtkWidget *caja1. Hay una sección que describe el proceso * en detalle */ pixmap = gdk_pixmap_create_from_xpm (parent->window. gtk_widget_show(etiqueta). Existen dos formas diferentes de crear un botón. */ GtkWidget *xpm_label_box (GtkWidget *parent. gtk_box_pack_start (GTK_BOX (caja1). xpm_filename). /* create box for xpm and etiqueta */ caja1 = gtk_hbox_new (FALSE. pixmapwid = gtk_pixmap_new (pixmap. /* cargamos el pixmap. gchar *xpm_filename. /* obtenemos el estilo del botón (probablemente para el color * de fondo. GdkBitmap *mask. FALSE. También se puede consultar el programa testgtk. &mask. FALSE. GtkStyle *style. GdkPixmap *pixmap. gtk_widget_show(pixmapwid).c (Se encuentra en gtk/testgtk. Se puede usar gtk_button_new_with_label() para conseguir un botón con etiqueta o simplemente gtk_button_new(). 3). GtkWidget *etiqueta. 2). Se * devuelve la caja.1 Botones normales Ya hemos visto prácticamente todo lo que hay que saber a cerca de este widget.h> /* Creamos la caja con una imagen y una etiqueta empaquetadas. gtk_box_pack_start (GTK_BOX (caja1). pero no estoy seguro) */ style = gtk_widget_get_style(parent). El widget Botón 6. Una vez finalizado esto se relaciona la caja con el botón mediante gtk_container_add. gtk_container_border_width (GTK_CONTAINER (caja1). El código está dividido en dos para que pueda ser reusado. Si se quiere se puede añadir una etiqueta a este último empaquetándola.

ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL). gtk_window_set_title (GTK_WINDOW (ventana)./* respuesta */ void callback (GtkWidget *widget. "destroy". gtk_signal_connect (GTK_OBJECT (boton). NULL). } /* final del ejemplo */ La función xpm_label_box puede ser usada para empaquetar xpm y etiquetas en cualquier widget que pueda ser un contenedor. (gpointer) "botón divertido"). "Botones con dibujos"). GtkWidget *caja1. GtkWidget *boton. GTK_SIGNAL_FUNC (gtk_exit). (char *) data). "clicked". GTK_SIGNAL_FUNC (gtk_exit). Se ha pulsado %s\n". gtk_widget_show(caja1). caja1 = xpm_label_box(ventana. boton = gtk_button_new (). gtk_container_add (GTK_CONTAINER (ventana). "botón divertido").xpm". gtk_container_border_width (GTK_CONTAINER (ventana). boton). "info. gtk_widget_realize(ventana). char *argv[]) { GtkWidget *ventana. 10). gtk_container_add (GTK_CONTAINER (boton). gpointer data) { g_print ("Hola de nuevo. return 0. gtk_main (). gtk_widget_show (ventana). NULL). "delete_event". &argv). El botón puede responder a las siguientes señales: • • • • pressed released clicked enter . /* It's a good idea to do this for all windows. GTK_SIGNAL_FUNC (callback). gtk_init (&argc. gtk_widget_show(boton). caja1). */ gtk_signal_connect (GTK_OBJECT (ventana). gtk_signal_connect (GTK_OBJECT (ventana). } int main (int argc.

• leave 6. el segundo TRUE cuando queremos que el botón no esté pulsado o FALSE para cuando lo esté. La señal que queremos recibir es «toggled». void gtk_toggle_button_toggled (GtkToggleButton *toggle_button).2 Botones de selección Estos botones son muy similares a los normales. En lugar de ser botones con texto en su interior son pequeños cuadrados con texto a su derecha. gpointer data) { if (GTK_TOGGLE_BUTTON (widget)->active) { /* Si el control llega aquí el botón está pulsado */ } else { /* El botón no está pulsado (sobresale) */ } } void gtk_toggle_button_set_state( GtkToggleButton *toggle_button. La primera crea un botón. mientras que la segunda crea un botón con una etiqueta. aunque sus propiedades y funciones son bastante similares. Por lo tanto muchas de sus llamadas seran heredadas por estos. Generalmente para comprobar el estado de una señal se establece un controlador de señales y luego se usa la siguiente macro. Por defecto se establece FALSE. Creamos un nuevo botón de selección: GtkWidget *gtk_toggle_button_new( void ). Para saber cual es el estado de un botón de selección. comprobación o circular se usa una de las macros del ejemplo siguiente. gint state ). Hay que destacar que cuando se usa gtk_toggle_button_set_state() y se cambia el estado del botón este emite la señal «clicked». El primer argumento es el botón. La función de respuesta debe ser de la forma: void toggle_button_callback (GtkWidget *widget. Cambia el estado del botón emitiendo la señal «toggled». 6. GtkWidget *gtk_toggle_button_new_with_label( gchar *etiqueta ). Como se ha podido imaginar estas funciones son iguales a las de un botón normal. La llamada de arriba puede ser usada para establecer el estado de un botón de selección (o de cualquiera de sus hijos: el circular o el de comprobación). Normalmente son usados para (des)seleccionar opciones. GtkWidget *gtk_check_button_new( void ).3 Botones de comprobación Los botones de comprobación son un poco diferentes a los anteriores. La única diferencia es que sólo pueden estar en dos posiciones diferentes alternadas mediante pulsaciones del ratón. En éstas se comprueba el estado del botón mediante una respuesta. . Los botones de selección son la base de otros tipos: los de comprobación y los circulares. Las dos funciones que los crean son muy similares a las de los botones normales.

NULL). ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL). GtkWidget *separator. } main(int argc. GtkWidget *boton. gtk_window_set_title (GTK_WINDOW (ventana). gpointer data ) { gtk_main_quit().4 Botones circulares Estos botones son similares a los de selección con la salvedad de que están agrupados. gint state ). Por tanto son usados para permitir al usuario seleccionar algo de una lista de opciones mutuamente excluyentes. "radio buttons"). GTK_SIGNAL_FUNC(close_application). Así se consigue enlazar una cadena de botones. gchar *etiqueta ). . GtkWidget *caja2. de modo que sólo uno puede estar seleccionado. GSList *group.&argv). GtkWidget *caja1. gtk_init(&argc. 0). Las llamadas para crear un botón circular son: GtkWidget *gtk_radio_button_new( GSList *group ). GdkEvent *event. A continuación de ésta se puede crear el grupo usando: GSList *gtk_radio_button_group( GtkRadioButton *radio_button ). El nuevo argumento sirve para especificar el grupo al que pertenecen.GtkWidget *gtk_check_button_new_with_label ( gchar *etiqueta ). gtk_container_border_width (GTK_CONTAINER (ventana). La función new_with_label crea un botón de comprobación con una etiqueta dentro. Para añadir un nuevo botón a un grupo hay que usar gtk_radio_button_group con el anterior botón como argumento. "delete_event". El siguiente ejemplo crea un grupo de tres botones: /* Principio del ejemplo radiobuttons.char *argv[]) { static GtkWidget *ventana = NULL. La primera llamada debe pasar NULL como primer argumento.h> #include <glib. GtkWidget *gtk_radio_button_new_with_label( GSList *group. gtk_signal_connect (GTK_OBJECT (ventana). El proceso para comprobar el estado de un botón de este tipo es igual al de los de comprobación. El resultado se le pasa a gtk_radio_button_new o a gtk_radio_button_new_with_label. 6.c */ #include <gtk/gtk.h> void close_application( GtkWidget *widget. (El ejemplo siguiente sirve para aclarar el proceso) También se puede establecer cúal es el botón pulsado por defecto: void gtk_toggle_button_set_state( GtkToggleButton *toggle_button.

10). gtk_box_pack_start (GTK_BOX (caja1). 10). TRUE. 0). caja2. "botón3"). caja2 = gtk_vbox_new (FALSE. . TRUE. gtk_widget_show (boton). 0). para que así cuando se ajuste uno. TRUE. boton. gtk_widget_grab_default (boton). separator = gtk_hseparator_new (). group = gtk_radio_button_group (GTK_RADIO_BUTTON (boton)). boton = gtk_radio_button_new_with_label(group. 0). y bien pasar el nuevo valor al manejador de señal o bien obligarle a que mire dentro de la estructura de datos del widget para conocer este valor. GTK_WIDGET_SET_FLAGS (boton. Ajustes (Adjustment) Existen diferentes widgets en GTK+ que pueden ser ajustados visualmente por el usuario mediante el ratón o el teclado. TRUE. gtk_box_pack_start (GTK_BOX (caja2). Pero también puede ser que quiera conectar los ajustes de varios widgets. gtk_container_add (GTK_CONTAINER (ventana). gtk_box_pack_start (GTK_BOX (caja1). gtk_widget_show (ventana). TRUE.caja1 = gtk_vbox_new (FALSE. "botón2"). Un ejemplo son los widgets de selección descritos en la sección Widgets de selección de rango. return(0). gtk_widget_show (caja2). TRUE. gtk_widget_show (caja1). gtk_widget_show (caja2). GTK_SIGNAL_FUNC(close_application). GTK_OBJECT (ventana)). gtk_box_pack_start (GTK_BOX (caja2). gtk_widget_show (separator). } /* final del ejemplo */ 7. FALSE. gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (boton). Si cada widget posee su propia forma de establecer u obtener sus valores de ajuste el programador puede que tenga que escribir sus propios controladores de señales para traducir el resultado de la señal producida por un widget como el argumento de una función usada para determinar valores en otro widget. boton. gtk_box_pack_start (GTK_BOX (caja1). Como es lógico el programa tiene que poder reaccionar a los cambios que el usuario realiza en los widgets de selección de rango. group = gtk_radio_button_group (GTK_RADIO_BUTTON (boton)). boton = gtk_button_new_with_label ("close"). gtk_container_border_width (GTK_CONTAINER (caja2). TRUE. FALSE. 10). 10). TRUE. caja1). TRUE. GTK_CAN_DEFAULT). gtk_signal_connect_object (GTK_OBJECT (boton). los demás se ajusten automáticamente. por ejemplo el widget de texto o el viewport. 0). gtk_box_pack_start (GTK_BOX (caja2). gtk_box_pack_start (GTK_BOX (caja2). 0). separator. boton. gtk_main(). boton. TRUE. TRUE. "botón1"). 0). caja2 = gtk_vbox_new (FALSE. 0). El ejemplo más obvio es conectar una barra de desplazamiento a una región con texto. Una forma de hacer que el programa reaccione sería tener cada widget emitiendo su propio tipo de señal cuando cambie el ajuste. También hay otros widgets que pueden ser ajustados parcialmente. gtk_widget_show (boton). TRUE. 0). gtk_container_border_width (GTK_CONTAINER (caja2). gtk_widget_show (boton). caja2. boton = gtk_radio_button_new_with_label (NULL. boton = gtk_radio_button_new_with_label(group. gtk_widget_show (boton). TRUE). "clicked".

NULL). gfloat lower. la lista compuesta o la ventana con barra deslizante. barras de estado. pero los resultados son.Para resolver este problema GTK+ usa objetos del tipo GtkAdjustment. mientras que page_increment es el mayor. mientras que las barras deslizantes sólo modifican value. El argumento lower especifica los valores más pequeños que el ajuste puede contener. Para aclarar esto y otras cosas vamos a estudiar la estructura del ajuste struct _GtkAdjustment { GtkData data. . gfloat step_increment. Por defecto sólo se modificará el value (valor) de un ajuste. El otro grupo incluye los widgets de texto. Como los GtkAdjustment derivan de GtkObject poseen cualidades intrínsecas que les permiten ser algo más que simples estructuras de datos. Normalmente estos widgets son ajustados «directamente» por el usuario. Estos widgets usan valores en pixels para sus ajustes.2 Forma sencilla de usar los ajustes Los widgets ajustábles se pueden dividir en dos categorias diferentes.1 Creando un ajuste Los ajustes se pueden crear usando: GtkObject *gtk_adjustment_new( gfloat value. Con ellos se consigue almacenar y traspasar información de una forma abstracta y flexible. escalas. Ahora queda completamente demostrada la utilidad de los ajustes. 7.3 Descripción detallada de los ajustes Puede que se esté preguntando cómo es posible crear sus propios controladores para responder a las modificaciones producidas por el usuario y cómo obtener el valor del ajuste hecho por este. excepto value. gfloat page_size ). Con page_size se determina el valor visible de un widget. A su vez con step_increment se especifica el valor más pequeño en el que se puede variar la magnitud en cuestión (valor de paso asociado). insisten en establecer todos los valores excepto value. y normalmente son ajustados «indirectamente» mediante barras deslizantes. Veamos un ejemplo: /* creamos un ajuste */ text = gtk_text_new (NULL. o botones giratorios). si se comparte un objeto de ajuste entre una barra deslizante y un widget de texto al manipular la barra se modificará el widget de texto. Probablemente ya se habrá dado cuenta de que como los widgets de texto (y todos los widgets del segundo grupo). gfloat upper. Normalmente no tendrán en cuenta ninguno de los valores de un ajuste proporcionado por el programador. 7. indefinidos (entiendase que tendrá que leer el código fuente para saber que pasa con cada widget). aquellos que necesitan saber las unidades de la cantidad almacenada y los que no. Este último grupo incluye los widgets de tamaño (barras deslizantes. El argumento value es el valor inicial que le queremos dar al ajuste. Los argumentos lower y upper serán los limites dentro de los cuales el usuario puede manipular los ajustes. 7. en general. Lo más importante es que pueden emitir señales que a su vez pueden ser usadas tanto para reaccionar frente al cambio de datos introducidos por el usuario como para transferir los nuevos valores de forma transparente entre widgets ajustables. /* lo usamos con la barra deslizante */ vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj). Normalmente se corresponde con las posiciones situadas más arriba y a la izquierda de un widget ajustable. Aunque todos los widgets pueden crear sus propios ajustes o usar otros creados por el programador con el segundo grupo suele ser conveniente dejarles que creen sus propios ajustes. gfloat page_increment. El uso más obvio es el de almacenes de párametros para widgets de escala (barras deslizantes y escalas).

Tal y como se mencionó antes GtkAdjustment es una subclase de GtkObject y por tanto puede emitir señales. page_increment. Cuando se establece el value de un ajuste normalmente se quiere que cualquier widget se entere del cambio producido. Por tanto todos los widgets ajustables deben conectar controladores de señales a sus señales del tipo value_changed.gfloat gfloat gfloat gfloat gfloat gfloat }. Los widgets de tamaño normalmente conectan un controlador a esta señal. Todos los widgets que usan GtkAdjustment deben emitir esta señal cuando cambie el valor de algún ajuste. Los widgets de selección de rango Este tipo de widgets incluye a las barras de desplazamiento (scroollbar) y la menos conocida escala (scale). GtkWidget *picture) { set_picture_rotation (picture. pero como sus funciones y su implementación son muy parecidas los describimos al mismo tiempo. Pero si cambia directamente alguno de los valores de GtkAdjustment debe hacer que se emita la siguiente señal para reconfigurar todos aquellos widgets que usen ese ajuste: gtk_signal_emit_by_name (GTK_OBJECT (adjustment). step_increment. . ¿Qué pasa cuando un widget reconfigura los valores upper o lower (por ejemplo cuando se añade más texto)? Simplemente que se emite la señal changed. GTK_SIGNAL_FUNC (cb_rotate_picture). "value_changed". que debe ser parecida a: void (* changed) (GtkAdjustment *adjustment). Tampoco se preocupe mucho porque la macro GTK_ADJUSTMENT (Object) comprueba los tipos durante el proceso de ejecución (como hacen todas las macros de GTK+ que sirven para comprobar los tipos). Para ello GTK+ posee una función especial: void gtk_adjustment_set_value( GtkAdjustment *adjustment. upper. value. y conectarla con el ajuste del widget de escala mediante: gtk_signal_connect (GTK_OBJECT (adj). 8. Esto sucede cuando el usuario cambia algo o el programa modifica los ajustes mediante. Así se consigue que se actualicen los valores de los ajustes cuando se comparten entre varios widgets. lower.. adj->value). Ambos pueden ser usados para muchas cosas. Probablemente nunca tenga que conectar un controlador a esta señal a no ser que esté escribiendo un nuevo tipo de widget. por lo que tendrá que hacerlo usted mismo. Lo primero que hay que aclarar es que no hay ninguna macro o función de acceso que permita obtener el value de un GtkAdjustment. gfloat value ). picture). .. Por ejemplo el tamaño de la guía en una barra deslizante que se alarga o encoge según la inversa de la diferencia de los valores lower y upper. page_size. Principalmente se utilizan para permitirle al usuario escoger un valor dentro de un rango ya prefijado. Por ejemplo si queremos que rote una figura cuando modificamos un widget de escala habría que usar una respuesta como esta: void cb_rotate_picture (GtkAdjustment *adj. Esta es la definición de la señal como viene en struct _GtkAdjustmentClass void (* value_changed) (GtkAdjustment *adjustment). que cambia el aspecto de éste para reflejar el cambio. "changed").

El ajuste (adjustment) puede ser tanto un ajuste creado mediante gtk_adjustment_new() como NULL. Puede crear estos widgets utilizar las funciones siguientes.h>. Por ejemplo el widget GtkColorSelection contiene widgets de escala que controlan las componentes del color a seleccionar. Normalmente el valor preciso es menos importante que el efecto visual. . Funciones y señales Los widgets de escala pueden indicar su valor actual como un número. Para el resto de los casos. Todos contienen una guía y un rectángulo para determinar la posición dentro de la guía (en una procesador de textos con entorno gráfico se encuentra situado a la derecha del texto y sirve para situarnos en las diferentes partes del texto). en cuyo caso se creará uno. este se mueve hacia donde hemos hecho el click. ya son más sencillos de usar y más potentes. El usuario probablemente fijará el valor a ojo.h> y <gtk/gtkvscrollbar. definidas en <gtk/gtkhscrollbar. Es útil especificar NULL si quiere pasar el ajuste recién creado a la función constructora de algún otro widget (como por ejemplo el widget texto) que se ocupará de configurarlo correctamente por usted. Con el ratón podemos subir o bajar el rectángulo.2 Widgets de escala Los widgets de escala se usan para determinar el valor de una cantidad que se puede interpretar visualmente. o puede ser NULL.0. Cuando el usuario manipula la barra de desplazamiento el widget cambiará el valor del ajuste. ¡mire los ficheros de cabecera!). gint draw_value ). En este último caso se crea un GtkAdjustment anónimo con todos sus valores iguales a 0. Realmente no hay mucho que añadir. mientras que si hacemos `click' dentro de la guía. pero no sobre el rectángulo. Hay dos tipos separados de barras de desplazamiento. Si no ha quedado claro el uso de esta función consulte la sección Ajustes para una discusión más detallada. o un puerto de visión (y en muchos es más fácil utilizar el widget scrolled window). Como funcionan de la misma manera los vamos a describir a la vez. una caja de texto. por lo que el color se selecciona con el ratón y no mediante un número concreto. como una lista. crean widgets de escala verticales y horizontales respectivamente. Las funciones definidas en <gtk/gtkvscale. El argumento adjustment puede ser un puntero a un ajuste ya existente. GtkWidget* gtk_vscale_new( GtkAdjustment *adjustment ).Todos los widgets de selección comparten elementos gráficos. cada uno de los cuales tiene su propia ventana X window y recibe eventos. según sea horizontal o vertical.h> y <gtk/gtkhscale. Tal y como se mencionó en Ajustes todos los widgets usados para seleccionar un rango estan asociados con un objeto de ajuste. debería utilizar los widgets de escala. 8. pero se puede modificar usando: void gtk_scale_set_draw_value( GtkScale *scale. y esto es todo lo que hay (si no me cree. GtkWidget* gtk_vscrollbar_new( GtkAdjustment *adjustment ). Su comportamiento por defecto es mostrar este valor. Dependiendo del botón pulsado el rectángulo se moverá hasta la posición del click o una cantidad prefijada de ante mano. 8. GtkWidget* gtk_hscale_new( GtkAdjustment *adjustment ).1 El widget barra de desplazamiento El widget barra de desplazamiento solamente debe utilizarse para hacer scroll sobre otro widget. Creación de un widget de escala Existen dos tipos de widgets de escala: GtkHScale (que es horizontal) y GtkVscale (vertical). a partir del cual calculan la longitud de la barra y su posición.h>: GtkWidget* gtk_hscrollbar_new( GtkAdjustment *adjustment ).

Para un usuario normal las funciones interesantes son aquellas definidas en: <gtk/gtkrange.h> y funcionan igual en todos los widgets de rango. Las actualizaciones definidas en <gtk/gtkenums.Este es el valor por defecto.Los valores posibles de draw_value son son TRUE o FALSE. Estableciendo cada cúanto se actualizan La política de actualización de un widget define en que puntos de la interacción con el usuario debe cambiar el valor value en su GtkAdjustment y emitir la señal «value_changed». .h>. 8.3 Funciones comunes La descripción interna de la clase GtkRange es bastante complicada. Casi todas las señales y funciones sólo son útiles para desarrollar derivados. GTK_UPDATE_POLICY_DELAYED . El valor mostrado por un widget de escala por defecto se redondea a un valor decimal (igual que con value en un GtkAdjustment). Para establecer la política de actualización se usa la conversión definida en la macro void gtk_range_set_update_policy( GtkRange GtkUpdateType policy) .La señal «value_changed» sólo se emite cuando se ha parado de mover la barra y el usuario ha soltado el botón del ratón. el valor se puede dibujar en diferentes posiciones con respecto a la posición del rectangulo que hay dentro de la guía: void gtk_scale_set_value_pos( GtkScale GtkPositionType pos ). *range.h> como enum GtkPositionType y son auto explicatorios. por ejemplo cuando la barra deslizante se mueve incluso aunque sea un poquito. GtkAdjustment *adjustment ). Si se escoge un lateral de la guía. GTK_UPDATE_POLICY_DISCONTINUOUS . void gtk_range_set_adjustment( GtkRange *range. pero al igual que con el resto de las «clases base» sólo es interesante si se quiere «hackear». En la práctica sólo se mostrarán 13 como máximo. entonces seguirá al rectángulo a lo largo de la guía. son: • • • GTK_UPDATE_POLICY_CONTINUOUS .h> como enum GtkUpdateType. Todas las funcioenes precedentes se encuentran definidas en: <gtk/gtkscale. Obteniendo y estableciendo Ajustes Para obtener o establecer el ajuste de un widget de rango se usa: GtkAdjustment* gtk_range_get_adjustment( GtkRange *range ). Por último. Con el primero se muestra el valor y con el segundo no. Se puede cambiar con: void gtk_scale_set_digits( GtkScale *scale.La señal «value_changed» se emite continuamente. *scale. gint digits ). Estan definidos en <gtk/gtkscale.La señal sólo se emite cuando el usuario suelta el botón del ratón o si la barra no se mueve durante un periodo largo de tiempo. donde digits es el número de posiciones decimales que se quiera. Si ha leido la sección acerca del widget libro de notas entonces ya conoce cuales son los valores posibles de pos.

Av Pág. 8. Simplemente dibuja una ventana con tres widgets de rango conectados al mismo ajuste. También son diferentes para los widgets de escala y para las barras deslizantes. ya que ambas actúan sobre la misma área) Widgets de rango vertical Todos los widgets de rango pueden ser manipulados con las teclas arriba. A su vez Inicio y Final sirven para pasar de un extremo al otro de la guía.5 Ejemplo Este ejemplo es una versión modificada del test «range controls» que a su vez forma parte de testgtk. mientras que para el widget GtkHScrollbar se consigue con Control-Inicio y Control-Final. /* principio del ejemplo widgets de selección de rango rangewidgets.La función gtk_range_get_adjustment() devuelve un puntero al ajuste al que range esté conectado. mientras que Re Pág y Av Pag lo hacen según page_increment. GTK_CAN_FOCUS). Acostumbrarse a que tanto las barras deslizantes como los widgets de escala puedan tomar la atención del teclado puede ser un proceso largo. La función gtk_range_set_adjustment() no hace nada si se le pasa como argumento el valor range del ajuste que esta siendo usado (aunque se haya modificado algún valor). A continuación llamará a la función gtk_range_adjustment_changed() que en teoría recalculará el tamaño y/o la posición de la barra. Con el widget GtkVScale podemos ir a los extremos utilizando las teclas Inicio y Final mientras que con el widget GtkVScrollbar habrá que utilizar Control-Re Pág y Control-Av Pág. Tal y como se mencionó en la sección de los ajustes si se quiere reusar el mismo GtkAdjustment cuando se modifican sus valores se debe emitir la señal «changed». Con cada pulsación de cualquier botón sobre las flechas el valor del ajuste se modifica una cantidad igual a step_increment. Para el widget GtkHScale el mover la barra una cantidad dada por page_increment se consigue mediante Control-Izquierda y Control-derecha. "changed"). En el caso de que sea un ajuste nuevo (GtkAdjustment) dejará de usar el antiguo (probablemente lo destruirá) y conectará las señales apropiadas al nuevo. abajo. Si que se cree que los usuarios no lo van a entender se puede anular mediante la función GTK_WIDGET_UNSET_FLAGS y con GTK_CAN_FOCUS como argumento: GTK_WIDGET_UNSET_FLAGS (scrollbar.4 Enlaces con el teclado y el ratón Todos los widgets de rango reaccionan más o menos de la misma manera a las pulsaciones del ratón. *vscale. Re Pág. El usuario también puede mover la barra de un extremo al otro de la guía mediante el teclado. Los enlaces entre teclas (que sólo estan activos cuando el widget tiene la atención (focus)) se comportan de manera diferente para los widgets de rango horizontales que para los verticales. 8. Por ejemplo: gtk_signal_emit_by_name (GTK_OBJECT (adjustment). Las flechas mueven las barras la cantidad fijada mediante step_increment. Al pulsar el botón 1 sobre el rectángulo de la barra el value del ajuste aumentará o disminuirá según page_increment. Widgets de rango horizontal Las teclas izquierda y derecha funcionan tal y como espera que funcionen en estos widgets: mueven la barra una cantidad dada por step_increment. (Simplemente para evitar confusiones entre las teclas de las barras deslizantes horizontales y verticales.h> GtkWidget *hscale. . redibujándola en caso de que sea necesario.c */ #include <gtk/gtk.c. Así se consigue ver como funcionan estos widgets al ser manipulados por el usuario. Con el botón 2 la barra se desplazará al punto en el que el botón fue pulsado. y un conjunto de controles para ajustar algunos de los parámetros ya mencionados.

. boton->active). } void cb_draw_value( GtkToggleButton *boton ) { /* Activa o desactiva el valor display en los widgets de escala * dependiendo del estado del botón de comprobación */ gtk_scale_set_draw_value (GTK_SCALE (hscale). "activate". gpointer data ) { GtkWidget *item. (gint) adj->value). policy). GtkPositionType pos ) { /* Establece el valor position en los widgets de escala */ gtk_scale_set_value_pos (GTK_SCALE (hscale). gtk_scale_set_value_pos (GTK_SCALE (vscale). /* Ahora emite la señal "changed" para reconfigurar todos los * widgets que están enlazados a este ajuste */ gtk_signal_emit_by_name (GTK_OBJECT (set).void cb_pos_menu_select( GtkWidget *item. gtk_scale_set_digits (scale. GtkUpdateType policy ) { /* Establece la política de actualización para los widgets * de escala */ gtk_range_set_update_policy (GTK_RANGE (hscale). policy). GTK_UPDATE_CONTINUOUS). data). "changed"). } void cb_page_size( GtkAdjustment *get. gtk_scale_set_draw_value (GTK_SCALE (vscale). } /* Funciones varias */ GtkWidget *make_menu_item( gchar *name. set->page_increment = get->value. callback. pos). 1). gtk_scale_set_digits (GTK_SCALE (vscale). item = gtk_menu_item_new_with_label (name). (gint) adj->value). } void scale_set_default_values( GtkScale *scale ) { gtk_range_set_update_policy (GTK_RANGE (scale). } void cb_update_menu_select( GtkWidget *item. pos). gtk_widget_show (item). return(item). GtkSignalFunc callback. GtkAdjustment *set ) { /* Establece el tamaño de la página y el incremento del * ajuste al valor especificado en la escala "Page Size" */ set->page_size = get->value. } void cb_digits_scale( GtkAdjustment *adj ) { /* Establece el número de cifras decimales a las que se * redondeará adj->value */ gtk_scale_set_digits (GTK_SCALE (hscale). gtk_range_set_update_policy (GTK_RANGE (vscale). boton->active). gtk_signal_connect (GTK_OBJECT (item).

page_size */ /* Observe que el valor de page_size solo sirve para los widgets * barras de desplazamiento (scrollbar). 10).1. gtk_widget_show (hscale). 0. 101. step_increment. 200. TRUE. caja3. gtk_container_add (GTK_CONTAINER (ventana).page_size). 1. GTK_POS_TOP). gtk_widget_set_usize (GTK_WIDGET (hscale). GtkWidget *opt. gtk_box_pack_start (GTK_BOX (caja3). *caja2. 30). "destroy". 0). 0). 0). gtk_scale_set_draw_value (scale. scrollbar. GTK_SIGNAL_FUNC(gtk_main_quit).0). TRUE. gtk_widget_show (caja1).gtk_scale_set_value_pos (scale. lower. *menu. */ adj1 = gtk_adjustment_new (0. 0). TRUE. 10). /* Reutilizamos el mismo ajuste */ hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1)). scale_set_default_values (GTK_SCALE (vscale)). y que el valor más * alto que obtendrá será (upper . gtk_box_pack_start (GTK_BOX (caja1). upper.0.0. GTK_UPDATE_CONTINUOUS). *caja3. *item. GtkWidget *caja1. } /* crea la ventana principal */ void create_range_controls( void ) { GtkWidget *ventana. 0. TRUE. TRUE. GtkWidget *etiqueta. TRUE. TRUE. /* Reutilizamos de nuevo el mismo ajuste */ scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1)). /* value. gtk_container_border_width (GTK_CONTAINER (caja2). *adj2. GtkObject *adj1. gtk_window_set_title (GTK_WINDOW (ventana). NULL). 1. gtk_widget_show (caja2). 0). caja2. TRUE. gtk_box_pack_start (GTK_BOX (caja3). "range controls"). gtk_widget_show (scrollbar). GtkWidget *separator. caja1). 0). scale_set_default_values (GTK_SCALE (hscale)). caja3 = gtk_vbox_new (FALSE. vscale. gtk_widget_show (caja3). gtk_widget_show (vscale).0. 10). hscale. GtkWidget *scale. GtkWidget *boton. /* creación estándar de una ventana */ ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL). vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1)). GtkWidget *scrollbar. gtk_box_pack_start (GTK_BOX (caja2). caja2 = gtk_hbox_new (FALSE. caja1 = gtk_vbox_new (FALSE. TRUE). TRUE. gtk_signal_connect (GTK_OBJECT (ventana). gtk_box_pack_start (GTK_BOX (caja2).0. page_increment. /* Observe que con esto conseguimos que la escala siempre se * actualice de una forma continua cuando se mueva la barra de * desplazamiento */ gtk_range_set_update_policy (GTK_RANGE (scrollbar). . TRUE.

gtk_container_border_width (GTK_CONTAINER (caja2). menu = gtk_menu_new(). item = make_menu_item ("Right". gtk_menu_append (GTK_MENU (menu). GTK_SIGNAL_FUNC (cb_pos_menu_select). /* Un botón para comprobar si el valor se muestra o no*/ boton = gtk_check_button_new_with_label("Display value on scale widgets"). gtk_menu_append (GTK_MENU (menu). gtk_container_border_width (GTK_CONTAINER (caja2). gtk_widget_show (caja2). 0). FALSE. item). gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (boton). "toggled". gtk_box_pack_start (GTK_BOX (caja1). . 10). item = make_menu_item ("Top". TRUE. FALSE. 10). gtk_box_pack_start (GTK_BOX (caja2). TRUE. gtk_menu_append (GTK_MENU (menu). TRUE. item). item = make_menu_item ("Left". gtk_widget_show (boton). /* Sí. gtk_widget_show (etiqueta). GINT_TO_POINTER (GTK_POS_BOTTOM)). 10). gtk_signal_connect (GTK_OBJECT (boton). TRUE). 10). GTK_SIGNAL_FUNC (cb_pos_menu_select). gtk_box_pack_start (GTK_BOX (caja2). etiqueta. GTK_SIGNAL_FUNC (cb_update_menu_select). 10). opt = gtk_option_menu_new(). menu = gtk_menu_new(). etiqueta. GTK_SIGNAL_FUNC (cb_pos_menu_select). gtk_widget_show (etiqueta). gtk_box_pack_start (GTK_BOX (caja2). opt = gtk_option_menu_new(). 0).caja2 = gtk_hbox_new (FALSE. gtk_widget_show (opt). TRUE. item). GTK_SIGNAL_FUNC(cb_draw_value). gtk_menu_append (GTK_MENU (menu). gtk_menu_append (GTK_MENU (menu). GINT_TO_POINTER (GTK_POS_RIGHT)). TRUE. item). boton. TRUE. item = make_menu_item ("Continuous". 0). /* Una opción en el menú para cambiar la posición del * valor */ etiqueta = gtk_label_new ("Scale Value Position:"). FALSE. caja2 = gtk_hbox_new (FALSE. 0). TRUE. gtk_container_border_width (GTK_CONTAINER (caja2). 0). NULL). item). esta vez para la política * de actualización de los widgets */ etiqueta = gtk_label_new ("Scale Update Policy:"). otra opción de menú. gtk_box_pack_start (GTK_BOX (caja1). item = make_menu_item ("Bottom". opt. 10). gtk_widget_show (caja2). 0). caja2 = gtk_hbox_new (FALSE. gtk_box_pack_start (GTK_BOX (caja2). GINT_TO_POINTER (GTK_POS_TOP)). caja2. TRUE. FALSE. menu). GINT_TO_POINTER (GTK_POS_LEFT)). caja2. GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS)). gtk_option_menu_set_menu (GTK_OPTION_MENU (opt). GTK_SIGNAL_FUNC(cb_pos_menu_select).

TRUE. 0). gtk_scale_set_digits (GTK_SCALE (scale). /* Y un último widget GtkHScale para ajustar el tamaño de la * página de la barra de desplazamiento. gtk_box_pack_start (GTK_BOX (caja1). gtk_signal_connect (GTK_OBJECT (adj2). separator = gtk_hseparator_new (). TRUE. adj1). scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2)). gtk_container_border_width (GTK_CONTAINER (caja2). 0). menu). FALSE. caja2. adj2 = gtk_adjustment_new (1. etiqueta. gtk_container_border_width (GTK_CONTAINER (caja2). scale. 10). 0). GINT_TO_POINTER (GTK_UPDATE_DELAYED)). caja2. */ etiqueta = gtk_label_new ("Scrollbar Page Size:").0. 1. item). 0). 1. gtk_box_pack_start (GTK_BOX (caja2). gtk_signal_connect (GTK_OBJECT (adj2). TRUE. FALSE. 0).0. FALSE. TRUE. gtk_box_pack_start (GTK_BOX (caja2). gtk_widget_show (caja2). 1. gtk_scale_set_digits (GTK_SCALE (scale). gtk_container_border_width (GTK_CONTAINER (caja2). gtk_menu_append (GTK_MENU (menu).0). gtk_box_pack_start (GTK_BOX (caja2). FALSE. TRUE. GTK_SIGNAL_FUNC (cb_page_size). caja2 = gtk_hbox_new (FALSE. 101. 10). etiqueta. gtk_box_pack_start (GTK_BOX (caja2).0. 0). gtk_box_pack_start (GTK_BOX (caja2). opt. separator.0. gtk_widget_show (scale). TRUE. TRUE. gtk_widget_show (separator). 10). GTK_SIGNAL_FUNC (cb_update_menu_select).0. gtk_widget_show (etiqueta).0). scale. GTK_SIGNAL_FUNC (cb_update_menu_select). 0. TRUE. gtk_menu_append (GTK_MENU (menu).item = make_menu_item ("Discontinuous". 0). 5. gtk_widget_show (opt). gtk_widget_show (scale). caja2. "value_changed". TRUE. caja2 = gtk_hbox_new (FALSE. 0). gtk_option_menu_set_menu (GTK_OPTION_MENU (opt). gtk_box_pack_start (GTK_BOX (caja1). TRUE. TRUE. gtk_widget_show (etiqueta). FALSE. gtk_box_pack_start (GTK_BOX (caja1). GTK_SIGNAL_FUNC (cb_digits_scale). 0).0. 10). gtk_widget_show (caja2).0. 1. NULL). scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2)).0. gtk_widget_show (caja2). caja2. item = make_menu_item ("Delayed". /* Un widget GtkHScale para ajustar el número de dígitos en * la escala. TRUE. 10). 0). adj2 = gtk_adjustment_new (1. */ etiqueta = gtk_label_new ("Scale Digits:"). TRUE. gtk_box_pack_start (GTK_BOX (caja1). 0.0. . 0). item). TRUE. 0.0. 10). "value_changed". GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS)). gtk_box_pack_start (GTK_BOX (caja1). 1. caja2 = gtk_vbox_new (FALSE. FALSE. 0). gtk_widget_show (caja2).

Para crear una nueva etiqueta se usa: GtkWidget *gtk_label_new( char *str ). El texto de la etiqueta se puede justificar utilizando: . Con esto seguimos realizando la función deseada. boton. ya que se utiliza internamente por GTK. NULL). mientras que el segundo es el valor devuelto para la cadena. Widgets varios 9.1 Etiquetas Las etiquetas se usan mucho en GTK y son bastante simples de manejar. ya que un «delete_event» no manejado desenboca en una señal «destroy» para la ventana. &argv). Para cambiarla después de que haya sido creada se usa: void gtk_label_set( GtkLabel *etiqueta. 9. GTK_SIGNAL_FUNC(gtk_main_quit). No pueden emitir señales ya que no tienen ventanas X window asociadas. Si se desea capturar señales se debe usar el widget EventBox o un widget botón. return(0). TRUE. En este caso el primer argumento es la etiqueta ya creada (cambiado su tipo mediante la macro GTK_LABEL()) y el segundo es la nueva cadena. gtk_box_pack_start (GTK_BOX (caja2). "clicked". y que sólo conecta la señal «destroy». si es necesario. gtk_signal_connect_object (GTK_OBJECT (boton). GTK_WIDGET_SET_FLAGS (boton. TRUE. Para obtener el estado de la cadena en un momento dado existe la función: void gtk_label_get( GtkLabel *etiqueta. gtk_widget_show (boton). No libere la memoria de la cadena devuelta. gtk_main(). create_range_controls(). char *argv[] ) { gtk_init(&argc. GTK_CAN_DEFAULT). char **str ). El primer argumento es la etiqueta. char *str ). El espacio que necesite la nueva etiqueta se ajustará automáticamente. } /* fin del ejemplo */ Observe que el programa no llama a gtk_signal_connect para conectar el «delete_event». El único argumento es la cadena de texto que se quiere mostrar. } int main( int argc. gtk_widget_show (ventana). 0). gtk_widget_grab_default (boton).boton = gtk_button_new_with_label ("Quit").

puede especificar un motivo para el subrayado con: void gtk_label_set_pattern (GtkLabel *etiqueta. /* Inicializa GTK */ gtk_init(&argc. Por ahora puede ignorarlo. Este ejemplo utiliza el widget marco (frame) para hacer una mejor demostración de los estilos de la etiqueta. Los valores posibles para jtype son: • • • • GTK_JUSTIFY_LEFT GTK_JUSTIFY_RIGHT GTK_JUSTIFY_CENTER (the default) GTK_JUSTIFY_FILL El widget etiqueta también es capaz de separar el texto de forma automática cuando se llega al final de una linea. NULL). hbox = gtk_hbox_new (FALSE. 5). ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL). El argumento wrap toma el valor TRUE o FALSE. GTK_SIGNAL_FUNC(gtk_main_quit). char *argv[] ) { static GtkWidget *ventana = NULL. FALSE.void gtk_label_set_justify( GtkLabel *etiqueta. /* principio del ejemplo label label. FALSE. El argumento pattern indica cual debe ser el aspecto del subrayado. vbox. const gchar *pattern). Si quiere que su etiqueta salga subrayada. la cadena "__ __" debe hacer que se subrayen los dos primeros y el octavo y el noveno carácter. GtkJustification jtype ). frame = gtk_frame_new ("Normal Label"). "destroy". GtkWidget *vbox. &argv). gtk_box_pack_start (GTK_BOX (hbox). GtkWidget *frame. . gtk_signal_connect (GTK_OBJECT (ventana). GtkWidget *etiqueta. gboolean wrap). gtk_window_set_title (GTK_WINDOW (ventana). ya que el widget Frame se explicará más tarde. vbox = gtk_vbox_new (FALSE. GtkWidget *hbox. Consiste en una cadena de espacios en blanco y carácteres de subrayado. 5). 0).c */ #include <gtk/gtk. Esto se puede conseguir utilizando: void gtk_label_set_line_wrap (GtkLabel *etiqueta. A continuación tenemos un pequeño ejemplo que ilustra el uso de estas funciones. "Etiqueta"). gtk_container_add (GTK_CONTAINER (ventana). Por ejemplo.h> int main( int argc. gtk_container_set_border_width (GTK_CONTAINER (ventana). 5). hbox).

do de do de do. " \ "and correctly adds "\ "many extra spaces. gtk_label_set_justify (GTK_LABEL (etiqueta). gtk_label_set_line_wrap (GTK_LABEL (etiqueta). frame. FALSE. GTK_JUSTIFY_FILL). frame = gtk_frame_new ("Multi-line Label"). gtk_label_set_justify (GTK_LABEL (etiqueta). etiqueta). gtk_container_add (GTK_CONTAINER (frame). GTK_JUSTIFY_LEFT). "\ "Here comes the sun. . frame. etiqueta = gtk_label_new ("This is an example of a line-wrapped label.\n"\ " This is a new paragraph. gtk_box_pack_start (GTK_BOX (vbox). frame = gtk_frame_new ("Line wrapped label"). frame. "). TRUE). longer. FALSE. etiqueta = gtk_label_new ("This is an example of a line-wrapped. FALSE. GTK_JUSTIFY_LEFT). gtk_container_add (GTK_CONTAINER (frame). gtk_label_set_justify (GTK_LABEL (etiqueta). gtk_container_add (GTK_CONTAINER (frame). gtk_label_set_justify (GTK_LABEL (etiqueta). but automatically " \ "wraps the words to fit. FALSE. FALSE. gtk_label_set_pattern (GTK_LABEL (etiqueta). 0). 0). etiqueta). etiqueta). gtk_box_pack_start (GTK_BOX (vbox). for all good men.\nSecond line\n" \ "Third line"). FALSE. frame = gtk_frame_new ("Filled. Here is another sentence. FALSE. FALSE. gtk_label_set_line_wrap (GTK_LABEL (etiqueta). etiqueta = gtk_label_new ("This is a Right-Justified\nMulti-line label. gtk_container_add (GTK_CONTAINER (frame). FALSE. TRUE). " \ "Here is a seneance to prove "\ "my point. frame. gtk_box_pack_start (GTK_BOX (vbox). gtk_container_add (GTK_CONTAINER (frame). frame = gtk_frame_new ("Underlined label"). 0). etiqueta). etiqueta).\nThird line"). etiqueta = gtk_label_new ("This label is underlined!\n" "This one is underlined in quite a funky fashion"). 0). to come to " \ "the aid of their party. FALSE. FALSE. gtk_box_pack_start (GTK_BOX (vbox). better " \ "paragraph. (j/k)"). FALSE. gtk_container_add (GTK_CONTAINER (frame). wrapped label"). 0). " \ "The time has come. 0). GTK_JUSTIFY_RIGHT). 0). vbox. "_________________________ _ _________ _ ______ __ _______ ___"). gtk_box_pack_start (GTK_BOX (hbox). It " \ "should not be taking up the entire " /* big space to test spacing */\ "width allocated to it. It is coming to an end. gtk_box_pack_start (GTK_BOX (vbox). vbox = gtk_vbox_new (FALSE.").\n" \ "Fourth line. filled label. etiqueta = gtk_label_new ("This is a Multi-line label. 5). frame = gtk_frame_new ("Right Justified Label"). " \ "The sixth sheik's six sheep's sick. gtk_box_pack_start (GTK_BOX (vbox). frame. 0). "\ "unfortunately. " \ "It should be taking "\ "up the entire width allocated to it. frame. etiqueta = gtk_label_new ("This is a Left-Justified\n" \ "Multi-line label. FALSE. FALSE.\n"\ " This is another newer. FALSE. gtk_container_add (GTK_CONTAINER (frame). FALSE. etiqueta). gtk_box_pack_start (GTK_BOX (vbox). frame.\n" \ " It supports multiple paragraphs correctly. etiqueta). frame = gtk_frame_new ("Left Justified Label").etiqueta = gtk_label_new ("This is a Normal label").

}. gtk_widget_show (etiqueta). sólo hay que usar una función: GtkWidget *gtk_dialog_new( void ). return(0). un separador y una hbox llamada «action_area».j. Para crear un nuevo cuadro de diálogo hay que llamar a: GtkWidget *ventana. gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->vbox). etiqueta. una tabla en una vbox). y hay unas cuantas rutinas especiales para controlar este caso particular. TRUE. sólo es una ventana con algunas cosas ya preempaquetadas.6 Pixmaps Los pixmaps son estructuras de datos que contienen dibujos. Simplemente se crea una ventana en la cual se empaqueta una vbox. TRUE. gtk_main (). GtkWidget *vbox. Un bitmap es un pixmap que sólo tiene dos colores.5 Cuadros de diálogo El widget del cuadro de diálogo es bastante simple. Este tipo de widgets pueden ser usados como mensages pop-up (pequeñas ventanas con texto en su interior que aparecen cuando el usuario hace algo y queremos informarle de alguna cosa) y otras cosas parecidas. gtk_widget_show (boton). ventana = gtk_dialog_new (). 0). TRUE.gtk_widget_show_all (ventana). Estos pueden ser usados en diferentes lugares. TRUE. Por ejemplo para empaquetar un botón en la action_area escribiríamos algo así: boton = . pero los iconos y los cursores son los más comunes. 9. Una vez que el cuadro ha sido creado sólo hay que usarlo. 0). Su manejo desde el punto de vista del programador es bastante fácil.. GtkWidget *action_area. Su estructura es la siguiente: struct GtkDialog { GtkWindow ventana. gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->action_area). Si se precisa algo más complejo siempre se puede empaquetar otro widget en cualquiera de las cajas (p.. . boton. Otra cosa que nos puede interesar es empaquetar una etiqueta en la vbox: etiqueta = gtk_label_new ("Dialogs are groovy"). Otros ejemplo posible es poner dos botones en el action_area (uno para cancelar y el otro para permitir algo) junto con una etiqueta en la vbox el usuario puede seleccionar lo que quiera. } /* fin del ejemplo */ 9.

Bajo X-windows. comunican con un programa que muestra los gráficos y que controla el tecledo y el ratón.Para comprender los pixmaps. las aplicaciones no tienen porque estar ejecutándose en el ordenador que está interactuando con el usuario. GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *ventana. " c None". puede ayudar entender como funciona X-windows. "X c #FFFFFFFFFFFF". Se pueden incorporar imágenes pequeñas dentro de un programa en formato XPM. " . es importante mantener alguna información en el servidor X. Veremos con detalle cada una de las dos posibilidades. Como la comunicación entre el servidor y el cliente puede llevarse a cabo mediante una red. Tanto la altura como la anchura estan expresadas en pixels. GdkBitmap **mask. en lugar de leerla de un archivo. Más adelante veremos un ejemplo. ". gchar **data ). ".X. gint depth. gchar *data. GdkBitmap **mask. Los pixmaps se pueden crear usando datos que se encuentren en la memoria o en un archivo. Esto significa que una vez que se establecen los valores del pixmap. gint height. La máscara especifica que bits son opacos. const gchar *filename ). gint width. en su lugar lo único que hay que enviar es una orden del estilo «mostrar pixmap número XYZ aquí». Los pixmaps por ejemplo. llamadas «clientes». El archivo especificado mediante filename debe contener una imagen en ese formato para que sea cargada en la estructura.XXX. gint width. GdkColor *transparent_color. c #000000000000". GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *ventana. ". . al utilizar construcciones como los pixmaps conseguirá que sus programas funciones de forma aceptable bajo X-windows. GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *ventana. Un pixmap se crea usando esta información. " ". gint height ).. Todos los demás bits se colorean usando el color especificado en transparent_color.. gchar *data. Con esto creamos un pixmap con la profundidad (número de colores) especificada en los datos del bitmap. Para usar un pixmap en GTK primero tiene que construir una estructura del tipo GdkPixmap usando rutinas de GDK. se almacenan en la memoria del servidor X. El formato XPM es una representacion de los pixmaps para el sistema X Window.. GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *ventana. no tienen que estar transmitiéndose por la red. El puntero del tipo GdkWindow indica la ventana en cuestión. Esta rutina se utiliza para crear un bitmap a partir de datos almacenados en la memoria. " . Los valores fg y bg son los colores del frente y del fondo respectivamente. GdkColor *bg ). Es bastante popular y existen muchos programas para crear imágenes en este formato. Este programa que interactua directamente con el usuario se llama un «display server» o «servidor X». ya que los pixmaps sólo tienen sentido dentro de la pantalla en la que van a ser mostrados. Incluso si no está utilizando X-windows con GTK. Las distintas aplicaciones.. GdkColor *fg.. GdkColor *transparent_color. Cada bit de información indica si el pixel luce o no. Un ejemplo sería: /* XPM */ static const char * xpm_data[] = { "16 16 3 1".

" . Esto se hace usando: GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap...XXXXXXX.XXXXXXX. . . ".. ".XXXXXXX. " . " .XXX. ". Cuando hayamos acabado de usar un pixmap y no lo vayamos a usar durante un tiempo suele ser conveniente liberar el recurso mediante gdk_pixmap_unref().XXX. ".. "}. ". ".. .XXXXXXX.XXXXXXX. ". El ejemplo siguiente usa un pixmap en un botón: /* comienzo del ejemplo pixmap.XXXXXXX. ".. " . ".XXXXXXX.. Las otras funciones del widget pixmap son: guint gtk_pixmap_get_type( void ).. ".. ".XXXXXXX. . ". . .XXX.. ".XXXXXXX. void gtk_pixmap_set( GtkPixmap *pixmap.. ". ".. La función gtk_pixmap_set se usa para cambiar los datos del pixmap que el widget está manejando en ese momento.c */ #include <gtk/gtk. " ".. ".h> /* Datos en formato XPM del icono de apertura de archivo */ static const char * xpm_data[] = { "16 16 3 1". " . .XXX. . ".. val es el pixmap creado usando GDK.XX. void gtk_pixmap_get( GtkPixmap *pixmap.. . . ". Primero tenemos que crear un widget pixmap que contenga un pixmap GDK. "X c #FFFFFFFFFFFF".XXX. ". ".XX. " . GdkPixmap *val.. GdkBitmap **mask).XXXXXXX. GdkBitmap *mask ). " .XXX. " . Una vez que hemos creado el pixmap lo podemos mostrar como un widget GTK. ".XXX. . ".XXX. ".. ".. " c None". " .XXX." " " " " " " " " " " " " .XXXXXXX.XXXXXXX. GdkBitmap *mask ). " . c #000000000000". (Los pixmaps deben ser considerados recursos preciosos)....X. " .XXXXXXX. GdkPixmap **val.

. GdkPixmap *pixmap. NULL ).. ".XXXXXXX. char *argv[] ) { GtkWidget *ventana.*/ gtk_init( &argc. "clicked". " "}. /* Cuando se llama a esta función (usando signal delete_event) se * termina la aplicación*/ void close_application( GtkWidget *widget. *boton. boton ).. " . pixmapwid ).. gtk_widget_show( pixmapwid ). /* Ahora para el pixmap de gdk */ style = gtk_widget_get_style( ventana ). mask ). 10 ). GdkBitmap *mask. gtk_signal_connect( GTK_OBJECT(boton). GTK_SIGNAL_FUNC (close_application). gtk_widget_show( boton ). *pixmapwid. gpointer data ) { printf( "botón pulsado\n" ).xpm con la información XPM (que se encuentra en en directorio actual) habríamos usado: /* cargar un pixmap desde un fichero */ . gtk_signal_connect( GTK_OBJECT (ventana). } int main( int argc. /* Un pixmap widget que contendrá al pixmap */ pixmapwid = gtk_pixmap_new( pixmap. /* Creamos la ventana principal y relacionamos la señal * delete_event con acabar el programa. return 0. gtk_container_border_width( GTK_CONTAINER (ventana). ". "delete_event". /* Un botón para contener al pixmap */ boton = gtk_button_new(). gtk_widget_show( ventana ). (gchar **)xpm_data ).. gtk_container_add( GTK_CONTAINER(ventana). &style->bg[GTK_STATE_NORMAL]. &mask.. ventana = gtk_window_new( GTK_WINDOW_TOPLEVEL ). NULL ). pixmap = gdk_pixmap_create_from_xpm_d( ventana->window.. &argv ). } /* Al presionar el botón aparece el mensaje */ void button_clicked( GtkWidget *widget.. GtkStyle *style. gtk_container_add( GTK_CONTAINER(boton). " ". GdkEvent *event. gpointer data ) { gtk_main_quit(). } /* final del ejemplo */ Para cargar un archivo llamado icon0. GTK_SIGNAL_FUNC(button_clicked)." . /* mostramos la ventana */ gtk_main ().

/icon0. Este tipo de ventanas son pixmaps en los que el fondo es transparente. "2 c #DF7D4D344103". Así cuando la imagen del fondo tiene muchos colores no los sobreescribimos con el borde de nuestro icono. Si queremos usar imágenes con otras formas debemos usar ventanas con forma (shaped windows). "8 c #492445144924". "r c #71C6451430C2". "a c #A69996589658". "* c #8E3886178E38". mask ). "O c #A699A289A699". "1 c #861720812081". "y c #28A208200820". "4 c #861782078617". "7 c #49241C711040". "@ c #8E38410330C2". "p c #71C661855965". "g c #30C230C230C2". "u c #186110401040". ". "+ c #965892489658". "> c #618561856185". "s c #30C228A230C2". &style->bg[GTK_STATE_NORMAL]. "0 c #69A618611861". . El ejemplo siguiente muestra la imagen de una carretilla en el escritorio. pixmapwid = gtk_pixmap_new( pixmap. "q c #B6DA71C65144". ": c #C71B9A699658". "i c #596528A21861". "% c #96588A288E38". "e c #CF3CBAEAB6DA". "< c #104000000000". ". "f c #596545145144". "t c #EFBEDB6CD75C". ". "= c #104008200820". "# c #D75C7DF769A6". gtk_container_add( GTK_CONTAINER(ventana). "6 c #000000000000". "h c #8E3882078617". ". &mask. /* comienzo del ejemplo carretilla wheelbarrow. "$ c #F7DECF3CC71B". c #C71B30C230C2".c */ #include <gtk/gtk. "& c #A69992489E79". "9 c #082008200820". c #20811C712081". pixmapwid ). "X c #965875D669A6".h> /* XPM */ static char * WheelbarrowFull_xpm[] = { "48 48 64 1". c #DF7DCF3CC71B". "d c #BEFBA289AEBA". gtk_widget_show( pixmapwid ).xpm" ). "5 c #41033CF34103". "o c #71C671C671C6". "3 c #79E769A671C6". "w c #410330C238E3". " c None". Una desventaja de los pixmaps es que la imagen mostrada siempre es rectangular (independientemente de como sea la imagen en sí). "c #596510401040".pixmap = gdk_pixmap_create_from_xpm( ventana->window.

B* ".3DZZZZrCVSA2rZrV7Dmmwxxxx&en". " c1-699Blvlllllu7k96MMMg4 ".xxc:. "Oh$. " +@#$%o& ". " >966666M ". " 4666FF666> ". "Z c #30C218611040".u=Blllj=54 ". "S c #618534D32081".Xe. " *=-. "k c #38E30C300820". " *10y8n6FjvllllB<166668 ".c. "z c #38E328A238E3". " ". "B c #28A2208128A2". " *. " <<M4 466lj<Mxu66o ". "V c #A699596538E3". "n c #28A228A228A2". " . " *>> +66uv. " >.ro ". ". " OXq6c. "D c #38E31C711040". " +89<02qwo ". "ty> 459@>+&& ". "M c #104010401040".."j c #208118612081". "l c #30C2208128A2".e3g54 ". " Oh$.dfg> ".Od.mNwxxxxxxxfa. "%$. "F c #082000000820". " p71=4 m69996kD8Z-66698&& ". "e* >. " 45671#:X3 ".66. . " @26MvzxNzvlbwfpdettttttttttt. "c c #618555555965".kO *pd$%svbzz.Xa. " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ". " 3206Bwxxszx%et.ka *3d$a8lz. " *#16jszN. "C c #30C21C711040".67. " oM6668+ ". " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ". "N c #492438E34103". " *kk5 >66By7=xu664 ".n& ". " OS0y6FBlvvvzvzss. " p.0<6666g ".. " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ".q-6MN. " 566.:.a8j. "b c #38E328A230C2".%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ". " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>". " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g".sxxxxfX. " N-k-<> >=01-kuu666> ".=* *3:.zN666* ".xxj669 ". "m c #41032CB228A2".16=lsNwwNwgsvslbwwvccc3pcfu<o ". " :. " Oh$. " Oh$@. "x c #514438E34924".B ". " &i0ycm6n4 ogk17. " . " Oh$@g& *3d$XNlvvvlllm. " S-kg+>666<M<996-y6n<8* ".d3g8+ ". "A c #965865955965".. "v c #30C2208130C2".eaAp77m77mmmf3&eeeg* ". "$2u+ ><ipas8* ".dfmZZrrSS:#riirDSAX@Af5xxxxxfevo".<69BvwwsszslllbBlllllllu<5+ ". " *4 ".XoO ". " Ou0<> o66y<ulw<66& ".#::o+ ".ya *3d.&wn> ".6ky& &46-10ul.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ". " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.<12#:34 ".

return 0. "delete_event". 9. /* Con esto cubrimos todo menos la imagen */ gtk_widget_shape_combine_mask( ventana. /* Creamos la ventana principal y relacionamos la señal * delete_event para terminar la aplicación. gc = style->black_gc. GdkEvent *event. GTK_SIGNAL_FUNC(close_application). fixed = gtk_fixed_new(). /* mostramos la ventana */ gtk_widget_set_uposition( ventana. gtk_signal_connect( GTK_OBJECT(ventana). mask ). gtk_fixed_put( GTK_FIXED(fixed). &argv). gtk_main (). *fixed. GdkPixmap *gdk_pixmap. style = gtk_widget_get_default_style(). GdkGC *gc. 20.*/ gtk_init (&argc. GtkStyle *style. 0. &style->bg[GTK_STATE_NORMAL]. gtk_widget_show (ventana). pixmap. Con las líneas siguientes la pulsación del botón hace que se acabe el programa. Conviene destacar * que la ventana no tendrá título puesto que es popup. GdkBitmap *mask.9 Entrada de texto . gpointer data ) { gtk_main_quit(). pixmap = gtk_pixmap_new( gdk_pixmap. } /* final del ejemplo */ Para que la carretilla sea más realista podríamos relacionar la pulsación del botón con que haga algo. 0. gtk_widget_show( ventana ). 0 ). *pixmap. "button_press_event". mask. gdk_pixmap = gdk_pixmap_create_from_xpm_d( ventana->window. GTK_SIGNAL_FUNC (close_application). } int main (int argc. char *argv[]) { GtkWidget *ventana. gtk_container_add( GTK_CONTAINER(ventana). 400 )." " ". NULL ). ventana = gtk_window_new( GTK_WINDOW_POPUP ). 200 ). 0 ). gtk_signal_connect (GTK_OBJECT (ventana). WheelbarrowFull_xpm ). gtk_widget_set_usize( fixed. gtk_widget_show( pixmap ). "}. void close_application( GtkWidget *widget. gtk_widget_set_events( ventana. NULL). gtk_widget_show( fixed ). gtk_widget_get_events( ventana ) | GDK_BUTTON_PRESS_MASK ). fixed ). &mask. 200.

Las función siguientes permiten decir donde poner el punto de inserción. const gchar *text ). void gtk_entry_append_text( GtkEntry const gchar *text ). Esta función se puede utilizar después de poner algún texto por defecto en el widget. que también admite como argumento una bandera booleana. gboolean editable ). hay varias funciones que sirven para alterar el que texto que se está en el widget Entry. Si quiere impedir que alguien cambie el contenido del widget escribiendo en él. Las funciones gtk_entry_append_text y gtk_entry_prepend_text permiten añadir o preañadir texto. haciéndole fácil al usuario eliminar este texto. void gtk_entry_select_region( GtkEntry *entry. *entry. Esta función permite camiar el estado de edición de un widget Entry. Se pueden obtener los contenidos del widget llamando a la función que se describe a continuación. void gtk_entry_set_visibility( GtkEntry *entry. void gtk_entry_set_text( GtkEntry *entry. siendo el argumento editable TRUE o FALSE. gint end ). void gtk_entry_prepend_text( GtkEntry const gchar *text ). como por ejemplo cuando estamos introduciendo una clave. *entry. Se puede seleccionar una región del texto utilizando la siguiente función. El texto se puede poner con llamadas a funciones que permiten reemplazar. . Si estamos utilizando el widget Entry en un sitio donde no queremos que el texto que se introduce sea visible. GtkWidget *gtk_entry_new_with_max_length( guint16 max ). Hay dos funciones para crear un widget Entry: GtkWidget *gtk_entry_new( void ). Obtener los contenidos del widget puede ser útil en las funciones de llamada descritas más adelante. La función gtk_entry_set_text cambia el contenido actual del widget Entry. utilice la función void gtk_entry_set_editable( GtkEntry *entry. mientras que la segunda crea el widget y además establece un límite en la longitud del texto que irá en el mismo. La primera sirve para crear un nuevo widget Entry. podemos utilizar la función siguiente. void gtk_entry_set_position( GtkEntry *entry. gint posicion ). gchar *gtk_entry_get_text( GtkEntry *entry ). gboolean visible ). gint start. preañadir o añadir el texto al contenido actual del widget Entry.El widget Entry permite mostrar e introducir texto en una línea de un cuadro de diálogo.

"delete_event". 0). *check. gtk_window_set_title(GTK_WINDOW (ventana). entry. GTK_ENTRY(entry)->text_length). char *argv[]) { GtkWidget GtkWidget GtkWidget GtkWidget GtkWidget *ventana. *hbox. GTK_SIGNAL_FUNC(enter_callback). } void entry_toggle_visibility (GtkWidget *checkbutton. GtkWidget *entry) { gchar *entry_text. . gtk_entry_append_text (GTK_ENTRY (entry). /* Principio del ejemplo entry entry. 0). entry). TRUE. podemos conectar con las señales activate o changed. entry_text). changed se activa cuando cambia algo del texto. gtk_widget_set_usize( GTK_WIDGET (ventana). } int main (int argc. 0). entry_text = gtk_entry_get_text(GTK_ENTRY(entry)). entry = gtk_entry_new_with_max_length (50).Si queremos saber el momento en el que el usuario ha introducido el texto. gtk_box_pack_start (GTK_BOX (vbox). " world"). gtk_widget_show (entry). GTK_TOGGLE_BUTTON(checkbutton)->active).h> void enter_callback(GtkWidget *widget. gtk_entry_set_text (GTK_ENTRY (entry). gtk_container_add (GTK_CONTAINER (ventana). "hello"). (GtkSignalFunc) gtk_exit. 0. "GTK Entry"). &argv). *boton. NULL). GtkWidget *entry) { gtk_entry_set_visibility(GTK_ENTRY(entry). GTK_TOGGLE_BUTTON(checkbutton)->active). 200. vbox = gtk_vbox_new (FALSE. gtk_widget_show (hbox). /* crear una nueva ventana */ ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL). activate se activa cuando el usuario aprieta la tecla enter en el widget. gtk_widget_show (vbox). hbox). vbox). } void entry_toggle_editable (GtkWidget *checkbutton. gtk_signal_connect(GTK_OBJECT(entry). TRUE. cuando se introduce o se elimina algún carácter. GtkWidget *entry) { gtk_entry_set_editable(GTK_ENTRY(entry). gtk_init (&argc.e. gtk_signal_connect(GTK_OBJECT (ventana). printf("Entry contents: %s\n". *vbox. hbox = gtk_hbox_new (FALSE. "activate". 100). *entry. p. gtk_entry_select_region (GTK_ENTRY (entry). gtk_container_add (GTK_CONTAINER (vbox).c */ #include <gtk/gtk.

GTK_OBJECT (ventana)). gfloat incremento_pagina. Recuerde que un widget ajuste puede crearse con la siguiente función. TRUE). El botón spin utiliza un objeto Ajuste para conservar la información referente al rango de valores que puede tomar el botón spin. gfloat paso. que ilustra la información que se guarda: GtkObject *gtk_adjustment_new( gfloat valor. Esto hace que el widget botón spin sea muy poderoso. gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check). boton. Consiste en una caja para la entrada de texto con una flecha para arriba y otra para abajo justo al lado de la caja. entry). gtk_widget_grab_default (boton). El widget botón spin permite tener valores con un número de cifras decimales (o sin cifras decimales) y la posibilidad de incrementarlo/decrementarlo en pasos configurables. gtk_widget_show(ventana). GTK_WIDGET_SET_FLAGS (boton. TRUE. gtk_widget_show (check).check = gtk_check_button_new_with_label("Editable"). gtk_box_pack_start (GTK_BOX (hbox). gtk_signal_connect (GTK_OBJECT(check). TRUE. } /* fin del ejemplo */ 9. Estos atributos de un ajuste se utilizan en un botón spin de la forma siguiente: • • • • • valor: valor inicial del botón spin inferior: valor inferior del rango superior: valor superior del rango paso: valor a incrementar/decrementar cuando pulsemos el botón 1 en una flecha incremento_pagina: valor a incrementar/decrementar cuando pulsemos el botón 2 en una flecha . return(0). "toggled". "clicked". TRUE. GTK_SIGNAL_FUNC(entry_toggle_editable). Si utilizamos alguna de las flechas haremos que el valor suba o baje dentro del rango de los valores posibles. gfloat tamano_pagina ). gfloat superior. check. TRUE. 0). gtk_widget_show (boton). GTK_CAN_DEFAULT). GTK_SIGNAL_FUNC(gtk_exit). check = gtk_check_button_new_with_label("Visible"). gtk_signal_connect (GTK_OBJECT(check).10 Botones spin El widget botón spin se utiliza normalmente para permitir que el usuario elija un valor de un rango de valores. "toggled". gfloat inferior. La acción de matener pulsado uno de los botones puede resultar (es opcional) en una aceleración del cambio en el valor de acuerdo con el tiempo que se mantenga pulsado. gtk_main(). gtk_widget_show (check). gtk_box_pack_start (GTK_BOX (hbox). gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check). TRUE. 0). GTK_SIGNAL_FUNC(entry_toggle_visibility). boton = gtk_button_new_with_label ("Close"). TRUE. También podemos introducir directamente un valor específico (utilizando la caja de texto). gtk_signal_connect_object (GTK_OBJECT (boton). check. entry). gtk_box_pack_start (GTK_BOX (vbox). 0). TRUE).

GtkSpinType direccion. Podemos establecer y obtener el ajuste utilizando las dos funciones siguientes: void gtk_spin_button_set_adjustment( GtkSpinButton *boton_spin. Si quiere alterar el valor de un spin de forma relativa a su valor actual. El resto de argumentos son los que acabamos de explicar. El valor que un botón spin está mostrando actualmente puede cambiarse utilizando las siguientes funciones: void gtk_spin_button_set_value( GtkSpinButton *boton_spin. puede utilizar la siguiente función: void gtk_spin_button_spin( GtkSpinButton *boton_spin. Veamos como crear un botón spin: GtkWidget *gtk_spin_button_new( GtkAdjustment *ajuste. gfloat valor ). El argumento boton_spin especifica el botón spin que va a reconfigurarse. gint gtk_spin_button_get_value_as_int( GtkSpinButton *boton_spin ). GtkAdjustment *ajuste. guint digitos ). gfloat aceleracion.• tamano_pagina: no se utiliza Además.0 y 1.0 e indica la aceleración que tendrá el botón spin. GtkAdjustment *ajuste ). se puede utilizar el botón 3 para saltar directamente a los valores superior o inferior cuando se pulsa en una de las flechas. El valor actual de un botón spin puede obtenerse como un entero o como un flotante con las funciones siguientes: gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *boton_spin ). El parámetro direccion puede tomar uno de los valores siguientes: • • • • GTK_SPIN_STEP_FORWARD GTK_SPIN_STEP_BACKWARD GTK_SPIN_PAGE_FORWARD GTK_SPIN_PAGE_BACKWARD . El número de cifras decimales también puede alterarse utilizando: void gtk_spin_button_set_digits( GtkSpinButton *boton_spin. El argumento aceleracion toma un valor entre 0. gfloat incremento ). Se puede reconfigurar un botón spin después de su creación utilizando la función: void gtk_spin_button_configure( GtkSpinButton *boton_spin. El argumento digitos especifica el número de cifras decimales con que se mostrará el valor. GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *boton_spin ). guint digitos) . gfloat aceleracion. guint digitos ).

La primera de estas funciones se utiliza para restringir el contenido de la caja de texto de un botón spin a un valor numérico. que se indica cuando creamos el Ajuste que se utiliza con el botón spin. GTK_SPIN_STEP_FORWARD y GTK_SPIN_STEP_BACKWARD aumentan o disminuyen (respectivamente) el valor del botón spin por la cantidad especificada por incremento. Puede indicar si un botón spin pasará del límite superior al inferior utilizando la siguiente función: void gtk_spin_button_set_wrap( GtkSpinButton *boton_spin. Los valores posibles de politica son o GTK_UPDATE_ALWAYS o GTK_UPDATE_IF_VALID. gboolean redondear ). void gtk_spin_button_set_numeric( GtkSpinButton *boton_spin. Para hacer que redondee tenemos que utilizar la función siguiente: void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *boton_spin. y vamos a pasar a las funciones que afectan a la apariencia y al comportamiento del widget botón spin en sí mismo. En el caso de GTK_UPDATE_IF_VALID el valor de un botón spin cambiará si el texto introducido es un valor numérico contenido dentro del rango especificado por el Ajuste. GtkSpinButtonUpdatePolicy politica ). Puede hacer que un botón spin redondee su valor al paso más cercano. GTK_SPIN_END hace que el botón spin tenga el mismo valor que el valor superior del rango Ajuste. Ahora vamos a dejar de lado las funciones para establecer y obtener el rango de los atributos del botón spin. En caso de utilizar GTK_UPDATE_ALWAYS se ignorarán los errores que puedan ocurrir en la conversión del texto en un valor numérico. . GTK_SPIN_HOME hace que el botón spin tenga el mismo valor que el valor inferior del rango Ajuste. a menos que incremento sea igual a 0. En caso contrario el texto introducido se convierte al valor del botón spin. gboolean wrap ). en cuyo caso el valor se aumentará o disminuirá por el valor especificado en paso dentro del Ajuste. gboolean numerico ). Esto evita que un usuario introduzca cualquier valor no númerico. Para política de actualización de un botón spin puede cambiarse con la siguiente función: void gtk_spin_button_set_update_policy( GtkSpinButton *boton_spin. GTK_SPIN_USER_DEFINED cambia el valor del botón spin por la cantidad especificada. Estas políticas afectan al comportamiento de un botón spin cuando se lee el texto insertado en la caja de texto y se sincroniza con los valores del Ajuste. GTK_SPIN_PAGE_FORWARD y GTK_SPIN_PAGE_BACKWARD sencillamente alteran el valor del botón spin por la cantidad incremento. Algunos de los valores que puede utilizar direccion hacen que se utilicen valores que están almacenados en el objeto Ajuste que está asociado con el botón spin.• • • GTK_SPIN_HOME GTK_SPIN_END GTK_SPIN_USER_DEFINED Trataré de explicar todas las posibilidades que ofrece esta función.

GtkSpinButton *spin. gtk_spin_button_get_value_as_int (spin)). etiqueta = GTK_LABEL (gtk_object_get_user_data (GTK_OBJECT (widget))).*f". gtk_spin_button_get_value_as_float (spin)). puede pedir de forma explícita que un botón spin se actualice a sí mismo: void gtk_spin_button_update( GtkSpinButton *boton_spin ).c */ #include <gtk/gtk. "%d". /* principio del ejemplo spinbutton spinbutton. buf). spin->digits. gpointer data ) { gchar buf[32]. } void toggle_numeric( GtkWidget *widget. Es hora de un nuevo ejemplo. Como siempre. gtk_spin_button_get_value_as_int (spin)). if (GPOINTER_TO_INT (data) == 1) sprintf (buf. GTK_TOGGLE_BUTTON (widget)->active). } int main( int argc. GTK_TOGGLE_BUTTON (widget)->active). GtkShadowType tipo_sombra ). gtk_label_set_text (etiqueta. GtkSpinButton *spin ) { gtk_spin_button_set_numeric (spin. } void get_value( GtkWidget *widget. void toggle_snap( GtkWidget *widget. spin = GTK_SPIN_BUTTON (spinner1).El aspecto de los botones utilizados en un botón spin pueden cambiarse utilizando las siguientes funciones: void gtk_spin_button_set_shadow_type( GtkSpinButton *boton_spin. . el tipo_sombra puede ser uno de los siguientes: • • • • GTK_SHADOW_IN GTK_SHADOW_OUT GTK_SHADOW_ETCHED_IN GTK_SHADOW_ETCHED_OUT Finalmente. "%0. GtkSpinButton *spin ) { gtk_spin_button_set_snap_to_ticks (spin. GtkSpinButton *spin ) { gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1).h> static GtkWidget *spinner1. else sprintf (buf. } void change_digits( GtkWidget *widget. GtkLabel *etiqueta.

0. "destroy". 10). adj = (GtkAdjustment *) gtk_adjustment_new (1.0). etiqueta = gtk_label_new ("Day :"). main_vbox = gtk_vbox_new (FALSE. frame = gtk_frame_new ("Not accelerated"). FALSE. GtkWidget *val_label. . "Spin Button"). GtkWidget *vbox2.0. etiqueta. TRUE. gtk_misc_set_alignment (GTK_MISC (etiqueta). 0). NULL). FALSE. mes y año */ hbox = gtk_hbox_new (FALSE. TRUE. TRUE. GtkWidget *vbox. gtk_container_set_border_width (GTK_CONTAINER (vbox). 1. GtkWidget *etiqueta.5). TRUE). GtkWidget *boton. TRUE. TRUE. gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner). GtkWidget *spinner2. 5). gtk_container_set_border_width (GTK_CONTAINER (main_vbox). 0.0). 0). TRUE. TRUE. 31. 5). gtk_container_add (GTK_CONTAINER (frame). frame. gtk_box_pack_start (GTK_BOX (vbox2). 5). gtk_box_pack_start (GTK_BOX (hbox). 0. 0. gtk_signal_connect (GTK_OBJECT (ventana). 0.0. etiqueta = gtk_label_new ("Month :"). TRUE. &argv). TRUE. vbox2. hbox. vbox2 = gtk_vbox_new (FALSE. GtkWidget *main_vbox.0. TRUE. gtk_box_pack_start (GTK_BOX (vbox2). gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner). gtk_box_pack_start (GTK_BOX (vbox2).0. gtk_misc_set_alignment (GTK_MISC (etiqueta). 12. 0.0. spinner. 5). vbox = gtk_vbox_new (FALSE.char *argv[] ) { GtkWidget *ventana. GtkWidget *spinner. 0).0. TRUE. FALSE. etiqueta. gtk_window_set_title (GTK_WINDOW (ventana). 1. 5). vbox2 = gtk_vbox_new (FALSE.0.0.0. 0. 0). vbox). 0). /* spin del día. GtkWidget *frame. /* Inicializar GTK */ gtk_init(&argc.5). 0). gtk_box_pack_start (GTK_BOX (main_vbox). gtk_box_pack_start (GTK_BOX (hbox). 0). 5. adj = (GtkAdjustment *) gtk_adjustment_new (1. GTK_SHADOW_OUT). gtk_container_add (GTK_CONTAINER (ventana). gtk_box_pack_start (GTK_BOX (vbox). spinner = gtk_spin_button_new (adj.0. ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL). 0). 5. vbox2. GtkWidget *hbox. GtkAdjustment *adj. 1. 0). 1. GTK_SIGNAL_FUNC (gtk_main_quit). main_vbox).

adj = (GtkAdjustment *) gtk_adjustment_new (0. TRUE). 0. gtk_box_pack_start (GTK_BOX (vbox2). vbox2. 0. 0. 5. 1. hbox = gtk_hbox_new (FALSE. . 0). FALSE. etiqueta. spinner2 = gtk_spin_button_new (adj. 1. vbox2. 0). etiqueta = gtk_label_new ("Digits :"). 5). TRUE. GTK_SHADOW_IN).0. 5). 0). vbox2 = gtk_vbox_new (FALSE.5). 2).0. 5). TRUE. 5).0. FALSE). 0). gtk_box_pack_start (GTK_BOX (vbox2). GTK_SHADOW_ETCHED_IN). frame. etiqueta = gtk_label_new ("Year :").0. 100.5). TRUE. 0). gtk_container_add (GTK_CONTAINER (frame). 1. vbox2. gtk_box_pack_start (GTK_BOX (vbox2). hbox = gtk_hbox_new (FALSE. TRUE). TRUE. TRUE. "clicked". TRUE). hbox. TRUE. spinner1. FALSE. spinner. TRUE. TRUE. gtk_box_pack_start (GTK_BOX (main_vbox).0. 0). 0.5. (gpointer) spinner2). gtk_widget_set_usize (spinner. 10000. gtk_box_pack_start (GTK_BOX (hbox). vbox). spinner2. 1. TRUE. TRUE. etiqueta. FALSE. gtk_box_pack_start (GTK_BOX (hbox). TRUE. gtk_box_pack_start (GTK_BOX (hbox).0). 5). gtk_box_pack_start (GTK_BOX (vbox2). gtk_box_pack_start (GTK_BOX (vbox2). gtk_container_set_border_width (GTK_CONTAINER (vbox).0. TRUE. gtk_widget_set_usize (spinner1. 0. 55. 0). 0). boton = gtk_check_button_new_with_label ("Snap to 0. vbox2 = gtk_vbox_new (FALSE. 0. TRUE. 0. 0). 0. 0). adj = (GtkAdjustment *) gtk_adjustment_new (1998. gtk_misc_set_alignment (GTK_MISC (etiqueta). gtk_box_pack_start (GTK_BOX (vbox). 0).5-ticks"). 0). FALSE. 0. FALSE. 0). TRUE. 0. -10000. gtk_misc_set_alignment (GTK_MISC (etiqueta).0. 0).0. 0). gtk_box_pack_start (GTK_BOX (vbox). 0). TRUE. 0). etiqueta. 0. 0).0. 0. 100. 2100. adj = (GtkAdjustment *) gtk_adjustment_new (2.0. FALSE. FALSE. 5). gtk_signal_connect (GTK_OBJECT (adj). etiqueta = gtk_label_new ("Value :"). GTK_SIGNAL_FUNC (change_digits). 0). 0). gtk_box_pack_start (GTK_BOX (vbox2).0. 100. spinner = gtk_spin_button_new (adj. 1. gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner). spinner1 = gtk_spin_button_new (adj. FALSE. "value_changed". gtk_box_pack_start (GTK_BOX (vbox2).spinner = gtk_spin_button_new (adj. FALSE. gtk_signal_connect (GTK_OBJECT (boton). TRUE. gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1). gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner).0). gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner). 0. gtk_misc_set_alignment (GTK_MISC (etiqueta).5). gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner). vbox2 = gtk_vbox_new (FALSE. hbox. vbox = gtk_vbox_new (FALSE. TRUE. frame = gtk_frame_new ("Accelerated"). gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2). spinner.

gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (boton). 5). gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (boton). hbox. TRUE. TRUE. "0"). gtk_box_pack_start (GTK_BOX (hbox). 0). TRUE. val_label). TRUE. FALSE. spinner1). boton = gtk_check_button_new_with_label ("Numeric only input mode"). TRUE. gtk_box_pack_start (GTK_BOX (hbox). TRUE.GTK_SIGNAL_FUNC (toggle_snap). gtk_box_pack_start (GTK_BOX (vbox). val_label). FALSE. gtk_box_pack_start (GTK_BOX (vbox). 0). Para conseguirlo puede ajustar cada variable mediante las regletas o introduciendo directamente el valor deseado. "clicked". spinner1). gtk_widget_show_all (ventana). GTK_SIGNAL_FUNC (get_value). boton. boton. boton = gtk_button_new_with_label ("Value as Float"). 0). saturación. ya sea mediante un cambio que haga el usuario o median el resultado de una llamada a la función gtk_color_selection_set_color(). "clicked". 0). opcionalmente. 0). /* Entramos dentro del bucle de eventos */ gtk_main (). GINT_TO_POINTER (1)). TRUE). boton. GTK_SIGNAL_FUNC (toggle_numeric). gtk_label_set_text (GTK_LABEL (val_label). TRUE. También puede pinchar en la rueda de colores y seleccionar así el color deseado. boton. valor). } /* fin del ejemplo */ 9. verde y azul) y HSV (tono. TRUE. También se puede establecer. boton = gtk_button_new_with_label ("Close"). 0). GTK_SIGNAL_FUNC (gtk_widget_destroy). gtk_box_pack_start (GTK_BOX (hbox).12 Selección de Color El widget selección de color. 5). TRUE. gtk_signal_connect (GTK_OBJECT (boton). gtk_signal_connect (GTK_OBJECT (boton). gtk_object_set_user_data (GTK_OBJECT (boton). Este widget compuesto le permite al usuario seleccionar un color manipulando los tripletes RGB (rojo. gtk_box_pack_start (GTK_BOX (main_vbox). return(0). hbox. TRUE. boton. gtk_signal_connect_object (GTK_OBJECT (boton). gtk_box_pack_start (GTK_BOX (vbox). TRUE. hbox = gtk_hbox_new (FALSE. TRUE. gtk_object_set_user_data (GTK_OBJECT (boton). "clicked". TRUE). la transparencia del color. gtk_box_pack_start (GTK_BOX (vbox). El widget de selección de color emite (por ahora) sólo una señal. TRUE. hbox = gtk_hbox_new (FALSE. 5). 5). val_label = gtk_label_new (""). . gtk_signal_connect (GTK_OBJECT (boton). "clicked". nos permite (¡sorpresa!) la selección interactiva de colores. TRUE. GTK_OBJECT (ventana)). GTK_SIGNAL_FUNC (get_value). que se emite cuando cambia el color seleccionado. color_changed. boton = gtk_button_new_with_label ("Value as Int"). val_label. GINT_TO_POINTER (2)).

Puede poner el color actual explicitamente haciendo uso de esta función con un puntero a un vector de colores (de tipo gdouble). Consiste en un GtkFrame con un GtkColorSelection. GtkWidget *drawingarea = NULL. Esta función se utiliza para indicar la política de actuación. Puede utilizar estos botones accediendo a los widgets ok_button.0 y 1. gdouble *color ). Todos los valores se encuentran entre 0. ver gtk_color_selection_set_opacity()).h> #include <gtk/gtk. El widget de selección de color admite el ajuste de la transparencia de un color (también conocido como el canal alfa). utilice esta función. Cuando necesite preguntar por el color actual.h> GtkWidget *colorseldlg = NULL. Aquí tenemos un pequeño ejemplo que muestra el uso de GtkColorSelectionDialog. color es un puntero al vector de colores que se rellenará. (es decir GTK_COLOR_SELECTION_DIALOG(colorseldialog)>ok_button). Crea un GtkColorSelectionDialog. Crea un widget GtkColorSelection huérfano al que le tendrá que asignarle un padre. Éste es el constructor del cuadro de selección de color más común. La posición 0 contiene la componente roja del color. GtkWidget *gtk_color_selection_dialog_new( const gchar *title ). Ver la descripción de la función gtk_color_selection_set_color() para conocer la estructura de este vector. void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel. void gtk_color_selection_set_color( GtkColorSelection *colorsel. Probablemente no utilizará este constructor directamente. Si se utiliza use_opacity como FALSE se desactiva la transparencia. cancel_button y help_button de la estructura GtkColorSelectionDialog. Pulsando en ella se abre un cuadro de diálogo de selección del color. Si se llama a esta función con use_opacity como TRUE se activa la transparencia. Esta opción está desactivada por defecto. y cambiando el color en el cuadro de diálogo se cambia el color de fondo de la zona de dibujo. void gtk_color_selection_set_opacity( GtkColorSelection *colorsel. Si tiene problemas de rendimiento. El widget tiene dos «sabores» diferentes. normalmente cuando haya recibido una señal color_changed. la 2 la azul y la transparencia está en la posición 3 (solamente si está activada la transparencia. GtkUpdateType policy ). «Cancelar» y «Ayuda». El programa muestra una ventana con una zona de dibujo. gint use_opacity ). . /* principio del ejemplo colorsel colorsel. void gtk_color_selection_get_color( GtkColorSelection *colorsel. gtk_color_selection y gtk_color_selection_dialog: GtkWidget *gtk_color_selection_new( void ).c */ #include <glib.0. La longitud del vector depende de si está activada la transparencia. heredado de un GtkDialog. La política por defecto es GTK_UPDATE_CONTINUOUS que significa que el color seleccionado se actualiza continuamente cuando el usuario arrastra la barra o selecciona con el ratón un color de la rueda de colores.Echémosle un vistazo a lo que nos ofrece el widget de selección de color. «Aceptar». El widget GtkColorSelection está heredado del widget GtkVBox. un GtkHSeparator y un GtkHBox con tres botones.h> #include <gdk/gdk. puede poner la política GTK_UPDATE_DISCONTINUOUS o GTK_UPDATE_DELAYED. la 1 contiene la verde. gdouble *color ).

0). } /* Manejador del evento Drawingarea */ gint area_event (GtkWidget *widget. gdk_color.0). GtkWidget *colorsel. /* Conectar con la señal «color_changed»..0). .color). GdkEvent *event. /* Obtener el widget GtkColorSelection */ colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel. ¡tenemos un evento y todavía no está el colorseldlg! */ handled = TRUE. /* Meterlo en un entero sin signo de 16 bits (0. /* Pedir memoria para el color */ gdk_color_alloc (colormap.65535) e insertarlo en la estructura GdkColor */ gdk_color. GdkColormap *colormap. gpointer client_data) { gint handled = FALSE. darle al dato del cliente el valor del widget colorsel */ gtk_signal_connect(GTK_OBJECT(colorsel). gdk_color. "color_changed". &gdk_color). GdkColor gdk_color. /* Obtener el color actual */ gtk_color_selection_get_color (colorsel. GtkColorSelection *colorsel) { gdouble color[3].red = (guint16)(color[0]*65535. /* Poner el color de fondo de la ventana */ gdk_window_set_background (drawingarea->window.green = (guint16)(color[1]*65535. (gpointer)colorsel). /* Comprobar si hemos recibido un evento de pulsación de botón */ if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL) { /* Sí. &gdk_color). (GtkSignalFunc)color_changed_cb. /* Obtener el mapa de colores de la zona de dibujo */ colormap = gdk_window_get_colormap (drawingarea->window). /* Crear el cuadro de diálogo de selección del color */ colorseldlg = gtk_color_selection_dialog_new("Select background color"). /* Limpiar la ventana */ gdk_window_clear (drawingarea->window).blue = (guint16)(color[2]*65535./* Manejador del cambio de color */ void color_changed_cb (GtkWidget *widget.

"event". then show them both */ gtk_container_add (GTK_CONTAINER(ventana). gtk_window_set_policy (GTK_WINDOW(ventana). gtk_widget_show (drawingarea). "delete_event". gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea). /* Crea la zona de dibujo. 200). gchar *argv[]) { GtkWidget *ventana. pone el tamaño y caza los eventos de los botones */ drawingarea = gtk_drawing_area_new (). (gpointer)drawingarea). "Color selection test"). /* Enlaza con los eventos «delete» y «destroy». GDK_BUTTON_PRESS_MASK). 200. TRUE. } return handled. (gpointer)ventana). /* Add drawingarea to window. le da título y la política */ ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL). gtk_window_set_title (GTK_WINDOW(ventana)./* Mostrar el cuadro de diálogo */ gtk_widget_show(colorseldlg). /* Para satisfacer a los compiladores pijos */ . } /* Manipulador de los eventos cerrar y salir */ void destroy_window (GtkWidget *widget. (gpointer)ventana). gtk_widget_show (ventana). y elimina las opciones relacionadas con gtk incluidas en la línea de órdenes */ gtk_init (&argc. (GtkSignalFunc)destroy_window. gtk_widget_set_events (drawingarea. gpointer client_data) { gtk_main_quit (). TRUE). (GtkSignalFunc)area_event. "destroy".&argv). drawingarea). /* Inicializa el toolkit. TRUE. /* Entrar en el bucle principal de gtk (nunca sale de aquí) */ gtk_main (). para que podamos salir */ gtk_signal_connect (GTK_OBJECT(ventana). /* Crea la ventana de más alto nivel. gtk_signal_connect (GTK_OBJECT(drawingarea). } /* Principal */ gint main (gint argc. (GtkSignalFunc)destroy_window. gtk_signal_connect (GTK_OBJECT(ventana).

} int main (int argc. Aunque aparezca el botón de ayuda en la pantalla. /* principio del ejemplo filesel filesel. Para poner el nombre del fichero en el cuadro de diálogo. por ejemplo para poder utilizar un directorio o un fichero por defecto. Para obtener el texto que el usuario ha introducido.13 Selección de ficheros El widget de selección de ficheros nos proporciona una forma rápida y sencilla de mostrar un cuadro de diálogo para la selección de un fichero. Ya viene con los botones Aceptar. Son los siguientes: • • • • • • • • dir_list file_list selection_entry selection_text main_vbox ok_button cancel_button help_button Lo más probable es que sólo utilice los punteros ok_button.c. gpointer data) { gtk_main_quit (). utilice la función: gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel ). Cancelar y Ayuda. utilice la función: void gtk_file_selection_set_filename( GtkFileSelection *filesel. } /* final del ejemplo */ 9. Como puede ver. } void destroy (GtkWidget *widget. char *argv[]) { . no hace nada y no tiene ninguna señal conectada. Una magnifica ayuda para acortar el tiempo de programación. modificado para que se puede ejecutar independientemente. gchar *filename ). no es muy complicado crear un widget para la selección de ficheros.c */ #include <gtk/gtk. y help_button para controlar cuando se pulsan. gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs))). Para crear un nuevo cuadro de diálogo de selección de ficheros utilice: GtkWidget *gtk_file_selection_new( gchar *title ). GtkFileSelection *fs) { g_print ("%s\n". cancel_button.return 0. También hay punteros a los widgets que contiene el cuadro de diálogo. Aquí incluímos un ejemplo robado de testgtk.h> /* Obtener el nombre del fichero e imprimirlo en la consola */ void file_ok_sel (GtkWidget *w.

&argv). como si fuese un cuadro de diálogo para grabar ficheros y estuviesemos dando un nombre por defecto */ gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew). gtk_main (). /* Conectar el cancel_button con la destrucción del widget */ gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button). } /* fin del ejemplo */ . "clicked". (GtkSignalFunc) file_ok_sel. /* Damos el nombre del fichero. return 0. "destroy". /* Crear un nuevo widget de selección de ficheros */ filew = gtk_file_selection_new ("File selection"). "clicked". &filew). filew ). /* Conectar el ok_button con la función file_ok_sel */ gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button). GTK_OBJECT (filew)). gtk_init (&argc. gtk_signal_connect (GTK_OBJECT (filew).png"). gtk_widget_show(filew). (GtkSignalFunc) destroy.GtkWidget *filew. "penguin. (GtkSignalFunc) gtk_widget_destroy.