1 <!doctype linuxdoc system>
4 Traducción realizada por:
5 Joaquín Cuenca Abela (e98cuenc@criens.u-psud.fr)
6 Eduardo Anglada Varela (eduardo.anglada@adi.uam.es)
8 Versión beta 2 de la traducción del GTK+
9 Tutorial 1.2. Cualquier sugerencia será bienvenida.
10 Los cambios más significativos de esta versión son la traducción
11 de las variables de los programas y XXX.
13 Si quiere obtener este documento puede encontrarlo en Linux Landia:
14 http://www.croftj.net/~barreiro/spanish/gnome-es/
18 <title>GTK Tutorial v1.2
19 <author>Tony Gale <tt><htmlurl url="mailto:gale@gtk.org"
20 name="<gale@gtk.org>"></tt>,
21 Ian Main <tt><htmlurl url="mailto:imain@gtk.org"
22 name="<imain@gtk.org>"></tt>
23 <date>21 de Febrero de 1999
25 Este documento es un tutorial sobre como utilizar GTK (el GIMP
31 <!-- ***************************************************************** -->
33 <!-- ***************************************************************** -->
35 GTK (GIMP Toolkit) es una biblioteca para crear interfaces gráficas
36 de usuario. Su licencia es la LGPL, así que mediante GTK podrá
37 desarrollar programas con licencias abiertas, gratuitas, libres, y
38 hasta licencias comerciales no libres sin mayores problemas.
40 Se llama el GIMP toolkit porque fue escrito para el desarrollo del
41 General Image Manipulation Program (GIMP), pero ahora GTK se utiliza
42 en un gran número de proyectos de programación, incluyendo el
43 proyecto GNU Network Object Model Environment (GNOME). GTK está
44 construido encima de GDK (GIMP Drawing Kit) que básicamente es un
45 recubrimiento de las funciones de bajo nivel que deben haber para
46 acceder al sistema de ventanas sobre el que se programe (Xlib en el
47 caso de X windows). Los principales autores de GTK son:
50 <item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
51 name="petm@xcf.berkeley.edu"></tt>
52 <item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
53 name="spencer@xcf.berkeley.edu"></tt>
54 <item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
55 name="jmacd@xcf.berkeley.edu"></tt>
58 GTK es esencialmente una interfaz para la programación de
59 aplicaciones orientadas al objeto (API). Aunque está completamente
60 escrito en C, esta implementado haciendo uso de la idea de clases y de
61 funciones respuesta o de <em/callback/ (punteros o funciones).
63 Tenemos un tercer componente llamado glib, que contiene unas cuantas
64 funciones para reemplazar algunas llamadas estándar, así como
65 funciones adicionales para manejar listas enlazadas, etc... Se
66 reemplazan algunas funciones para aumentar la portabilidad de GTK, ya
67 que algunas de las funciones implementadas no están disponibles o
68 no son estándar en otros unixs, como por ejemplo
69 g_strerror(). Algunas otras contienen mejoras a la versión de libc,
70 como g_malloc que mejora las posibilidades de encontrar errores.
72 Este tutorial describe la interfaz C de GTK. Hay recubrimientos GTK
73 para muchos otros lenguajes, incluyendo C++, Guile, Perl, Python, TOM,
74 Ada95, Objective C, Free Pascal, y Eiffel. Si va a utilizar el
75 recubrimiento para alguno de estos lenguajes, mire primero su
76 documentación. En algunos casos la documentación puede describir
77 algún convenio importante (que debería conocer de antemano) y
78 después puede volver a este tutorial. También hay algún API
79 multiplataforma (como wxWindows y V) que utilizan GTK como una de sus
80 plataformas destino; de nuevo, consulte primero la documentación
81 que viene con estos paquetes.
83 Si está desarrollando su aplicación GTK en C++, hay algunas
84 cosas que debería saber. Hay un recubriento a GTK para C++ llamado
85 GTK--, que proporciona una interfaz C++ a GTK; probablemente
86 debería empezar mirando ahí. Si no le gusta esa aproximación
87 al problema, por los motivos que sean, tiene dos
88 alternativas. Primero, puede ceñirse al subconjunto C de C++ cuando
89 realice alguna llamada a GTK a través de su interfaz en C. Segundo,
90 puede utilizar GTK y C++ al mismo tiempo declarando todas las
91 funciones respuesta como funciones estáticas en clases C++, y de
92 nuevo, llamar a GTK utilizando su interfaz C. Si elige esta última
93 forma de actuar, puede incluir como dato de la función respuesta un
94 puntero al objeto a manipular (el también llamado valor
95 «this»). La elección de una u otra opción es cuestión de
96 gustos personales, ya que de las tres maneras conseguirá utilizar
97 GTK en C++. Ninguna de estas aproximaciones requiere el uso de un
98 preprocesador especializado, por lo que sin importar la opción que
99 escoja podrá utilizar C++ estándar en C++.
101 Este tutorial es un intento de documentar GTK tanto como sea posible,
102 pero no está completo. Este tutorial asume un buen conocimiento de
103 C y de como crear programas bajo este lenguaje. Se verá beneficiado
104 si tiene un conocimiento previo de la programación en X, pero no
105 debería ser necesario. Si está aprendiendo GTK y es el primer
106 conjunto de <em/widgets/ que utiliza, por favor envíenos sus
107 comentarios sobre este tutorial y los problemas que ha
110 Este documento es un `trabajo pendiente de finalizar'. Para encontrar
111 actualizaciones mire en http://www.gtk.org/ <htmlurl
112 url="http://www.gtk.org/" name="http://www.gtk.org/">.
114 Me gustaría escuchar cualquier problema que le surja mientras
115 aprende GTK siguiendo este documento, y apreciaré cualquier
116 información sobre como mejorarlo. Por favor, vea la sección <ref
117 id="sec_Contributing" name="Contribuyendo"> para encontrar más
120 <!-- ***************************************************************** -->
122 <!-- ***************************************************************** -->
125 Por supuesto lo primero que hay que hacer es descargar las fuentes de
126 GTK e instalarlas. La última versión siempre se puede obtener de
127 ftp.gtk.org (en el directorio /pub/gtk). En <htmlurl
128 url="http://www.gtk.org/" name="http://www.gtk.org/"> hay más
129 información sobre GTK. Para configurar GTK hay que usar GNU
130 autoconf. Una vez descomprimido se pueden obtener las opciones usando
131 <tt>./configure --help</tt>.
133 El código de GTK además contiene las fuentes completas de todos
134 los ejemplos usados en este manual, así como los makefiles para
137 Para comenzar nuestra introducción a GTK vamos a empezar con el
138 programa más sencillo posible. Con él vamos a crear una ventana de
139 200x200 <em/pixels/ que sólo se puede destruir desde el shell.
142 /* principio del ejemplo base base.c */
146 int main (int argc, char *argv[])
150 gtk_init (&argc, &argv);
152 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
153 gtk_widget_show (ventana);
159 /* final del ejemplo */
162 Puede compilar el programa anterior con gcc tecleando:
164 gcc base.c -o base `gtk-config --cflags --libs`
167 El significado de la extraña opción de compilación se explica
170 Todo programa que use GTK debe llamar a <tt>gtk/gtk.h</tt> donde se
171 declaran todas las variables, funciones, estructuras, etc. que serán
172 usadas en el programa.
177 gtk_init (&argc, &argv);
180 Llama a la función gtk_init (gint *argc, gchar *** argv) responsable
181 de `arrancar' la biblioteca y de establecer algunos parámetros (como son
182 los colores y los visuales por defecto), llama a gdk_init (gint *argc,
183 gchar *** argv) que inicializa la biblioteca para que pueda
184 utilizarse, establece los controladores de las señales y comprueba los
185 argumentos pasados a la aplicación desde la línea de comandos,
186 buscando alguno de los siguientes:
189 <item> <tt/--gtk-module/
190 <item> <tt/--g-fatal-warnings/
191 <item> <tt/--gtk-debug/
192 <item> <tt/--gtk-no-debug/
193 <item> <tt/--gdk-debug/
194 <item> <tt/--gdk-no-debug/
195 <item> <tt/--display/
197 <item> <tt/--no-xshm/
202 En el caso de que encuentre alguno lo quita de la lista, dejando todo
203 aquello que no reconozca para que el programa lo utilice o lo
204 ignore. Así se consigue crear un conjunto de argumentos que son
205 comunes a todas las aplicaciones basadas en GTK.
207 Las dos líneas de código siguientes crean y muestran una ventana.
210 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
211 gtk_widget_show (ventana);
214 El argumento GTK_WINDOW_TOPLEVEL especifica que queremos que el gestor
215 de ventanas decore y sitúe la ventana. En lugar de crear una ventana
216 de tamaño 0 x 0 toda ventana sin hijos por defecto es de 200 x 200, con
217 lo que se consigue que pueda ser manipulada.
219 La función gtk_widget_show() le comunica a GTK que hemos acabado de
220 especificar los atributos del <em/widget/, y que por tanto puede
223 La última línea comienza el proceso del bucle principal de GTK.
229 Otra llamada que siempre está presente en cualquier aplicación es
230 gtk_main(). Cuando el control llega a ella, GTK se queda dormido
231 esperando a que suceda algún tipo de evento de las X (como puede ser
232 pulsar un botón), que pase el tiempo necesario para que el usuario
233 haga algo, o que se produzcan notificaciones de IO de archivos. En
234 nuestro caso concreto todos los eventos serán ignorados.
237 <!-- ----------------------------------------------------------------- -->
238 <sect1>Programa «Hola Mundo» en GTK
240 El siguiente ejemplo es un programa con un <em/widget/ (un
241 botón). Simplemente es la versión de GTK del clásico «hola mundo».
244 /* comienzo del ejemplo holamundo */
247 /* Ésta es una función respuesta (callback). Sus argumentos
248 son ignorados por en este ejemplo */
249 void hello (GtkWidget *widget, gpointer data)
251 g_print ("Hola mundo\n");
254 gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
256 /* si se devuelve FALSE al administrador de llamadas
257 * "delete_event", GTK emitirá la señal de destrucción
258 * "destroy". Esto es útil para diálogos emergentes del
259 * tipo: ¿Seguro que desea salir?
261 g_print ("Ha ocurrido un evento delete\n");
263 /* Cambiando TRUE por FALSE la ventana se destruirá con
270 void destroy (GtkWidget *widget, gpointer data)
275 int main (int argc, char *argv[])
278 /* GtkWidget es el tipo de almacenamiento usado para los
283 /* En cualquier aplicación hay que realizar la siguiente
284 * llamada. Los argumentos son tomados de la línea de comandos
285 * y devueltos a la aplicación. */
287 gtk_init (&argc, &argv);
289 /* creamos una ventana nueva */
290 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
292 /* Cuando la ventana recibe la señal "delete_event" (emitida
293 * por el gestor de ventanas, normalmente mediante la opción
294 * 'close', o en la barra del título) hacemos que llame a la
295 * función delete_event() tal y como ya hemos visto. Los datos
296 * pasados a la función de respuesta son NULL, y serán ignorados. */
297 gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
298 GTK_SIGNAL_FUNC (delete_event), NULL);
300 /* Aquí conectamos el evento "destroy" con el administrador de
301 * señales. El evento se produce cuando llamamos a
302 * gtk_widget_destroy() desde la ventana o si devolvemos 'FALSE'
303 * en la respuesta "delete_event". */
304 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
305 GTK_SIGNAL_FUNC (destroy), NULL);
307 /* establecemos el ancho del borde de la ventana. */
308 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
310 /* creamos un botón nuevo con la etiqueta "Hola mundo" */
311 boton = gtk_button_new_with_label ("Hola mundo");
313 /* Cuando el botón recibe la señal "clicked" llama a la
314 * función hello() pasándole NULL como argumento. (La
315 * función ya ha sido definida arriba). */
316 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
317 GTK_SIGNAL_FUNC (hello), NULL);
319 /* Esto hará que la ventana sea destruida llamando a
320 * gtk_widget_destroy(ventana) cuando se produzca "clicked". Una
321 * vez mas la señal de destrucción puede provenir del gestor
322 * de ventanas o de aquí. */
323 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
324 GTK_SIGNAL_FUNC (gtk_widget_destroy),
325 GTK_OBJECT (ventana));
327 /* Ahora empaquetamos el botón en la ventana (usamos un gtk
329 gtk_container_add (GTK_CONTAINER (ventana), boton);
331 /* El último paso es representar el nuevo widget... */
332 gtk_widget_show (boton);
335 gtk_widget_show (ventana);
337 /* Todas las aplicaciones basadas en GTK deben tener una llamada
338 * gtk_main() ya que el control termina justo aquí y debe
339 * esperar a que suceda algún evento */
345 /* final del ejemplo*/
348 <!-- ----------------------------------------------------------------- -->
349 <sect1>Compilando Hello World
351 Para compilar el ejemplo hay que usar:
354 gcc -Wall -g helloworld.c -o hello_world `gtk-config --cflags` \
358 Usamos el programa <tt>gtk-config</>, que ya viene (y se instala) con
359 la biblioteca. Es muy útil porque `conoce' que opciones son
360 necesarias para compilar programas que usen gtk. <tt>gtk-config
361 --cflags</tt> dará una lista con los directorios donde el
362 compilador debe buscar ficheros «include». A su vez <tt>gtk-config
363 --libs</tt> nos permite saber las bibliotecas que el compilador
364 intentará enlazar y dónde buscarlas.
366 Hay que destacar que las comillas simples en la orden de
367 compilación son absolutamente necesarias.
369 Las bibliotecas que se enlazan normalmente son:
373 <item>La biblioteca GTK (-lgtk), la biblioteca de <em/widgets/ que se
374 encuentra encima de GDK.
376 <item>La biblioteca GDK (-lgdk), el wrapper de Xlib.
378 <item>La biblioteca glib (-lglib), que contiene diversas funciones. En
379 nuestro ejemplo sólo hemos usado g_print(). GTK está construida
380 encima de glib por lo que simpre se usará. Vea la sección <ref
381 id="sec_glib" name="glib"> para más detalles.
383 <item>La biblioteca Xlib (-lX11) que es usada por GDK.
385 <item> La biblioteca Xext (-lXext) contiene código para
386 <em/pixmaps/ de memoria compartida y otras extensiones.
388 <item>La biblioteca matemática (-lm). Es usada por GTK para
393 <!-- ----------------------------------------------------------------- -->
394 <sect1>Teoría de señales y respuestas
396 Antes de profundizar en <tt/holamundo/ vamos a discutir las
397 señales y las respuestas. GTK es un toolkit (conjunto de
398 herramientas) gestionadas mediante eventos. Esto quiere decir que GTK
399 «duerme» en gtk_main hasta que se recibe un evento, momento en el
400 cual se transfiere el control a la función adecuada.
402 El control se transfiere mediante «señales». (Conviene destacar
403 que las señales de GTK no son iguales que las de los sistemas
404 UNIX, aunque la terminología es la misma.) Cuando sucede un evento,
405 como por ejemplo la pulsación de un botón, se «emitirá» la
406 señal apropiada por el <em/widget/ pulsado. Así es como GTK
407 proporciona la mayor parte de su utilidad. Hay un conjunto de
408 señales que todos los <em/widgets/ heredan, como por ejemplo
409 «destroy» y hay señales que son específicas de cada
410 <em/widget/, como por ejemplo la señal «toggled» de un botón
411 de selección (botón <em/toggle/).
413 Para que un botón haga algo crearemos un controlador que se encarga de
414 recoger las señales y llamar a la función apropiada. Esto se hace
415 usando una función como:
418 gint gtk_signal_connect( GtkObject *objeto,
421 gpointer datos_func );
424 Donde el primer argumento es el <em/widget/ que emite la señal, el
425 segundo el nombre de la señal que queremos `cazar', el tercero es
426 la función a la que queremos que se llame cuando se `cace' la
427 señal y el cuarto los datos que queremos pasarle a esta función.
429 La función especificada en el tercer argumento se denomina «función
430 de respuesta» y debe tener la forma siguiente:
433 void callback_func( GtkWidget *widget,
434 gpointer datos_respuesta );
437 Donde el primer argumento será un puntero al <em/widget/ que emitió la
438 señal, y el segundo un puntero a los datos pasados a la función tal y
439 como hemos visto en el último argumento a gtk_signal_connect().
441 Conviene destacar que la declaración de la función de respuesta debe
442 servir sólo como guía general, ya que algunas señales específicas
443 pueden generar diferentes parámetros de llamada. Por ejemplo, la señal
444 de GtkCList «select_row» proporciona los parámetros fila y columna.
446 Otra llamada usada en el ejemplo del hola mundo es:
449 gint gtk_signal_connect_object( GtkObject *objeto,
452 GtkObject *slot_object );
455 gtk_signal_connect_object() es idéntica a gtk_signal_connect() excepto
456 en que la función de llamada sólo usa un argumento, un puntero a un
457 objeto GTK. Por tanto cuando usemos esta función para conectar
458 señales, la función de respuesta debe ser de la forma:
461 void callback_func( GtkObject *object );
464 Donde, por regla general, el objeto es un <em/widget/. Sin embargo no
465 es normal establecer una respuesta para gtk_signal_connect_object. En
466 lugar de ello llamamos a una función de GTK que acepte un <em/widget/
467 o un objeto como un argumento, tal y como se vio en el ejemplo hola
470 ¿Para qué sirve tener dos funciones para conectar señales? Simplemente
471 para permitir que las funciones de respuesta puedan tener un número
472 diferente de argumentos. Muchas funciones de GTK sólo aceptan un
473 puntero a un GtkWidget como argumento, por lo que tendrá que usar
474 gtk_signal_connect_object() con estas funciones, mientras que
475 probablemente tenga que suministrarle información adicional a sus
478 <!-- XXX Completamente revisado hasta aquí -------------------------- -->
481 Además del mecanismo de señales descrito arriba existe otro conjunto
482 de <em>eventos</em> que reflejan como las X manejan los eventos. Se
483 pueden asignar funciones de respuesta a estos eventos. Los eventos
488 <item> button_press_event
489 <item> button_release_event
490 <item> motion_notify_event
494 <item> key_press_event
495 <item> key_release_event
496 <item> enter_notify_event
497 <item> leave_notify_event
498 <item> configure_event
499 <item> focus_in_event
500 <item> focus_out_event
503 <item> property_notify_event
504 <item> selection_clear_event
505 <item> selection_request_event
506 <item> selection_notify_event
507 <item> proximity_in_event
508 <item> proximity_out_event
509 <item> drag_begin_event
510 <item> drag_request_event
511 <item> drag_end_event
512 <item> drop_enter_event
513 <item> drop_leave_event
514 <item> drop_data_available_event
518 Para conectar una función de respuesta a alguno de los eventos
519 anteriores debe usar la función gtk_signal_connect, tal y como se
520 descrivió anteriormente, utilizando en el parámetro <tt/name/ uno de
521 los nombres de los eventos que se acaban de mencionar. La función de
522 respuesta para los eventos tiene un forma ligeramente diferente de la
523 que tiene para las señales:
526 void callback_func( GtkWidget *widget,
528 gpointer callback_data );
531 GdkEvent es una estructura <tt/union/ cuyo tipo depende de cual de los
532 eventos anteriores haya ocurrido. Para que podamos decir que evento se
533 ha lanzado cada una de las posibles alternativas posee un parámetro
534 <tt/type/ que refleja cual es el evento en cuestión. Los otros
535 componentes de la estructura dependerán del tipo de evento. Algunos
536 valores posibles son:
558 GDK_SELECTION_REQUEST
568 GDK_VISIBILITY_NOTIFY
570 GDK_OTHER_EVENT /* En desuso, usar filtros en lugar de ella */
573 Por lo tanto para conectar una función de respuesta a uno de estos
574 eventos debemos usar algo como:
577 gtk_signal_connect( GTK_OBJECT(boton), "button_press_event",
578 GTK_SIGNAL_FUNC(button_press_callback),
582 Por supuesto se asume que <tt/boton/ es un <em/widget/
583 GtkButton. Cada vez que el puntero del ratón se encuentre sobre el
584 botón y éste sea presionado, se llamará a la función
585 <tt/button_press_callback/. Esta función puede declararse así:
588 static gint button_press_event (GtkWidget *widget,
589 GdkEventButton *event,
593 Conviene destacar que se puede declarar el segundo argumento como
594 <tt/GdkEventButton/ porque sabemos que este tipo de evento ocurrirá
595 cuando se llame a la función.
597 El valor devuelto por esta función es usado para saber si el evento
598 debe ser propagado a un nivel más profundo dentro del mecanismo de
599 GTK para gestionar los eventos. Si devuelve TRUE el evento ya ha sido
600 gestionado y por tanto no tiene que ser tratado por el mecanismo de
601 gestión. Por contra si devuelve FALSE se continua con la gestión
602 normal del evento. Para más detalles se recomienda leer la sección
603 donde se aclara como se produce el proceso de propagación.
605 Para más detalles acerca de los tipos de información GdkEvent
606 consultar el apéndice <ref id="sec_GDK_Event_Types" name="Tipos de
609 <!-- ----------------------------------------------------------------- -->
610 <sect1>Aclaración de Hello World
612 Ahora que conocemos la teoría vamos a aclarar las ideas estudiando
613 en detalle el programa <tt/helloworld/.
615 Ésta es la función respuesta a la que se llamará cuando se
616 pulse el botón. En el ejemplo ignoramos tanto el <em/widget/ como
617 la información, pero no es difícil usarlos. El siguiente ejemplo
618 usará la información que recibe como argumento para decirnos que
619 botón fue presionado.
622 void hello (GtkWidget *widget, gpointer data)
624 g_print ("Hello World\n");
628 La siguiente respuesta es un poco especial, el «delete_event» ocurre
629 cuando el gestor de ventanas envía este evento a la aplicación. Aquí
630 podemos decidir que hacemos con estos eventos. Los podemos ignorar,
631 dar algún tipo de respuesta, o simplemente terminar la aplicación.
633 El valor devuelto en esta respuesta le permite a GTK saber que tiene
634 que hacer. Si devolvemos TRUE, estamos diciendo que no queremos que se
635 emita la señal «destroy» y por lo tanto queremos que nuestra
636 aplicación siga ejecutándose. Si devolvemos FALSE, decimos que
637 se emita «destroy», lo que hará que se ejecute nuestro manejador
638 de señal de «destroy».
641 gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
643 g_print ("delete event occured\n");
649 Con el siguiente ejemplo presentamos otra función de respuesta que hace
650 que el programa salga llamando a gtk_main_quit(). Con esta función le
651 decimos a GTK que salga de la rutina gtk_main() cuando vuelva a estar
655 void destroy (GtkWidget *widget, gpointer data)
661 Como el lector probablemente ya sabe toda aplicación debe tener una
662 función main(), y una aplicación GTK no va a ser menos. Todas las
663 aplicaciones GTK también tienen una función de este tipo.
666 int main (int argc, char *argv[])
669 Las líneas siguientes declaran un puntero a una estructura del tipo
670 GtkWidget, que se utilizarán más adelante para crear una ventana y un
678 Aquí tenemos otra vez a gtk_init. Como antes arranca el conjunto de
679 herramientas y filtra las opciones introducidas en la línea de
680 órdenes. Cualquier argumento que sea reconocido será borrado de la
681 lista de argumentos, de modo que la aplicación recibirá el resto.
684 gtk_init (&argc, &argv);
687 Ahora vamos a crear una ventana. Simplemente reservamos memoria para
688 la estructura GtkWindow *ventana, con lo que ya tenemos una nueva
689 ventana, ventana que no se mostrará hasta que llamemos a
690 gtk_widget_show (ventana) hacia el final del programa.
693 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
696 Aquí tenemos un ejemplo de como conectar un manejador de señal a un
697 objeto, en este caso, la ventana. La señal a cazar será
698 «destroy». Esta señal se emite cuando utilizamos el administrador de
699 ventanas para matar la ventana (y devolvemos TRUE en el manejador
700 «delete_event»), o cuando usamos llamamos a gtk_widget_destroy()
701 pasándole el <em/widget/ que representa la ventana como argumento.
702 Así conseguimos manejar los dos casos con una simple llamada a la
703 función destroy () (definida arriba) pasándole NULL como argumento y
704 ella acabará con la aplicación por nosotros.
706 GTK_OBJECT y GTK_SIGNAL_FUNC son macros que realizan la comprobación y
707 transformación de tipos por nosotros. También aumentan la legibilidad
711 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
712 GTK_SIGNAL_FUNC (destroy), NULL);
715 La siguiente función establece un atributo a un objeto contenedor
716 (discutidos luego). En este caso le pone a la ventana un área
717 negra de 10 <em/pixels/ de ancho donde no habrán <em/widgets/. Hay
718 funciones similares que serán tratadas con más detalle en la sección
719 <ref id="sec_setting_widget_attributes" name="Estableciendo los
720 atributos de los <em/widgets/">
722 De nuevo, GTK_CONTAINER es una macro que se encarga de la conversión
726 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
729 La siguiente llamada crea un nuevo botón. Reserva espacio en la
730 memoria para una nueva estructura del tipo GtkWidget, la inicializa
731 y hace que el puntero <tt/boton/ apunte a esta estructura. Su etiqueta
735 boton = gtk_button_new_with_label ("Hola mundo");
738 Ahora hacemos que el botón sea útil, para ello enlazamos el botón con
739 el manejador de señales para que cuando emita la señal «clicked», se
740 llame a nuestra función hola(). Los datos adicionales serán
741 ignorados, por lo que simplemente le pasaremos NULL a la función
742 respuesta. Obviamente se emitirá la señal «clicked» cuando pulsemos
743 en el botón con el ratón.
746 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
747 GTK_SIGNAL_FUNC (hola), NULL);
750 Ahora vamos a usar el botón para terminar nuestro programa. Así
751 aclararemos cómo es posible que la señal «destroy» sea emitida tanto
752 por el gestor de ventanas como por nuestro programa. Cuando el botón
753 es pulsado, al igual que arriba, se llama a la primera función
754 respuesta hello() y después se llamará a esta función. Las funciones
755 respuesta serán ejecutadas en el orden en que sean conectadas. Como la
756 función gtk_widget_destroy() sólo acepta un GtkWidget como argumento,
757 utilizaremos gtk_signal_connect_object() en lugar de
758 gtk_signal_connect().
761 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
762 GTK_SIGNAL_FUNC (gtk_widget_destroy),
763 GTK_OBJECT (ventana));
766 La siguiente llamada sirve para empaquetar (más detalles luego). Se
767 usa para decirle a GTK que el botón debe estar en la ventana dónde
768 será mostrado. Conviene destacar que un contenedor GTK sólo puede
769 contener un <em/widget/. Existen otros <em/widgets/ (descritos
770 después) que sirven para contener y establecer la disposición de
771 varios <em/widgets/ de diferentes formas.
774 gtk_container_add (GTK_CONTAINER (ventana), boton);
777 Ahora ya tenemos todo bien organizado. Como todos los controladores de
778 las señales ya están en su sitio, y el botón está situado en la
779 ventana donde queremos que esté, sólo nos queda pedirle a GTK que
780 muestre todos los <em/widgets/ en pantalla. El <em/widget/ ventana será
781 el último en mostrarse queremos que aparezca todo de golpe, en vez de
782 ver aparecer la ventana, y después ver aparecer el botón. De todas
783 formas con un ejemplo tan simple nunca se notaría cual es el orden de
787 gtk_widget_show (boton);
789 gtk_widget_show (ventana);
792 Llamamos a gtk_main() que espera hasta que el servidor X le comunique
793 que se ha producido algún evento para emitir las señales apropiadas.
799 Por último el `return' final que devuelve el control cuando gtk_quit()
806 Cuando pulsemos el botón del ratón el <em/widget/ emite la señal
807 correspondiente «clicked». Para que podamos usar la información el
808 programa activa el gestor de eventos que al recibir la señal llama a
809 la función que hemos elegido. En nuestro ejemplo cuando pulsamos el
810 botón se llama a la función hello() con NULL como argumento y además
811 se invoca al siguiente manipulador de señal. Así conseguimos que se
812 llame a la función gtk_widget_destroy() con el <em/widget/ asociado a
813 la ventana como argumento, lo que destruye al <em/widget/. Esto hace
814 que la ventana emita la señal «destroy», que es cazada, y que llama
815 a nuestra función respuesta destroy(), que simplemente sale de GTK.
817 Otra posibilidad es usar el gestor de ventanas para acabar con la
818 aplicación. Esto emitirá «delete_event» que hará que se
819 llame a nuestra función manejadora correspondiente. Si en la
820 función manejadora «delete_event» devolvemos TRUE la ventana se
821 quedará como si nada hubiese ocurrido, pero si devolvemos FALSE GTK
822 emitirá la señal «destroy» que, por supuesto, llamará a la
823 función respuesta «destroy», que saldrá de GTK.
825 <!-- ***************************************************************** -->
827 <!-- ***************************************************************** -->
829 <!-- ----------------------------------------------------------------- -->
830 <sect1>Tipos de datos
832 Existen algunos detalles de los ejemplos anteriores que hay que aclarar.
833 Los tipos gint, gchar, etc. que puede ver por ahí son typedefs a int y
834 a char respectivamente. Sirven para que no haya que tener en cuenta el
835 tamaño de cada uno de ellos a la hora de hacer cálculos.
837 Un buen ejemplo es <tt/gint32/ que es un entero de 32 bits independientemente
838 de la plataforma, bien sea un Alpha de 64 bits o un i386 de 32. Todas las
839 definiciones son muy intuitivas y se encuentran definidas en glib/glib.h
840 (que se incluye desde gtk.h).
842 Probablemente el lector se haya dado cuenta de que se puede usar GtkWidget
843 cuando la función llama a un GtkObject. Esto es debido a que GTK
844 está orienta a objetos y un <em/widget/ es un GtkObject.
846 <!-- ----------------------------------------------------------------- -->
847 <sect1>Más sobre el manejo de señales
849 Si estudiamos en mayor profundidad la declaración de
853 gint gtk_signal_connect( GtkObject *object,
856 gpointer func_data );
859 Podemos darnos cuenta de que el valor devuelto es del tipo gint. Este
860 valor es una etiqueta que identifica a la función de respuesta. Tal
861 y como ya vimos podemos tener tantas funciones de respuesta por
862 seÑal y objeto como sean necesarias, y cada una de ellas se
863 ejecutará en el mismo orden en el que fueron enlazadas.
865 Esta etiqueta nos permite eliminar la función respuesta de la lista
869 void gtk_signal_disconnect( GtkObject *object,
873 Por lo tanto podemos desconectar un manejador de señal pasándole
874 a la función anterior el <em/widget/ del que queremos desconectar y
875 la etiqueta o id devuelta por una de las funciones signal_connect.
877 Otra función que se usa para quitar desconectar todos los
878 controladores de un objeto es:
881 void gtk_signal_handlers_destroy( GtkObject *object );
884 Esta llamada es bastante auto explicativa. Simplemente quitamos todos los
885 controladores de señales del objeto que pasamos como primer argumento.
887 <!-- ----------------------------------------------------------------- -->
888 <sect1>Un Hello World mejorado.
890 Vamos a mejorar el ejemplo para obtener una visión más amplia
891 sobre el manejo de señales y respuestas. También introduciremos
892 los <em/widgets/ usados para empaquetar.
895 /* principio del ejemplo helloworld2 */
899 /* Nuestra respuesta mejorada. Los argumentos de la función se
900 * imprimen en el stdout.*/
901 void callback (GtkWidget *widget, gpointer data)
903 g_print ("Hello again - %s was pressed\n", (char *) data);
907 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
912 int main (int argc, char *argv[])
914 /* GtkWidget es el tipo de almacenamiento usado para los wigtes*/
919 /* Esta llamada está presente en todas las aplicaciones basadas
920 * en GTK. Los argumentos introducidos a la aplicación*/
921 gtk_init (&argc, &argv);
923 /* creamos una nueva ventana*/
924 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
926 /* Esta función es nueva, pone como título de la ventana
929 gtk_window_set_title (GTK_WINDOW (ventana), "¡Hola botones!");
931 /* Establecemos el controlador para la llamada delete_event que
932 * termina la aplicación inmediatamente. */
934 gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
935 GTK_SIGNAL_FUNC (delete_event), NULL);
938 /* Establecemos el ancho del borde de la ventana.*/
939 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
941 /* Creamos una caja donde empaquetaremos los widgets. El
942 * procedimiento de empaquetamiento se describe en detalle en la
943 * sección correspondiente. La caja no se ve realmente, sólo
944 * sirve para introducir los widgets. */
945 caja1 = gtk_hbox_new(FALSE, 0);
947 /* ponemos la caja en la ventana principal */
948 gtk_container_add (GTK_CONTAINER (ventana), caja1);
950 /* Creamos un nuevo botón con la etiqueta "Botón 1". */
951 boton = gtk_button_new_with_label ("Botón 1");
953 /* Cada vez que el botón sea pulsado llamamos a la función
954 * "callback" con un puntero a "botón 1" como argumento. */
955 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
956 GTK_SIGNAL_FUNC (callback), (gpointer) "botón 1");
958 /* En lugar de gtk_container_add empaquetamos el botón en la
959 * caja invisible, que a su vez ha sido empaquetado en la
961 gtk_box_pack_start(GTK_BOX(caja1), boton, TRUE, TRUE, 0);
963 /* Siempre se debe realizar este paso. Sirve para decirle a GTK
964 * que los preparativos del botón ya se han finalizado y que
965 * por tanto puede ser mostrado. */
966 gtk_widget_show(boton);
968 /* hacemos lo mismo para crear un segundo botón. */
969 boton = gtk_button_new_with_label ("Botón 2");
971 /* Llamamos a la misma función de respuesta pero con diferente
972 * argumento: un puntero a "botón 2". */
973 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
974 GTK_SIGNAL_FUNC (callback), (gpointer) "botón 2");
976 gtk_box_pack_start(GTK_BOX(caja1), boton, TRUE, TRUE, 0);
978 /* El orden en que mostramos los botones no es realmente
979 * importante, pero se recomienda mostrar la ventana la última
980 * para que todo aparezca de golpe. */
981 gtk_widget_show(boton);
983 gtk_widget_show(caja1);
985 gtk_widget_show (ventana);
987 /* Esperamos en gtk_main a que comience el espectáculo.*/
992 /* final del ejemplo*/
995 Compile el programa usando los mismos argumentos que en el ejemplo
996 anterior. Probablemente ya se habrá dado cuenta de que no hay una
997 forma sencilla para terminar el programa, se debe usar el gestor de
998 ventanas o la línea de comandos para ello. Un buen ejercicio para
999 el lector es introducir un tercer botón que termine el
1000 programa. También puede resultar interesante probar las diferentes
1001 opciones de gtk_box_pack_start() mientras lee la siguiente
1002 sección. Intente cambiar el tamaño de la ventana y observe el
1005 Como última nota, existe otra definición bastante útil:
1006 gtk_widow_new() - GTK_WINDOW_DIALOG. Su comportamiento es un poco
1007 diferente y debe ser usado para ventanas intermedias (cuadros de
1010 <!-- ***************************************************************** -->
1011 <sect><em/Widgets/ usados para empaquetar
1012 <!-- ***************************************************************** -->
1014 Al crear una aplicación normalmente se quiere que haya más de un
1015 <em/widget/ por ventana. Nuestro primer ejemplo sólo usaba un
1016 <em/widget/ por lo que usábamos la función gtk_container_add
1017 para «empaquetar» el <em/widget/ en la ventana. Pero cuando cuando
1018 se quiere poner más de un <em/widget/ en una ventana, ¿Cómo
1019 podemos controlar donde aparecerá el <em/widget/?. Aquí es donde
1020 entra el empaquetamiento.
1022 <!-- ----------------------------------------------------------------- -->
1023 <sect1>Empaquetamiento usando cajas
1025 Normalmente para empaquetar se usan cajas, tal y como ya hemos
1026 visto. Éstas son <em/widgets/ invisibles que pueden contener
1027 nuestros <em/widgets/ de dos formas diferentes, horizontal o
1028 verticalmente. Al hacerlo de la primera forma los objetos son
1029 insertados de izquierda a derecha o al revés (dependiendo de que
1030 llamada se use). Lo mismo ocurre en los verticales (de arriba a bajo o
1031 al revés). Se pueden usar tantas cajas como se quieran para
1032 conseguir cualquier tipo de efecto.
1034 Para crear una caja horizontal llamamos a gtk_hbox_new() y para las
1035 verticales gtk_vbox_new(). Las funciones usadas para introducir
1036 objetos dentro son gtk_box_pack_start() y gtk_box_pack_end(). La
1037 primera llenará de arriba a abajo o de izquierda a derecha. La
1038 segunda lo hará al revés.
1039 Usando estas funciones podemos ir metiendo <em/widgets/ con una
1040 justificación a la izquierda o a la derecha y además podemos
1041 mezclarlas de cualquier manera para conseguir el efecto
1042 deseado. Nosotros usaremos gtk_box_pack_start() en la mayoria de
1043 nuestros ejemplos. Un objeto puede ser otro contenedor o un
1044 <em/widget/. De hecho, muchos <em/widgets/ son contenedores,
1045 incluyendo el <em/widget/ botón (button) (aunque normalmente lo
1046 único que meteremos dentro será una etiqueta de texto).
1048 Mediante el uso de estas funciones le decimos a GTK dónde queremos
1049 situar nuestros widgets, y GTK podrá, por ejemplo, cambiarles el
1050 tamaño de forma automática y hacer otras cosas de
1051 utilidad. También hay unas cuantas opciones que tienen que ver con
1052 la forma en la que los <em/widgets/ serán empaquetados. Como puede
1053 imaginarse, este método nos da una gran flexibilidad a la hora de
1054 colocar y crear <em/widgets/.
1056 <!-- ----------------------------------------------------------------- -->
1057 <sect1>Detalles de la cajas.
1059 Debido a esta flexibilidad el empaquetamiento puede ser confuso al
1060 principio. Hay muchas opciones y no es obvio como encajan unas con
1061 otras. Pero en la práctica sólo hay cinco estilos diferentes.
1065 <IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528"
1066 HEIGHT="235" ALT="Imagen de ejemplo sobre el empaquetado con cajas">
1070 Cada línea contiene una caja horizontal (hbox) con diferentes
1071 botones. La llamada a gtk_box_pack es una manera de conseguir
1072 empaquetar cada uno de los botones dentro de la caja. Eso sí, cada uno
1073 de ellos se empaqueta de la misma forma que el resto (se llama con los
1074 mismos argumentos a gtk_box_pack_start()).
1076 Esta es la declaración de la función gtk_box_pack_start:
1079 void gtk_box_pack_start( GtkBox *box,
1086 El primer argumento es la caja dónde se empaqueta, el segundo el
1087 objeto. Por ahora el objeto será un botón, ya que estamos
1088 empaquetando botones dentro de las cajas.
1090 El argumento <tt/expand/ de gtk_box_pack_start() y de
1091 gtk_box_pack_end() controla si los <em/widgets/ son expandidos en la
1092 caja para rellenar todo el espacio de la misma (TRUE) o si por el
1093 contrario no se usa el espacio extra dentro de la caja
1094 (FALSE). Poniendo FALSE en <em/expand/ podremos hacer que nuestros
1095 <em/widgets/ tengan una justaficación a la derecha o a la
1096 izquierda. En caso contrario, los <em/widgets/ se expandirán para
1097 llenar toda la caja, y podemos conseguir el mismo efecto utilizando
1098 sólo una de las funciones gtk_box_pack_start o pack_end.
1100 El argumento <tt/fill/ de gtk_box controla si el espacio extra se mete
1101 dentro de los objetos (TRUE) o como relleno extra (FALSE). Sólo
1102 tiene efecto si el argumento de expansión también es TRUE.
1104 Al crear una nueva ventana la función debe ser parecida a esta:
1107 GtkWidget *gtk_hbox_new (gint homogeneous,
1111 El argumento <tt/homogeneous/ (tanto para gtk_hbox_new como para
1112 gtk_vbox_new) controla si cada objeto en la caja tiene el mismo
1113 tamaño (anchura en una hbox o altura en una vbox). Si se activa, el
1114 argumento <tt/expand/ de las rutinas gtk_box_pack siempre estará
1117 Puede que el lector se esté haciendo la siguiente pregunta:
1118 ¿Cúal es la diferencia entre espaciar (establecido cuando se
1119 crea la caja) y rellenar (determinado cuando se empaquetan los
1120 elementos)? El espaciado se añade entre objetos, y el rellenado se
1121 hace en cada parte de cada objeto. La siguiente figura debe aclarar la
1126 <IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509" HEIGHT="213"
1127 VSPACE="15" HSPACE="10" ALT="Imagen de ejemplo sobre el empaquetado con cajas">
1131 Estudiemos el código usado para crear las imágenes
1132 anteriores. Con los comentarios no debería de haber ningún
1133 problema para entenderlo.
1135 <!-- ----------------------------------------------------------------- -->
1136 <sect1>Programa demostración de empaquetamiento
1139 /* principio del ejemplo packbox packbox.c */
1142 #include "gtk/gtk.h"
1145 delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
1150 /* Hacemos una hbox llena de etiquetas de botón. Los argumentos
1151 * para las variables que estamos interesados son pasados a esta
1152 * función. No mostramos la caja, pero hacemos todo lo que
1154 GtkWidget *make_box (gint homogeneous, gint spacing,
1155 gint expand, gint fill, gint padding)
1161 /* creamos una nueva caja con los argumentos homogeneous y
1163 box = gtk_hbox_new (homogeneous, spacing);
1165 /* crear una serie de botones */
1166 boton = gtk_button_new_with_label ("gtk_box_pack");
1167 gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1168 gtk_widget_show (boton);
1170 boton = gtk_button_new_with_label ("(box,");
1171 gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1172 gtk_widget_show (boton);
1174 boton = gtk_button_new_with_label ("boton,");
1175 gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1176 gtk_widget_show (boton);
1178 /* Este botón llevará por etiqueta el valor de expand */
1180 boton = gtk_button_new_with_label ("TRUE,");
1182 boton = gtk_button_new_with_label ("FALSE,");
1184 gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1185 gtk_widget_show (boton);
1187 /* Este es el mismo caso que el de arriba, pero más compacto */
1188 boton = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1189 gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1190 gtk_widget_show (boton);
1192 sprintf (padstr, "%d);", padding);
1194 boton = gtk_button_new_with_label (padstr);
1195 gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
1196 gtk_widget_show (boton);
1202 main (int argc, char *argv[])
1208 GtkWidget *separator;
1209 GtkWidget *etiqueta;
1213 /* ¡No olvidar la siguiente llamada! */
1214 gtk_init (&argc, &argv);
1217 fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1218 /* hacemos limpieza en GTK y devolvemos el valor de 1 */
1222 which = atoi (argv[1]);
1224 /* Creamos la ventana */
1225 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1227 /* Siempre hay que conectar la señal de destrucción con la
1228 * ventana principal. Esto es muy importante para que el
1229 * comportamiento de la ventana sea intuitivo. */
1230 gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
1231 GTK_SIGNAL_FUNC (delete_event), NULL);
1232 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
1234 /* Creamos una caja vertical donde empaquetaremos las cajas
1235 * horizontales. Así podemos apilar las cajas horizontales
1236 * llenas con botones una encima de las otras. */
1237 caja1 = gtk_vbox_new (FALSE, 0);
1239 /* Aclaramos cúal es el ejemplo a mostrar. Se corresponde con
1240 * las imágenes anteriores. */
1243 /* creamos una nueva etiqueta. */
1244 etiqueta = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1246 /* Alineamos la etiqueta a la izquierda. Está función
1247 * será discutida en detalle en la sección de los
1248 * atributos de los widgets. */
1249 gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
1251 /* Empaquetamos la etiqueta en la caja vertical (vbox
1252 * caja1). Siempre hay que recordar que los widgets añadidos a
1253 * una vbox serán empaquetados uno encimo de otro. */
1254 gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
1256 /* mostramos la etiqueta. */
1257 gtk_widget_show (etiqueta);
1259 /* llamada a la función que hace las cajas. Los argumentos
1260 * son homogenous = FALSE, expand = FALSE, fill = FALSE,
1262 caja2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1263 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1264 gtk_widget_show (caja2);
1266 /* Llamad a la función para hacer cajas -
1267 * homogeneous = FALSE, spacing = 0, expand = FALSE,
1268 * fill = FALSE, padding = 0 */
1269 caja2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1270 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1271 gtk_widget_show (caja2);
1273 /* Los argumentos son: homogeneous, spacing, expand, fill,
1275 caja2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1276 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1277 gtk_widget_show (caja2);
1280 /* creamos un separador. Más tarde aprenderemos más cosas
1281 * sobre ellos, pero son bastante sencillos. */
1282 separator = gtk_hseparator_new ();
1284 /* empaquetamos el separador el la vbox. Los widgets serán
1285 * apilados verticalmente. */
1286 gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1287 gtk_widget_show (separator);
1289 /* creamos una nueva etiqueta y la mostramos */
1290 etiqueta = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1291 gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
1292 gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
1293 gtk_widget_show (etiqueta);
1295 /* Los argumentos son: homogeneous, spacing, expand, fill,
1297 caja2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1298 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1299 gtk_widget_show (caja2);
1301 /* Los argumentos son: homogeneous, spacing, expand, fill,
1303 caja2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1304 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1305 gtk_widget_show (caja2);
1307 /* un nuevo separador */
1308 separator = gtk_hseparator_new ();
1309 /* Los tres últimos argumentos son: expand, fill, padding. */
1310 gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1311 gtk_widget_show (separator);
1317 /* Nueva etiqueta */
1318 etiqueta = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1319 gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
1320 gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
1321 gtk_widget_show (etiqueta);
1323 /* Los argumentos son: homogeneous, spacing, expand, fill,
1325 caja2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1326 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1327 gtk_widget_show (caja2);
1329 /* Los argumentos son: homogeneous, spacing, expand, fill,
1331 caja2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1332 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1333 gtk_widget_show (caja2);
1335 separator = gtk_hseparator_new ();
1336 /* Los argumentos son: expand, fill, padding. */
1337 gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1338 gtk_widget_show (separator);
1340 etiqueta = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1341 gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
1342 gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
1343 gtk_widget_show (etiqueta);
1345 /* Los argumentos son: homogeneous, spacing, expand, fill,
1347 caja2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1348 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1349 gtk_widget_show (caja2);
1351 /* Los argumentos son: homogeneous, spacing, expand, fill,
1353 caja2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1354 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1355 gtk_widget_show (caja2);
1357 separator = gtk_hseparator_new ();
1358 /* Los argumentos son: expand, fill, padding. */
1359 gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1360 gtk_widget_show (separator);
1365 /* Con esto demostramos como hay que usar gtk_box_pack_end ()
1366 * para conseguir que los
1367 widgets esten alineados a la izquierda. */
1368 caja2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1370 /* la última etiqueta*/
1371 etiqueta = gtk_label_new ("end");
1373 /* la empaquetamos usando gtk_box_pack_end(), por lo que se
1374 * sitúa en el lado derecho de la hbox.*/
1375 gtk_box_pack_end (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
1377 /* mostrar la etiqueta */
1378 gtk_widget_show (etiqueta);
1381 /* empaquetamos caja2 en caja1 */
1382 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
1383 gtk_widget_show (caja2);
1386 /* el separador para la parte de abajo. */
1387 separator = gtk_hseparator_new ();
1389 /* Así se determina el tamaño del separador a 400 pixels
1390 * de largo por 5 de alto. La hbox también tendrá 400
1391 * pixels de largo y la etiqueta "end" estará separada de
1392 * las demás etiquetas en la hbox. Si no establecemos estos
1393 * parámetros todos los widgets en la hbox serán
1394 * empaquetados tan juntos como se pueda.*/
1395 gtk_widget_set_usize (separator, 400, 5);
1397 /* Empaquetamos el separador creado al principio de main() en
1398 * la vbox (caja1). */
1399 gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
1400 gtk_widget_show (separator);
1403 /* Creamos otra hbox... recordar que podemos crear tantas como
1405 quitbox = gtk_hbox_new (FALSE, 0);
1407 /* El botón de salida. */
1408 boton = gtk_button_new_with_label ("Quit");
1410 /* Establecemos la señal de destrucción de la ventana.
1411 * Recuerde que emitirá la señal de "destroy" que a su vez
1412 * será procesada por el controlador de señales, tal y como
1413 * ya hemos visto. */
1415 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
1416 GTK_SIGNAL_FUNC (gtk_main_quit),
1417 GTK_OBJECT (ventana));
1418 /* Empaquetamos el botón en la caja de salida (quitbox).
1419 * los tres últimos argumentos de gtk_box_pack_start
1420 * son:expand, fill, padding. */
1421 gtk_box_pack_start (GTK_BOX (caja1), quitbox, FALSE, FALSE, 0);
1423 /* empaquetamos la vbox (caja1) que ya contiene todos los widgets
1424 * en la ventana principal. */
1425 gtk_container_add (GTK_CONTAINER (ventana), caja1);
1427 /* mostramos todo aquello que faltaba por mostrar */
1428 gtk_widget_show (boton);
1429 gtk_widget_show (quitbox);
1431 gtk_widget_show (caja1);
1433 /* Si mostramos la ventana lo último todo aparece de golpe. */
1434 gtk_widget_show (ventana);
1436 /* por supuesto tenemos una función main. */
1439 /* El programa llega aquí cuando se llama a gtk_main_quit(),
1440 * pero no cuando se llama a gtk_exit(). */
1443 /* final del ejemplo*/
1446 <!-- ----------------------------------------------------------------- -->
1447 <sect1>Empaquetamiento usando tablas
1449 Existe otra forma de empaquetar: usando tablas. Estas pueden llegar a
1450 ser extremadamente útiles.
1452 Usando tablas creamos una cuadrícula donde podemos poner los
1453 widgets. Estos pueden ocupar tanto espacio como queramos.
1455 La primera función que conviene estudiar es gtk_table_new:
1458 GtkWidget *gtk_table_new( gint rows,
1463 Como es lógico el primer argumento es el número de filas y el
1464 segundo el de columnas.
1466 El tercero establece el tamaño de las celdas de la tabla. Si es TRUE
1467 se fuerza a que el tamaño de las celdas sea igual al de la celda
1468 mayor. Con FALSE se establece el ancho de toda una columna igual al de
1469 la celda más ancha de esa columna, y la altura de una fila será
1470 la de la celda más alta de esa fila.
1472 El número de filas y columnas varía entre 0 y n, donde n es el
1473 número especificado en la llamada a gtk_table_new. Así si se
1474 especifica columnas = 2 y filas = 2 la apariencia será parecida a:
1478 0+----------+----------+
1480 1+----------+----------+
1482 2+----------+----------+
1485 Conviene destacar que el origen de coordenadas se sitúa en la esquina superior izquierda. Para
1486 situar un widget en una ventana se usa la siguiente función:
1489 void gtk_table_attach( GtkTable *table,
1501 El primer argumento (<tt/table/) es el nombre de la tabla y el segundo
1502 (<tt/hijo/) el <em/widget/ que quiere poner en la tabla.
1504 Los argumentos <tt/left_attach/, <tt/right_attach/ especifican donde
1505 se pone el widget y cuantas cajas se usan. Por ejemplo, supongamos que
1506 queremos poner un botón que sólo ocupe la esquina inferior
1507 izquierda en nuestra tabla 2x2. Los valores serán left_attach = 1,
1508 right_attach = 2, top_attach = 2, top_attach = 1, bottom_attach = 2.
1510 Supongamos que queremos ocupar toda la fila de nuestra tabla 2x2,
1511 usaríamos left_attach = 0, right_attach = 2, top_attach = 0,
1514 Las opciones <tt/xoptions/ e <tt/yoptions/ son usadas para especificar
1515 como queremos el empaquetamiento y podemos utilizar multiples
1516 opciones simultaneamente con OR.
1521 <item>GTK_FILL - Si el relleno es más grande que el widget, y se
1522 especifica GTK_FILL, el <em/widget/ se expandirá ocupando todo el
1525 <item>GTK_SHRINK - En el caso de que hayamos dejado espacio sin usar
1526 cuando el usuario reajuste el tamaño de la ventana los <em/widgets/
1527 normalmente serán empujados al fondo de la ventana y
1528 desaparecerán. Si especifica GTK_SHRINK los widgets se reducirán
1531 <item>GTK_EXPAND - Mediante esta opción la tabla se expande usando
1532 todo el espacio libre de la ventana.
1535 El relleno es igual que con las cajas. Simplemente se crea una zona
1536 vacía alrededor del widget (el tamaño se especifica en pixels).
1538 gtk_table_attach() tiene MUCHAS opciones. Asi que hay un atajo:
1541 void gtk_table_attach_defaults( GtkTable *table,
1546 gint bottom_attach );
1549 Las opciones X e Y se ponen por defecto a GTK_FILL | GTK_EXPAND, y el
1550 relleno X e Y se pone a 0. El resto de los argumentos son identicos a
1551 la función anterior.
1553 Existen otras funciones como gtk_table_set_row_spacing() y
1554 gtk_table_set_col_spacing(), que sirven para especificar el espaciado
1555 entre las columnas/filas en la columna/fila que queramos.
1558 void gtk_table_set_row_spacing( GtkTable *table,
1566 void gtk_table_set_col_spacing ( GtkTable *table,
1571 Conviene destacar que el espaciado se sitúa a la derecha de la
1572 columna y debajo de la fila.
1574 Tambien se puede forzar que el espaciado sea el mismo para las filas
1578 void gtk_table_set_row_spacings( GtkTable *table,
1585 void gtk_table_set_col_spacings( GtkTable *table,
1589 Usando estas funciones las últimas fila y columna no estarán
1592 <!-- ----------------------------------------------------------------- -->
1593 <sect1>Ejemplo de empaquetamiento mediante tablas.
1595 Haremos una ventana con tres botones en una tabla 2x2. Los dos
1596 primeros botones ocuparán la fila de arriba, mientras que el
1597 tercero (de salida) ocupará toda la fila de abajo. El resultado es
1602 <IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10"
1603 ALT="Imagen de ejemplo sobre el empaquetado mediante tablas" WIDTH="180" HEIGHT="120">
1609 /* principio del ejemplo table table.c */
1611 #include <gtk/gtk.h>
1613 /* La respuesta, que además se imprime en stdout. */
1614 void callback (GtkWidget *widget, gpointer data)
1616 g_print ("Hello again - %s was pressed\n", (char *) data);
1619 /* Con esta otra respuesta terminamos el programa. */
1620 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
1625 int main (int argc, char *argv[])
1631 gtk_init (&argc, &argv);
1633 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1635 gtk_window_set_title (GTK_WINDOW (ventana), "Table");
1637 gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
1638 GTK_SIGNAL_FUNC (delete_event), NULL);
1640 gtk_container_border_width (GTK_CONTAINER (ventana), 20);
1642 table = gtk_table_new (2, 2, TRUE);
1644 gtk_container_add (GTK_CONTAINER (ventana), table);
1646 boton = gtk_button_new_with_label ("botón 1");
1648 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
1649 GTK_SIGNAL_FUNC (callback), (gpointer) "botón 1");
1651 gtk_table_attach_defaults (GTK_TABLE(table), boton, 0, 1, 0, 1);
1653 gtk_widget_show (boton);
1655 boton = gtk_button_new_with_label ("botón 2");
1657 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
1658 GTK_SIGNAL_FUNC (callback), (gpointer) "botón 2");
1659 gtk_table_attach_defaults (GTK_TABLE(table), boton, 1, 2, 0, 1);
1661 gtk_widget_show (boton);
1663 boton = gtk_button_new_with_label ("Quit");
1665 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
1666 GTK_SIGNAL_FUNC (delete_event), NULL);
1667 gtk_table_attach_defaults (GTK_TABLE(table), boton, 0, 2, 1, 2);
1669 gtk_widget_show (boton);
1671 gtk_widget_show (table);
1672 gtk_widget_show (ventana);
1678 /* final del ejemplo */
1681 <!-- ***************************************************************** -->
1682 <sect>Estudio general de los <em/widgets/
1683 <!-- ***************************************************************** -->
1685 Los pasos generales a la hora de crear un <em/widget/ son:
1689 <item> Usar gtk_*_new - Una de las diferentes formas de crear un
1690 <em/widget/. (Todas serán explicadas en esta sección).
1692 <item> Connectar todas las señales y los eventos a los
1693 controladores apropiados.
1695 <item> Establecer los atributos del <em/widget/.
1697 <item> Empaquetar el <em/widget/ en un contenedor usando las llamadas
1698 apropiadas, como gtk_container_add() o gtk_box_pack_start().
1700 <item> Mostrar el <em/widget/ usando gtk_widget_show().
1704 Mediante esta última llamada GTK `sabe' que hemos acabado de
1705 establecer los atributos del <em/widget/, y que por lo tanto puede
1706 mostrarse. Se puede usar gtk_widget_hide para hacer que desaparezca.
1707 El orden en el que se muestran los <em/widgets/ no es importante, pero
1708 se recomienda mostrar al final la ventana para que todo aparezca de
1709 golpe. El hijo de un <em/widget/ no se muestra hasta que lo hace la
1710 propia ventana (que en este caso es un <em/widget/ padre) mediante
1714 <!-- ----------------------------------------------------------------- -->
1715 <sect1> Conversión de tipos
1717 GTK usa un sistema de conversión de tipos mediante macros que
1718 comprueban si se puede realizar la conversión y en caso
1719 afirmativo la hacen. Las más comunes son:
1722 <item> GTK_WIDGET(widget)
1723 <item> GTK_OBJECT(object)
1724 <item> GTK_SIGNAL_FUNC(function)
1725 <item> GTK_CONTAINER(container)
1726 <item> GTK_WINDOW(ventana)
1730 Todas son usadas para cambiar de tipo los argumentos de una función.
1731 Aparecerán mucho en los ejemplos, para usarlas sólo hay que mirar la
1732 declaración de la función.
1734 Tal y como se puede ver en el árbol de clases (situado un poco
1735 más adelante) todos los <em/widgets/ derivan de la clase base
1736 GtkObject. Esto significa que siempre se puede usar un <em/widget/
1737 como argumento de una función (que acepte un objeto, claro)
1738 realizando la conversión de tipo GTK_OBJECT().
1743 gtk_signal_connect( GTK_OBJECT(boton), "clicked",
1744 GTK_SIGNAL_FUNC(callback_function), callback_data);
1747 Hemos hecho que el botón pase a ser un objeto y que se cambie el
1748 puntero a la función a una función respuesta.
1750 Muchos <em/widgets/ son contenedores, por lo que unos pueden derivar
1751 de otros (la mayoría lo hace de GtkContainer). Cualquiera puede ser
1752 usado junto con la macro GTK_CONTAINER como argumento a funciones en
1755 Desgraciadamente estas macros no son descritas en detalle en el
1756 tutorial, por lo que se recomienda echar un vistazo a los archivos de
1757 cabecera de GTK. En la práctica es posible aprender a manejar un
1758 <em/widget/ leyendo las declaraciones de las funciones.
1760 <!-- ----------------------------------------------------------------- -->
1761 <sect1>Árbol formado por los <em/widgets/
1763 A continuación se detallan todas las ramas del árbol que forman
1771 | | | +GtkAccelLabel
1780 | | | | `GtkAspectFrame
1782 | | | | +GtkToggleButton
1783 | | | | | `GtkCheckButton
1784 | | | | | `GtkRadioButton
1785 | | | | `GtkOptionMenu
1787 | | | | +GtkMenuItem
1788 | | | | | +GtkCheckMenuItem
1789 | | | | | | `GtkRadioMenuItem
1790 | | | | | `GtkTearoffMenuItem
1791 | | | | +GtkListItem
1792 | | | | `GtkTreeItem
1794 | | | | +GtkColorSelectionDialog
1796 | | | | | `GtkInputDialog
1797 | | | | +GtkDrawWindow
1798 | | | | +GtkFileSelection
1799 | | | | +GtkFontSelectionDialog
1803 | | | +GtkScrolledWindow
1807 | | | | +GtkHButtonBox
1808 | | | | `GtkVButtonBox
1810 | | | | +GtkColorSelection
1811 | | | | `GtkGammaCurve
1819 | | | `GtkFontSelection
1838 | | | `GtkSpinButton
1862 <!-- ----------------------------------------------------------------- -->
1863 <sect1><em/Widgets/ sin ventanas
1865 Los siguientes <em/widgets/ no tienen ventanas asociadas. Si se
1866 quieren capturar eventos se tendrá que utilizar GtkEventBox. En la
1867 sección <ref id="sec_The_EventBox_Widget" name="El widget
1868 EventBox"> se pueden encontrar más detalles sobre su uso.
1890 Vamos a continuar la explicación describiendo cada uno de los
1891 <em/widgets/ mediante ejemplos. También se puede consultar el
1892 programa testgtk.c (Se encuentra en gtk/testgtk.c).
1894 <!-- ***************************************************************** -->
1895 <sect>El <em/widget/ Botón
1896 <!-- ***************************************************************** -->
1898 <!-- ----------------------------------------------------------------- -->
1899 <sect1>Botones normales <label id="sec_Radio_Buttons">
1901 Ya hemos visto prácticamente todo lo que hay que saber a cerca de
1902 este <em/widget/. Existen dos formas diferentes de crear un
1903 botón. Se puede usar gtk_button_new_with_label() para conseguir un
1904 botón con etiqueta o simplemente gtk_button_new(). Si se quiere se
1905 puede añadir una etiqueta a este último empaquetándola,
1906 primero se crea una nueva caja y luego se empaquetan los objetos que
1907 se quieran mediante gtk_box_pack_start. Una vez finalizado esto se
1908 relaciona la caja con el botón mediante gtk_container_add.
1910 Estudiemos un ejemplo de gtk_button_new para crear un botón con una
1911 imagen y una etiqueta. El código está dividido en dos para que
1915 /* principio del ejemplo buttons buttons.c */
1917 #include <gtk/gtk.h>
1919 /* Creamos la caja con una imagen y una etiqueta empaquetadas. Se
1920 * devuelve la caja. */
1921 GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
1924 GtkWidget *etiqueta;
1925 GtkWidget *pixmapwid;
1930 /* create box for xpm and etiqueta */
1931 caja1 = gtk_hbox_new (FALSE, 0);
1932 gtk_container_border_width (GTK_CONTAINER (caja1), 2);
1934 /* obtenemos el estilo del botón (probablemente para el color
1935 * de fondo, pero no estoy seguro) */
1936 style = gtk_widget_get_style(parent);
1938 /* cargamos el pixmap. Hay una sección que describe el proceso
1940 pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
1941 &style->bg[GTK_STATE_NORMAL],
1943 pixmapwid = gtk_pixmap_new (pixmap, mask);
1945 etiqueta = gtk_label_new (label_text);
1947 gtk_box_pack_start (GTK_BOX (caja1),
1948 pixmapwid, FALSE, FALSE, 3);
1950 gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 3);
1952 gtk_widget_show(pixmapwid);
1953 gtk_widget_show(etiqueta);
1959 void callback (GtkWidget *widget, gpointer data)
1961 g_print ("Hola de nuevo. Se ha pulsado %s\n", (char *) data);
1965 int main (int argc, char *argv[])
1972 gtk_init (&argc, &argv);
1974 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1976 gtk_window_set_title (GTK_WINDOW (ventana), "Botones con dibujos");
1978 /* It's a good idea to do this for all windows. */
1979 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
1980 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1982 gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
1983 GTK_SIGNAL_FUNC (gtk_exit), NULL);
1985 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
1986 gtk_widget_realize(ventana);
1988 boton = gtk_button_new ();
1990 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
1991 GTK_SIGNAL_FUNC (callback),
1992 (gpointer) "botón divertido");
1994 caja1 = xpm_label_box(ventana, "info.xpm", "botón divertido");
1996 gtk_widget_show(caja1);
1998 gtk_container_add (GTK_CONTAINER (boton), caja1);
2000 gtk_widget_show(boton);
2002 gtk_container_add (GTK_CONTAINER (ventana), boton);
2004 gtk_widget_show (ventana);
2010 /* final del ejemplo */
2013 La función xpm_label_box puede ser usada para empaquetar xpm y
2014 etiquetas en cualquier widget que pueda ser un contenedor.
2016 El botón puede responder a las siguientes señales:
2026 <!-- ----------------------------------------------------------------- -->
2027 <sect1> Botones de selección
2029 Estos botones son muy similares a los normales. La única diferencia
2030 es que sólo pueden estar en dos posiciones diferentes alternadas
2031 mediante pulsaciones del ratón.
2033 Los botones de selección son la base de otros tipos: los de
2034 comprobación y los circulares. Por lo tanto muchas de sus llamadas
2035 seran heredadas por estos.
2037 Creamos un nuevo botón de selección:
2040 GtkWidget *gtk_toggle_button_new( void );
2042 GtkWidget *gtk_toggle_button_new_with_label( gchar *etiqueta );
2045 Como se ha podido imaginar estas funciones son iguales a las de un
2046 botón normal. La primera crea un botón, mientras que la segunda
2047 crea un botón con una etiqueta.
2049 Para saber cual es el estado de un botón de selección,
2050 comprobación o circular se usa una de las macros del ejemplo
2051 siguiente. En éstas se comprueba el estado del botón mediante
2052 una respuesta. La señal que queremos recibir es
2053 «toggled». Generalmente para comprobar el estado de una señal se
2054 establece un controlador de señales y luego se usa la siguiente
2055 macro. La función de respuesta debe ser de la forma:
2058 void toggle_button_callback (GtkWidget *widget, gpointer data)
2060 if (GTK_TOGGLE_BUTTON (widget)->active)
2062 /* Si el control llega aquí el botón está pulsado */
2066 /* El botón no está pulsado (sobresale) */
2072 void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
2076 La llamada de arriba puede ser usada para establecer el estado de un
2077 botón de selección (o de cualquiera de sus hijos: el circular o
2078 el de comprobación). El primer argumento es el botón, el segundo
2079 TRUE cuando queremos que el botón no esté pulsado o FALSE para
2080 cuando lo esté. Por defecto se establece FALSE.
2082 Hay que destacar que cuando se usa gtk_toggle_button_set_state() y se
2083 cambia el estado del botón este emite la señal «clicked».
2086 void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
2089 Cambia el estado del botón emitiendo la señal «toggled».
2090 <!-- ----------------------------------------------------------------- -->
2091 <sect1> Botones de comprobación
2093 Los botones de comprobación son un poco diferentes a los anteriores, aunque
2094 sus propiedades y funciones son bastante similares. En lugar de ser botones
2095 con texto en su interior son pequeños cuadrados con texto a su derecha.
2096 Normalmente son usados para (des)seleccionar opciones.
2098 Las dos funciones que los crean son muy similares a las de los botones
2102 GtkWidget *gtk_check_button_new( void );
2104 GtkWidget *gtk_check_button_new_with_label ( gchar *etiqueta );
2107 La función new_with_label crea un botón de comprobación con
2108 una etiqueta dentro.
2110 El proceso para comprobar el estado de un botón de este tipo es
2111 igual al de los de comprobación.
2113 <!-- ----------------------------------------------------------------- -->
2114 <sect1> Botones circulares
2116 Estos botones son similares a los de selección con la salvedad de
2117 que están agrupados, de modo que sólo uno puede estar
2118 seleccionado. Por tanto son usados para permitir al usuario
2119 seleccionar algo de una lista de opciones mutuamente excluyentes.
2121 Las llamadas para crear un botón circular son:
2123 GtkWidget *gtk_radio_button_new( GSList *group );
2125 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2129 El nuevo argumento sirve para especificar el grupo al que
2130 pertenecen. La primera llamada debe pasar NULL como primer
2131 argumento. A continuación de ésta se puede crear el grupo
2135 GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
2138 Para añadir un nuevo botón a un grupo hay que usar
2139 gtk_radio_button_group con el anterior botón como argumento. El
2140 resultado se le pasa a gtk_radio_button_new o a
2141 gtk_radio_button_new_with_label. Así se consigue enlazar una cadena
2142 de botones. (El ejemplo siguiente sirve para aclarar el proceso)
2144 También se puede establecer cúal es el botón pulsado por
2148 void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
2151 El siguiente ejemplo crea un grupo de tres botones:
2154 /* Principio del ejemplo radiobuttons.c */
2156 #include <gtk/gtk.h>
2159 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
2163 main(int argc,char *argv[])
2165 static GtkWidget *ventana = NULL;
2169 GtkWidget *separator;
2172 gtk_init(&argc,&argv);
2173 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2175 gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
2176 GTK_SIGNAL_FUNC(close_application),
2179 gtk_window_set_title (GTK_WINDOW (ventana), "radio buttons");
2180 gtk_container_border_width (GTK_CONTAINER (ventana), 0);
2182 caja1 = gtk_vbox_new (FALSE, 0);
2183 gtk_container_add (GTK_CONTAINER (ventana), caja1);
2184 gtk_widget_show (caja1);
2186 caja2 = gtk_vbox_new (FALSE, 10);
2187 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2188 gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2189 gtk_widget_show (caja2);
2191 boton = gtk_radio_button_new_with_label (NULL, "botón1");
2192 gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2193 gtk_widget_show (boton);
2195 group = gtk_radio_button_group (GTK_RADIO_BUTTON (boton));
2196 boton = gtk_radio_button_new_with_label(group, "botón2");
2197 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (boton), TRUE);
2198 gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2199 gtk_widget_show (boton);
2201 group = gtk_radio_button_group (GTK_RADIO_BUTTON (boton));
2202 boton = gtk_radio_button_new_with_label(group, "botón3");
2203 gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2204 gtk_widget_show (boton);
2206 separator = gtk_hseparator_new ();
2207 gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 0);
2208 gtk_widget_show (separator);
2210 caja2 = gtk_vbox_new (FALSE, 10);
2211 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2212 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, TRUE, 0);
2213 gtk_widget_show (caja2);
2215 boton = gtk_button_new_with_label ("close");
2216 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
2217 GTK_SIGNAL_FUNC(close_application),
2218 GTK_OBJECT (ventana));
2219 gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2220 GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
2221 gtk_widget_grab_default (boton);
2222 gtk_widget_show (boton);
2223 gtk_widget_show (ventana);
2228 /* final del ejemplo */
2231 <!-- TODO: checout out gtk_radio_button_new_from_widget function - TRG -->
2233 <!-- ***************************************************************** -->
2234 <sect>Ajustes (<em/Adjustment/) <label id="sec_Adjustment">
2235 <!-- ***************************************************************** -->
2237 Existen diferentes <em/widgets/ en GTK+ que pueden ser ajustados
2238 visualmente por el usuario mediante el ratón o el teclado. Un
2239 ejemplo son los <em/widgets/ de selección descritos en la
2240 sección <ref id="sec_Range_Widgets" name="Widgets de selección
2241 de rango">. También hay otros widgets que pueden ser ajustados
2242 parcialmente, por ejemplo el <em/widget/ de texto o el <em/viewport/.
2244 Como es lógico el programa tiene que poder reaccionar a los
2245 cambios que el usuario realiza en los <em/widgets/ de selección de
2246 rango. Una forma de hacer que el programa reaccione sería tener
2247 cada <em/widget/ emitiendo su propio tipo de señal cuando cambie el
2248 ajuste, y bien pasar el nuevo valor al manejador de señal o bien
2249 obligarle a que mire dentro de la estructura de datos del <em/widget/
2250 para conocer este valor. Pero también puede ser que quiera conectar
2251 los ajustes de varios <em/widgets/, para que así cuando se ajuste
2252 uno, los demás se ajusten automáticamente. El ejemplo más
2253 obvio es conectar una barra de desplazamiento a una región con
2254 texto. Si cada <em/widget/ posee su propia forma de establecer u
2255 obtener sus valores de ajuste el programador puede que tenga que
2256 escribir sus propios controladores de señales para traducir el
2257 resultado de la señal producida por un <em/widget/ como el
2258 argumento de una función usada para determinar valores en otro
2261 Para resolver este problema GTK+ usa objetos del tipo GtkAdjustment.
2262 Con ellos se consigue almacenar y traspasar información de una forma
2263 abstracta y flexible. El uso más obvio es el de almacenes de
2264 párametros para <em/widgets/ de escala (barras deslizantes y
2265 escalas). Como los GtkAdjustment derivan de GtkObject poseen
2266 cualidades intrínsecas que les permiten ser algo más que simples
2267 estructuras de datos. Lo más importante es que pueden emitir
2268 señales que a su vez pueden ser usadas tanto para reaccionar frente
2269 al cambio de datos introducidos por el usuario como para transferir
2270 los nuevos valores de forma transparente entre <em/widgets/ ajustables.
2272 <sect1>Creando un ajuste
2274 Los ajustes se pueden crear usando:
2277 GtkObject *gtk_adjustment_new( gfloat value,
2280 gfloat step_increment,
2281 gfloat page_increment,
2285 El argumento <tt/value/ es el valor inicial que le queremos dar
2286 al ajuste. Normalmente se corresponde con las posiciones situadas
2287 más arriba y a la izquierda de un <em/widget/ ajustable. El argumento
2288 <tt/lower/ especifica los valores más pequeños que el ajuste
2289 puede contener. A su vez con <tt/step_increment/ se especifica el
2290 valor más pequeño en el que se puede variar la magnitud en
2291 cuestión (valor de paso asociado), mientras que <tt/page_increment/
2292 es el mayor. Con <tt/page_size/ se determina el valor visible de un
2295 <!-- ----------------------------------------------------------------- -->
2296 <sect1> Forma sencilla de usar los ajustes
2298 Los <em/widgets/ ajustábles se pueden dividir en dos categorias
2299 diferentes, aquellos que necesitan saber las unidades de la cantidad
2300 almacenada y los que no. Este último grupo incluye los <em/widgets/
2301 de tamaño (barras deslizantes, escalas, barras de estado, o botones
2302 giratorios). Normalmente estos <em/widgets/ son ajustados
2303 «directamente» por el usuario. Los argumentos <tt/lower/ y
2304 <tt/upper/ serán los limites dentro de los cuales el usuario puede
2305 manipular los ajustes. Por defecto sólo se modificará el
2306 <tt/value/ (valor) de un ajuste.
2308 El otro grupo incluye los <em/widgets/ de texto, la lista compuesta o
2309 la ventana con barra deslizante. Estos <em/widgets/ usan valores en
2310 pixels para sus ajustes, y normalmente son ajustados
2311 «indirectamente» mediante barras deslizantes. Aunque todos los
2312 <em/widgets/ pueden crear sus propios ajustes o usar otros creados por
2313 el programador con el segundo grupo suele ser conveniente dejarles que
2314 creen sus propios ajustes. Normalmente no tendrán en cuenta ninguno
2315 de los valores de un ajuste proporcionado por el programador, excepto
2316 <tt/value/, pero los resultados son, en general, indefinidos
2317 (entiendase que tendrá que leer el código fuente para saber que
2318 pasa con cada widget).
2320 Probablemente ya se habrá dado cuenta de que como los <em/widgets/
2321 de texto (y todos los <em/widgets/ del segundo grupo), insisten en
2322 establecer todos los valores excepto <tt/value/, mientras que las
2323 barras deslizantes sólo modifican <tt/value/, si se comparte un
2324 objeto de ajuste entre una barra deslizante y un <em/widget/ de texto
2325 al manipular la barra se modificará el <em/widget/ de texto. Ahora
2326 queda completamente demostrada la utilidad de los ajustes. Veamos un
2330 /* creamos un ajuste */
2331 text = gtk_text_new (NULL, NULL);
2332 /* lo usamos con la barra deslizante */
2333 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
2337 <!-- ----------------------------------------------------------------- -->
2338 <sect1> Descripción detallada de los ajustes
2340 Puede que se esté preguntando cómo es posible crear sus propios
2341 controladores para responder a las modificaciones producidas por
2342 el usuario y cómo obtener el valor del ajuste hecho por este.
2343 Para aclarar esto y otras cosas vamos a estudiar la estructura
2347 struct _GtkAdjustment
2354 gfloat step_increment;
2355 gfloat page_increment;
2360 Lo primero que hay que aclarar es que no hay ninguna macro o función
2361 de acceso que permita obtener el <tt/value/ de un GtkAdjustment, por
2362 lo que tendrá que hacerlo usted mismo. Tampoco se preocupe mucho
2363 porque la macro <tt>GTK_ADJUSTMENT (Object)</tt> comprueba los tipos
2364 durante el proceso de ejecución (como hacen todas las macros de GTK+
2365 que sirven para comprobar los tipos).
2367 Cuando se establece el <tt/value/ de un ajuste normalmente se quiere
2368 que cualquier <em/widget/ se entere del cambio producido. Para ello
2369 GTK+ posee una función especial:
2372 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2376 Tal y como se mencionó antes GtkAdjustment es una subclase de GtkObject
2377 y por tanto puede emitir señales. Así se consigue que se actualicen
2378 los valores de los ajustes cuando se comparten entre varios <em/widgets/.
2379 Por tanto todos los <em/widgets/ ajustables deben conectar controladores
2380 de señales a sus señales del tipo <tt/value_changed/. Esta es la
2381 definición de la señal como viene en <tt/struct _GtkAdjustmentClass/
2384 void (* value_changed) (GtkAdjustment *adjustment);
2387 Todos los <em/widgets/ que usan GtkAdjustment deben emitir esta
2388 señal cuando cambie el valor de algún ajuste. Esto sucede cuando
2389 el usuario cambia algo o el programa modifica los ajustes
2390 mediante. Por ejemplo si queremos que rote una figura cuando
2391 modificamos un <em/widget/ de escala habría que usar una respuesta
2395 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2397 set_picture_rotation (picture, adj->value);
2401 y conectarla con el ajuste del <em/widget/ de escala mediante:
2404 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
2405 GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
2407 ¿Qué pasa cuando un <em/widget/ reconfigura los valores
2408 <tt/upper/ o <tt/lower/ (por ejemplo cuando se añade más texto)?
2409 Simplemente que se emite la señal <tt/changed/, que debe ser
2413 void (* changed) (GtkAdjustment *adjustment);
2416 Los <em/widgets/ de tamaño normalmente conectan un controlador a
2417 esta señal, que cambia el aspecto de éste para reflejar el
2418 cambio. Por ejemplo el tamaño de la guía en una barra deslizante
2419 que se alarga o encoge según la inversa de la diferencia de los
2420 valores <tt/lower/ y <tt/upper/.
2422 Probablemente nunca tenga que conectar un controlador a esta señal
2423 a no ser que esté escribiendo un nuevo tipo de <em/widget/. Pero si
2424 cambia directamente alguno de los valores de GtkAdjustment debe hacer
2425 que se emita la siguiente señal para reconfigurar todos aquellos
2426 <em/widgets/ que usen ese ajuste:
2429 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2434 <!-- ***************************************************************** -->
2435 <sect>Los <em/widgets/ de selección de rango <label id="sec_Range_Widgets">
2436 <!-- ***************************************************************** -->
2438 Este tipo de <em/widgets/ incluye a las barras de desplazamiento
2439 (<em>scroollbar</em>) y la menos conocida escala
2440 (<em/scale</em>). Ambos pueden ser usados para muchas cosas, pero como
2441 sus funciones y su implementación son muy parecidas los describimos
2442 al mismo tiempo. Principalmente se utilizan para permitirle al usuario
2443 escoger un valor dentro de un rango ya prefijado.
2445 Todos los <em/widgets/ de selección comparten elementos
2446 gráficos, cada uno de los cuales tiene su propia ventana X window y
2447 recibe eventos. Todos contienen una guía y un rectángulo para
2448 determinar la posición dentro de la guía (en una procesador de
2449 textos con entorno gráfico se encuentra situado a la derecha del
2450 texto y sirve para situarnos en las diferentes partes del texto). Con
2451 el ratón podemos subir o bajar el rectángulo, mientras que si
2452 hacemos `click' dentro de la guía, pero no sobre el rectángulo,
2453 este se mueve hacia donde hemos hecho el click. Dependiendo del
2454 botón pulsado el rectángulo se moverá hasta la posición
2455 del click o una cantidad prefijada de ante mano.
2457 Tal y como se mencionó en <ref id="sec_Adjustment" name="Ajustes">
2458 todos los <em/widgets/ usados para seleccionar un rango estan
2459 asociados con un objeto de ajuste, a partir del cual calculan la
2460 longitud de la barra y su posición. Cuando el usuario manipula la
2461 barra de desplazamiento el widget cambiará el valor del ajuste.
2463 <sect1>El <em/widget/ barra de desplazamiento
2465 El <em/widget/ barra de desplazamiento solamente debe utilizarse para
2466 hacer <em/scroll/ sobre otro <em/widget/, como una lista, una caja de
2467 texto, o un puerto de visión (y en muchos es más fácil utilizar
2468 el <em/widget/ scrolled window). Para el resto de los casos, debería
2469 utilizar los <em/widgets/ de escala, ya son más sencillos de usar y
2472 Hay dos tipos separados de barras de desplazamiento, según sea
2473 horizontal o vertical. Realmente no hay mucho que añadir. Puede
2474 crear estos <em/widgets/ utilizar las funciones siguientes, definidas
2475 en <tt><gtk/gtkhscrollbar.h></tt> y
2476 <tt><gtk/gtkvscrollbar.h></tt>:
2479 GtkWidget* gtk_hscrollbar_new( GtkAdjustment *adjustment );
2481 GtkWidget* gtk_vscrollbar_new( GtkAdjustment *adjustment );
2484 y esto es todo lo que hay (si no me cree, ¡mire los ficheros de
2485 cabecera!). El argumento <tt/adjustment/ puede ser un puntero a un
2486 ajuste ya existente, o puede ser NULL, en cuyo caso se creará
2487 uno. Es útil especificar NULL si quiere pasar el ajuste recién
2488 creado a la función constructora de algún otro <em/widget/ (como
2489 por ejemplo el <em/widget/ texto) que se ocupará de configurarlo
2490 correctamente por usted.
2492 <!-- ----------------------------------------------------------------- -->
2493 <sect1><em/Widgets/ de escala
2495 Los <em/widgets/ de escala se usan para determinar el valor de una
2496 cantidad que se puede interpretar visualmente. El usuario
2497 probablemente fijará el valor a ojo. Por ejemplo el <em/widget/
2498 GtkColorSelection contiene <em/widgets/ de escala que controlan las
2499 componentes del color a seleccionar. Normalmente el valor preciso es
2500 menos importante que el efecto visual, por lo que el color se
2501 selecciona con el ratón y no mediante un número concreto.
2503 <!-- ----------------------------------------------------------------- -->
2504 <sect2>Creación de un <em/widget/ de escala
2506 Existen dos tipos de <em/widgets/ de escala: GtkHScale (que es
2507 horizontal) y GtkVscale (vertical). Como funcionan de la misma manera
2508 los vamos a describir a la vez. Las funciones definidas en
2509 <tt><gtk/gtkvscale.h></tt> y <tt><gtk/gtkhscale.h></tt>,
2510 crean <em/widgets/ de escala verticales y horizontales
2514 GtkWidget* gtk_vscale_new( GtkAdjustment *adjustment );
2516 GtkWidget* gtk_hscale_new( GtkAdjustment *adjustment );
2519 El <tt/ajuste/ (adjustment) puede ser tanto un ajuste creado
2520 mediante <tt/gtk_adjustment_new()/ como <tt/NULL/. En este
2521 último caso se crea un GtkAdjustment anónimo con todos sus
2522 valores iguales a <tt/0.0/. Si no ha quedado claro el uso de esta
2523 función consulte la sección <ref id="sec_Adjustment"
2524 name="Ajustes"> para una discusión más detallada.
2526 <!-- ----------------------------------------------------------------- -->
2527 <sect2> Funciones y señales
2529 Los <em/widgets/ de escala pueden indicar su valor actual como un
2530 número. Su comportamiento por defecto es mostrar este valor, pero
2531 se puede modificar usando:
2534 void gtk_scale_set_draw_value( GtkScale *scale,
2538 Los valores posibles de <tt/draw_value son/ son <tt/TRUE/ o <tt/FALSE/.
2539 Con el primero se muestra el valor y con el segundo no.
2541 El valor mostrado por un <em/widget/ de escala por defecto se redondea
2542 a un valor decimal (igual que con <tt/value/ en un GtkAdjustment). Se
2547 void gtk_scale_set_digits( GtkScale *scale,
2552 donde <tt/digits/ es el número de posiciones decimales que se
2553 quiera. En la práctica sólo se mostrarán 13 como máximo.
2555 Por último, el valor se puede dibujar en diferentes posiciones con
2556 respecto a la posición del rectangulo que hay dentro de la guía:
2560 void gtk_scale_set_value_pos( GtkScale *scale,
2561 GtkPositionType pos );
2565 Si ha leido la sección acerca del <em/widget/ libro de notas
2566 entonces ya conoce cuales son los valores posibles de <tt/pos/. Estan
2567 definidos en <tt><gtk/gtkscale.h></tt> como <tt/enum GtkPositionType/
2568 y son auto explicatorios. Si se escoge un lateral de la guía,
2569 entonces seguirá al rectángulo a lo largo de la guía.
2571 Todas las funcioenes precedentes se encuentran definidas en:
2572 <tt><gtk/gtkscale.h></tt>.
2576 <!-- ----------------------------------------------------------------- -->
2577 <sect1> Funciones comunes <label id="sec_funciones_range">
2579 La descripción interna de la clase GtkRange es bastante complicada,
2580 pero al igual que con el resto de las «clases base» sólo es
2581 interesante si se quiere «hackear». Casi todas las señales y
2582 funciones sólo son útiles para desarrollar derivados. Para un
2583 usuario normal las funciones interesantes son aquellas definidas en:
2584 <tt><gtk/gtkrange.h></tt> y funcionan igual en todos los
2585 <em/widgets/ de rango.
2587 <!-- ----------------------------------------------------------------- -->
2588 <sect2> Estableciendo cada cúanto se actualizan
2590 La política de actualización de un <em/widget/ define en que
2591 puntos de la interacción con el usuario debe cambiar el valor
2592 <tt/value/ en su GtkAdjustment y emitir la señal
2593 «value_changed». Las actualizaciones definidas en
2594 <tt><gtk/gtkenums.h></tt> como <tt>enum GtkUpdateType</tt>, son:
2597 <item>GTK_UPDATE_POLICY_CONTINUOUS - Este es el valor por defecto.La
2598 señal «value_changed» se emite continuamente, por ejemplo cuando
2599 la barra deslizante se mueve incluso aunque sea un poquito.
2601 <item>GTK_UPDATE_POLICY_DISCONTINUOUS - La señal «value_changed»
2602 sólo se emite cuando se ha parado de mover la barra y el usuario ha
2603 soltado el botón del ratón.
2605 <item>GTK_UPDATE_POLICY_DELAYED - La señal sólo se emite cuando
2606 el usuario suelta el botón del ratón o si la barra no se mueve
2607 durante un periodo largo de tiempo.
2611 Para establecer la política de actualización se usa la
2612 conversión definida en la macro
2615 void gtk_range_set_update_policy( GtkRange *range,
2616 GtkUpdateType policy) ;
2619 <!-- ----------------------------------------------------------------- -->
2620 <sect2>Obteniendo y estableciendo Ajustes
2622 Para obtener o establecer el ajuste de un <em/widget/ de rango se usa:
2625 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
2627 void gtk_range_set_adjustment( GtkRange *range,
2628 GtkAdjustment *adjustment );
2631 La función <tt/gtk_range_get_adjustment()/ devuelve un puntero al
2632 ajuste al que <tt/range/ esté conectado.
2634 La función <tt/gtk_range_set_adjustment()/ no hace nada si se le
2635 pasa como argumento el valor <tt/range/ del ajuste que esta siendo
2636 usado (aunque se haya modificado algún valor). En el caso de que
2637 sea un ajuste nuevo (GtkAdjustment) dejará de usar el antiguo
2638 (probablemente lo destruirá) y conectará las señales
2639 apropiadas al nuevo. A continuación llamará a la función
2640 <tt/gtk_range_adjustment_changed()/ que en teoría recalculará el
2641 tamaño y/o la posición de la barra, redibujándola en caso de
2642 que sea necesario. Tal y como se mencionó en la sección de los
2643 ajustes si se quiere reusar el mismo GtkAdjustment cuando se modifican
2644 sus valores se debe emitir la señal «changed». Por ejemplo:
2647 gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
2652 <!-- ----------------------------------------------------------------- -->
2653 <sect1> Enlaces con el teclado y el ratón
2655 Todos los <em/widgets/ de rango reaccionan más o menos de la misma
2656 manera a las pulsaciones del ratón. Al pulsar el botón 1 sobre
2657 el rectángulo de la barra el <tt/value/ del ajuste aumentará o
2658 disminuirá según <tt/page_increment/. Con el botón 2 la barra
2659 se desplazará al punto en el que el botón fue pulsado. Con cada
2660 pulsación de cualquier botón sobre las flechas el valor del
2661 ajuste se modifica una cantidad igual a <tt/step_increment/.
2664 Acostumbrarse a que tanto las barras deslizantes como los <em/widgets/ de
2665 escala puedan tomar la atención del teclado puede ser un proceso largo.
2666 Si que se cree que los usuarios no lo van a entender se puede anular
2667 mediante la función GTK_WIDGET_UNSET_FLAGS y con GTK_CAN_FOCUS como
2671 GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
2674 Los enlaces entre teclas (que sólo estan activos cuando el
2675 <em/widget/ tiene la atención (focus)) se comportan de manera
2676 diferente para los <em/widgets/ de rango horizontales que para los
2677 verticales. También son diferentes para los <em/widgets/ de escala
2678 y para las barras deslizantes. (Simplemente para evitar confusiones
2679 entre las teclas de las barras deslizantes horizontales y verticales,
2680 ya que ambas actúan sobre la misma área)
2682 <sect2><em/Widgets/ de rango vertical
2684 Todos los <em/widgets/ de rango pueden ser manipulados con las teclas
2685 arriba, abajo, <tt/Re Pág/, <tt/ Av Pág/. Las flechas mueven las
2686 barras la cantidad fijada mediante <tt/step_increment/, mientras que
2687 <tt/Re Pág/ y <tt/Av Pag/ lo hacen según <tt/page_increment/.
2689 El usuario también puede mover la barra de un extremo al otro de la
2690 guía mediante el teclado. Con el <em/widget/ GtkVScale podemos ir a
2691 los extremos utilizando las teclas <tt/Inicio/ y <tt/Final/ mientras
2692 que con el <em/widget/ GtkVScrollbar habrá que utilizar
2693 <tt/Control-Re Pág/ y <tt/Control-Av Pág/.
2695 <!-- ----------------------------------------------------------------- -->
2696 <sect2><em/Widgets/ de rango horizontal
2698 Las teclas izquierda y derecha funcionan tal y como espera que
2699 funcionen en estos <em/widgets/: mueven la barra una cantidad dada por
2700 <tt/step_increment/. A su vez <tt/Inicio/ y <tt/Final/ sirven para
2701 pasar de un extremo al otro de la guía. Para el <em/widget/
2702 GtkHScale el mover la barra una cantidad dada por <tt/page_increment/
2703 se consigue mediante <tt>Control-Izquierda</tt> y
2704 <tt>Control-derecha</tt>, mientras que para el <em/widget/
2705 GtkHScrollbar se consigue con <tt/Control-Inicio/ y
2710 <!-- ----------------------------------------------------------------- -->
2711 <sect1> Ejemplo <label id="sec_Ejemplo_Rango">
2713 Este ejemplo es una versión modificada del test «range controls»
2714 que a su vez forma parte de <tt/testgtk.c/. Simplemente dibuja una
2715 ventana con tres <em/widgets/ de rango conectados al mismo ajuste, y
2716 un conjunto de controles para ajustar algunos de los parámetros
2717 ya mencionados. Así se consigue ver como funcionan estos
2718 <em/widgets/ al ser manipulados por el usuario.
2721 /* principio del ejemplo widgets de selección de rango rangewidgets.c */
2723 #include <gtk/gtk.h>
2725 GtkWidget *hscale, *vscale;
2727 void cb_pos_menu_select( GtkWidget *item,
2728 GtkPositionType pos )
2730 /* Establece el valor position en los widgets de escala */
2731 gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
2732 gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
2735 void cb_update_menu_select( GtkWidget *item,
2736 GtkUpdateType policy )
2738 /* Establece la política de actualización para los widgets
2740 gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
2741 gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
2744 void cb_digits_scale( GtkAdjustment *adj )
2746 /* Establece el número de cifras decimales a las que se
2747 * redondeará adj->value */
2748 gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
2749 gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
2752 void cb_page_size( GtkAdjustment *get,
2753 GtkAdjustment *set )
2755 /* Establece el tamaño de la página y el incremento del
2756 * ajuste al valor especificado en la escala "Page Size" */
2757 set->page_size = get->value;
2758 set->page_increment = get->value;
2759 /* Ahora emite la señal "changed" para reconfigurar todos los
2760 * widgets que están enlazados a este ajuste */
2761 gtk_signal_emit_by_name (GTK_OBJECT (set), "changed");
2764 void cb_draw_value( GtkToggleButton *boton )
2766 /* Activa o desactiva el valor display en los widgets de escala
2767 * dependiendo del estado del botón de comprobación */
2768 gtk_scale_set_draw_value (GTK_SCALE (hscale), boton->active);
2769 gtk_scale_set_draw_value (GTK_SCALE (vscale), boton->active);
2772 /* Funciones varias */
2774 GtkWidget *make_menu_item( gchar *name,
2775 GtkSignalFunc callback,
2780 item = gtk_menu_item_new_with_label (name);
2781 gtk_signal_connect (GTK_OBJECT (item), "activate",
2783 gtk_widget_show (item);
2788 void scale_set_default_values( GtkScale *scale )
2790 gtk_range_set_update_policy (GTK_RANGE (scale),
2791 GTK_UPDATE_CONTINUOUS);
2792 gtk_scale_set_digits (scale, 1);
2793 gtk_scale_set_value_pos (scale, GTK_POS_TOP);
2794 gtk_scale_set_draw_value (scale, TRUE);
2797 /* crea la ventana principal */
2799 void create_range_controls( void )
2802 GtkWidget *caja1, *caja2, *caja3;
2804 GtkWidget *scrollbar;
2805 GtkWidget *separator;
2806 GtkWidget *opt, *menu, *item;
2807 GtkWidget *etiqueta;
2809 GtkObject *adj1, *adj2;
2811 /* creación estándar de una ventana */
2812 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2813 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
2814 GTK_SIGNAL_FUNC(gtk_main_quit),
2816 gtk_window_set_title (GTK_WINDOW (ventana), "range controls");
2818 caja1 = gtk_vbox_new (FALSE, 0);
2819 gtk_container_add (GTK_CONTAINER (ventana), caja1);
2820 gtk_widget_show (caja1);
2822 caja2 = gtk_hbox_new (FALSE, 10);
2823 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2824 gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2825 gtk_widget_show (caja2);
2827 /* value, lower, upper, step_increment, page_increment, page_size */
2828 /* Observe que el valor de page_size solo sirve para los widgets
2829 * barras de desplazamiento (scrollbar), y que el valor más
2830 * alto que obtendrá será (upper - page_size). */
2831 adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
2833 vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
2834 scale_set_default_values (GTK_SCALE (vscale));
2835 gtk_box_pack_start (GTK_BOX (caja2), vscale, TRUE, TRUE, 0);
2836 gtk_widget_show (vscale);
2838 caja3 = gtk_vbox_new (FALSE, 10);
2839 gtk_box_pack_start (GTK_BOX (caja2), caja3, TRUE, TRUE, 0);
2840 gtk_widget_show (caja3);
2842 /* Reutilizamos el mismo ajuste */
2843 hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
2844 gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30);
2845 scale_set_default_values (GTK_SCALE (hscale));
2846 gtk_box_pack_start (GTK_BOX (caja3), hscale, TRUE, TRUE, 0);
2847 gtk_widget_show (hscale);
2849 /* Reutilizamos de nuevo el mismo ajuste */
2850 scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
2851 /* Observe que con esto conseguimos que la escala siempre se
2852 * actualice de una forma continua cuando se mueva la barra de
2854 gtk_range_set_update_policy (GTK_RANGE (scrollbar),
2855 GTK_UPDATE_CONTINUOUS);
2856 gtk_box_pack_start (GTK_BOX (caja3), scrollbar, TRUE, TRUE, 0);
2857 gtk_widget_show (scrollbar);
2859 caja2 = gtk_hbox_new (FALSE, 10);
2860 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2861 gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2862 gtk_widget_show (caja2);
2864 /* Un botón para comprobar si el valor se muestra o no*/
2865 boton = gtk_check_button_new_with_label("Display value on scale widgets");
2866 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (boton), TRUE);
2867 gtk_signal_connect (GTK_OBJECT (boton), "toggled",
2868 GTK_SIGNAL_FUNC(cb_draw_value), NULL);
2869 gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2870 gtk_widget_show (boton);
2872 caja2 = gtk_hbox_new (FALSE, 10);
2873 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2875 /* Una opción en el menú para cambiar la posición del
2877 etiqueta = gtk_label_new ("Scale Value Position:");
2878 gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
2879 gtk_widget_show (etiqueta);
2881 opt = gtk_option_menu_new();
2882 menu = gtk_menu_new();
2884 item = make_menu_item ("Top",
2885 GTK_SIGNAL_FUNC(cb_pos_menu_select),
2886 GINT_TO_POINTER (GTK_POS_TOP));
2887 gtk_menu_append (GTK_MENU (menu), item);
2889 item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2890 GINT_TO_POINTER (GTK_POS_BOTTOM));
2891 gtk_menu_append (GTK_MENU (menu), item);
2893 item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2894 GINT_TO_POINTER (GTK_POS_LEFT));
2895 gtk_menu_append (GTK_MENU (menu), item);
2897 item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select),
2898 GINT_TO_POINTER (GTK_POS_RIGHT));
2899 gtk_menu_append (GTK_MENU (menu), item);
2901 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2902 gtk_box_pack_start (GTK_BOX (caja2), opt, TRUE, TRUE, 0);
2903 gtk_widget_show (opt);
2905 gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2906 gtk_widget_show (caja2);
2908 caja2 = gtk_hbox_new (FALSE, 10);
2909 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2911 /* Sí, otra opción de menú, esta vez para la política
2912 * de actualización de los widgets */
2913 etiqueta = gtk_label_new ("Scale Update Policy:");
2914 gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
2915 gtk_widget_show (etiqueta);
2917 opt = gtk_option_menu_new();
2918 menu = gtk_menu_new();
2920 item = make_menu_item ("Continuous",
2921 GTK_SIGNAL_FUNC (cb_update_menu_select),
2922 GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
2923 gtk_menu_append (GTK_MENU (menu), item);
2925 item = make_menu_item ("Discontinuous",
2926 GTK_SIGNAL_FUNC (cb_update_menu_select),
2927 GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
2928 gtk_menu_append (GTK_MENU (menu), item);
2930 item = make_menu_item ("Delayed",
2931 GTK_SIGNAL_FUNC (cb_update_menu_select),
2932 GINT_TO_POINTER (GTK_UPDATE_DELAYED));
2933 gtk_menu_append (GTK_MENU (menu), item);
2935 gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
2936 gtk_box_pack_start (GTK_BOX (caja2), opt, TRUE, TRUE, 0);
2937 gtk_widget_show (opt);
2939 gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2940 gtk_widget_show (caja2);
2942 caja2 = gtk_hbox_new (FALSE, 10);
2943 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2945 /* Un widget GtkHScale para ajustar el número de dígitos en
2947 etiqueta = gtk_label_new ("Scale Digits:");
2948 gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
2949 gtk_widget_show (etiqueta);
2951 adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
2952 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2953 GTK_SIGNAL_FUNC (cb_digits_scale), NULL);
2954 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2955 gtk_scale_set_digits (GTK_SCALE (scale), 0);
2956 gtk_box_pack_start (GTK_BOX (caja2), scale, TRUE, TRUE, 0);
2957 gtk_widget_show (scale);
2959 gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2960 gtk_widget_show (caja2);
2962 caja2 = gtk_hbox_new (FALSE, 10);
2963 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2965 /* Y un último widget GtkHScale para ajustar el tamaño de la
2966 * página de la barra de desplazamiento. */
2967 etiqueta = gtk_label_new ("Scrollbar Page Size:");
2968 gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
2969 gtk_widget_show (etiqueta);
2971 adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
2972 gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
2973 GTK_SIGNAL_FUNC (cb_page_size), adj1);
2974 scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
2975 gtk_scale_set_digits (GTK_SCALE (scale), 0);
2976 gtk_box_pack_start (GTK_BOX (caja2), scale, TRUE, TRUE, 0);
2977 gtk_widget_show (scale);
2979 gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
2980 gtk_widget_show (caja2);
2982 separator = gtk_hseparator_new ();
2983 gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 0);
2984 gtk_widget_show (separator);
2986 caja2 = gtk_vbox_new (FALSE, 10);
2987 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
2988 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, TRUE, 0);
2989 gtk_widget_show (caja2);
2991 boton = gtk_button_new_with_label ("Quit");
2992 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
2993 GTK_SIGNAL_FUNC(gtk_main_quit),
2995 gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
2996 GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
2997 gtk_widget_grab_default (boton);
2998 gtk_widget_show (boton);
3000 gtk_widget_show (ventana);
3006 gtk_init(&argc, &argv);
3008 create_range_controls();
3015 /* fin del ejemplo */
3018 Observe que el programa no llama a <tt/gtk_signal_connect/ para
3019 conectar el «delete_event», y que sólo conecta la señal
3020 «destroy». Con esto seguimos realizando la función deseada, ya que
3021 un «delete_event» no manejado desenboca en una señal «destroy»
3026 <!-- ***************************************************************** -->
3027 <sect><em/Widgets/ varios
3028 <!-- ***************************************************************** -->
3030 <!-- ----------------------------------------------------------------- -->
3033 Las etiquetas se usan mucho en GTK y son bastante simples de manejar.
3034 No pueden emitir señales ya que no tienen ventanas X window
3035 asociadas. Si se desea capturar señales se debe usar el <em/widget/
3036 EventBox o un <em/widget/ botón.
3038 Para crear una nueva etiqueta se usa:
3041 GtkWidget *gtk_label_new( char *str );
3044 El único argumento es la cadena de texto que se quiere mostrar.
3046 Para cambiarla después de que haya sido creada se usa:
3049 void gtk_label_set( GtkLabel *etiqueta,
3053 En este caso el primer argumento es la etiqueta ya creada (cambiado su
3054 tipo mediante la macro <tt/GTK_LABEL()/) y el segundo es la nueva cadena.
3055 El espacio que necesite la nueva etiqueta se ajustará
3056 automáticamente, si es necesario.
3058 Para obtener el estado de la cadena en un momento dado existe la
3062 void gtk_label_get( GtkLabel *etiqueta,
3065 El primer argumento es la etiqueta, mientras que el segundo es el
3066 valor devuelto para la cadena. No libere la memoria de la cadena
3067 devuelta, ya que se utiliza internamente por GTK.
3069 El texto de la etiqueta se puede justificar utilizando:
3072 void gtk_label_set_justify( GtkLabel *etiqueta,
3073 GtkJustification jtype );
3076 Los valores posibles para <tt/jtype/ son:
3078 <item> GTK_JUSTIFY_LEFT
3079 <item> GTK_JUSTIFY_RIGHT
3080 <item> GTK_JUSTIFY_CENTER (the default)
3081 <item> GTK_JUSTIFY_FILL
3084 El <em/widget/ etiqueta también es capaz de separar el texto de forma
3085 automática cuando se llega al final de una linea. Esto se puede
3086 conseguir utilizando:
3089 void gtk_label_set_line_wrap (GtkLabel *etiqueta,
3093 El argumento <tt/wrap/ toma el valor TRUE o FALSE.
3095 Si quiere que su etiqueta salga subrayada, puede especificar un motivo
3096 para el subrayado con:
3099 void gtk_label_set_pattern (GtkLabel *etiqueta,
3100 const gchar *pattern);
3103 El argumento <tt/pattern/ indica cual debe ser el aspecto del
3104 subrayado. Consiste en una cadena de espacios en blanco y carácteres
3105 de subrayado. Por ejemplo, la cadena <tt/"__ __"/ debe hacer que
3106 se subrayen los dos primeros y el octavo y el noveno carácter.
3108 A continuación tenemos un pequeño ejemplo que ilustra el uso de estas
3109 funciones. Este ejemplo utiliza el <em/widget/ marco (<em/frame/) para
3110 hacer una mejor demostración de los estilos de la etiqueta. Por ahora
3111 puede ignorarlo, ya que el <em/widget/ <ref id="sec_Frames"
3112 name="Frame"> se explicará más tarde.
3115 /* principio del ejemplo label label.c */
3117 #include <gtk/gtk.h>
3122 static GtkWidget *ventana = NULL;
3126 GtkWidget *etiqueta;
3128 /* Inicializa GTK */
3129 gtk_init(&argc, &argv);
3131 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3132 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
3133 GTK_SIGNAL_FUNC(gtk_main_quit),
3136 gtk_window_set_title (GTK_WINDOW (ventana), "Etiqueta");
3137 vbox = gtk_vbox_new (FALSE, 5);
3138 hbox = gtk_hbox_new (FALSE, 5);
3139 gtk_container_add (GTK_CONTAINER (ventana), hbox);
3140 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3141 gtk_container_set_border_width (GTK_CONTAINER (ventana), 5);
3143 frame = gtk_frame_new ("Normal Label");
3144 etiqueta = gtk_label_new ("This is a Normal label");
3145 gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3146 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3148 frame = gtk_frame_new ("Multi-line Label");
3149 etiqueta = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
3151 gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3152 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3154 frame = gtk_frame_new ("Left Justified Label");
3155 etiqueta = gtk_label_new ("This is a Left-Justified\n" \
3156 "Multi-line label.\nThird line");
3157 gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_LEFT);
3158 gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3159 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3161 frame = gtk_frame_new ("Right Justified Label");
3162 etiqueta = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
3163 "Fourth line, (j/k)");
3164 gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_RIGHT);
3165 gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3166 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3168 vbox = gtk_vbox_new (FALSE, 5);
3169 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3170 frame = gtk_frame_new ("Line wrapped label");
3171 etiqueta = gtk_label_new ("This is an example of a line-wrapped label. It " \
3172 "should not be taking up the entire " /* big space to test spacing */\
3173 "width allocated to it, but automatically " \
3174 "wraps the words to fit. " \
3175 "The time has come, for all good men, to come to " \
3176 "the aid of their party. " \
3177 "The sixth sheik's six sheep's sick.\n" \
3178 " It supports multiple paragraphs correctly, " \
3179 "and correctly adds "\
3180 "many extra spaces. ");
3181 gtk_label_set_line_wrap (GTK_LABEL (etiqueta), TRUE);
3182 gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3183 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3185 frame = gtk_frame_new ("Filled, wrapped label");
3186 etiqueta = gtk_label_new ("This is an example of a line-wrapped, filled label. " \
3187 "It should be taking "\
3188 "up the entire width allocated to it. " \
3189 "Here is a seneance to prove "\
3190 "my point. Here is another sentence. "\
3191 "Here comes the sun, do de do de do.\n"\
3192 " This is a new paragraph.\n"\
3193 " This is another newer, longer, better " \
3194 "paragraph. It is coming to an end, "\
3196 gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_FILL);
3197 gtk_label_set_line_wrap (GTK_LABEL (etiqueta), TRUE);
3198 gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3199 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3201 frame = gtk_frame_new ("Underlined label");
3202 etiqueta = gtk_label_new ("This label is underlined!\n"
3203 "This one is underlined in quite a funky fashion");
3204 gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_LEFT);
3205 gtk_label_set_pattern (GTK_LABEL (etiqueta),
3206 "_________________________ _ _________ _ ______ __ _______ ___");
3207 gtk_container_add (GTK_CONTAINER (frame), etiqueta);
3208 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3210 gtk_widget_show_all (ventana);
3216 /* fin del ejemplo */
3219 <!-- ----------------------------------------------------------------- -->
3222 En <em/widget/ flecha (<em/arrow/) dibuja la punta de una flecha,
3223 con un estilo y hacia una dirección a escoger. Puede ser muy útil
3224 en muchas aplicaciones cuando se coloca en un botón.
3226 Sólo hay dos funciones para manipular el <em/widget/ flecha:
3229 GtkWidget *gtk_arrow_new( GtkArrowType arrow_type,
3230 GtkShadowType shadow_type );
3232 void gtk_arrow_set( GtkArrow *arrow,
3233 GtkArrowType arrow_type,
3234 GtkShadowType shadow_type );
3237 La primera crea un nuevo <em/widget/ flecha del tipo y apariencia
3238 indicados. La segunda permite alterar posteriormente estos valores. El
3239 argumento <tt/arrow_type/ puede tomar uno de los valores siguientes:
3243 <item> GTK_ARROW_DOWN
3244 <item> GTK_ARROW_LEFT
3245 <item> GTK_ARROW_RIGHT
3248 Naturalmente, estos valores indican la dirección a la que debe apuntar
3249 la flecha. El argumento <tt/shadow_type/ puede tomar uno de los
3253 <item> GTK_SHADOW_IN
3254 <item> GTK_SHADOW_OUT (por defecto)
3255 <item> GTK_SHADOW_ETCHED_IN
3256 <item> GTK_SHADOW_ETCHED_OUT
3259 Aquí tenemos un pequeño ejemplo para ilustrar la utilización de la
3263 /* principio del ejemplo arrow arrow.c */
3265 #include <gtk/gtk.h>
3267 /* Crea un widget flecha con los parámetros especificados
3268 * y lo empaqueta en un botón */
3269 GtkWidget *create_arrow_button( GtkArrowType arrow_type,
3270 GtkShadowType shadow_type )
3275 boton = gtk_button_new();
3276 arrow = gtk_arrow_new (arrow_type, shadow_type);
3278 gtk_container_add (GTK_CONTAINER (boton), arrow);
3280 gtk_widget_show(boton);
3281 gtk_widget_show(arrow);
3289 /* GtkWidget es el tipo utilizado para los widgets */
3294 /* Inicializa el toolkit */
3295 gtk_init (&argc, &argv);
3297 /* Crea una nueva ventana */
3298 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3300 gtk_window_set_title (GTK_WINDOW (ventana), "Arrow Buttons");
3302 /* Es una buena idea hacer esto con todas las ventanas. */
3303 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
3304 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
3306 /* Establece el ancho del borde de la ventana. */
3307 gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
3309 /* Crea una caja para almacenar las flechas/botones */
3310 box = gtk_hbox_new (FALSE, 0);
3311 gtk_container_set_border_width (GTK_CONTAINER (box), 2);
3312 gtk_container_add (GTK_CONTAINER (ventana), box);
3314 /* Empaqueta y muestra todos nuestros widgets */
3315 gtk_widget_show(box);
3317 boton = create_arrow_button(GTK_ARROW_UP, GTK_SHADOW_IN);
3318 gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
3320 boton = create_arrow_button(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
3321 gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
3323 boton = create_arrow_button(GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
3324 gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
3326 boton = create_arrow_button(GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
3327 gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
3329 gtk_widget_show (ventana);
3331 /* Nos quedamos en gtk_main y ¡esperamos que empiece la diversión! */
3336 /* fin del ejemplo */
3339 <!-- ----------------------------------------------------------------- -->
3340 <sect1>El <em/widget/ de información rápida (<em/tooltip/)
3342 Estos <em/widgets/ son las pequeñas etiquetas que texto que
3343 aparecen cuando se sitúa el puntero del ratón sobre un botón
3344 u otro <em/widget/ durante algunos segundos. Son bastante fáciles
3345 de usar, así que no se dará ningún ejemplo. Si quiere ver
3346 algún ejemplo se recomienda leer el programa testgtk.c que
3349 Algunos <em/widgets/ (como la etiqueta) no pueden llevar asociado un
3352 Para cada función sólo hay que hacer una llamada para conseguir
3353 un <em/tooltip/. El objeto <tt/GtkTooltip/ que devuelve la siguiente
3354 función puede ser usado para crear múltiples <em/widgets/.
3357 GtkTooltips *gtk_tooltips_new( void );
3360 Una vez que el <em/tooltip/ ha sido creado (y el <em/widget/ sobre el
3361 que se quiere usar) simplemente hay que usar la siguiente llamada para
3365 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3367 const gchar *tip_text,
3368 const gchar *tip_private );
3371 El primer argumento es el <em/tooltip/ que ya ha creado, seguido del
3372 <em/widget/ al que se desea asociar el <em/tooltip/, el tercero es el
3373 texto que se quiere que aparezca y el último es una cadena de texto
3374 que puede ser usada como un identificador cuando se usa GtkTipsQuery
3375 para desarollar ayuda sensible al contexto. Por ahora conviene dejarlo
3378 <!-- TODO: sort out what how to do the context sensitive help -->
3383 GtkTooltips *tooltips;
3386 tooltips = gtk_tooltips_new ();
3387 boton = gtk_button_new_with_label ("botón 1");
3389 gtk_tooltips_set_tip (tooltips, boton, "Este es el botón 1", NULL);
3392 Existen otras funciones que pueden ser usadas con los <em/tooltips/.
3393 Solamente vamos a enumerlarlas añadiendo una pequeña descripción
3394 de que hace cada una.
3397 void gtk_tooltips_enable( GtkTooltips *tooltips );
3400 Permite que funcionen un conjunto de <em/tooltips/
3403 void gtk_tooltips_disable( GtkTooltips *tooltips );
3406 Oculta un conjunto de <em/tooltips/ para que no pueda ser mostrado.
3409 void gtk_tooltips_set_delay( GtkTooltips *tooltips,
3414 Establece cuantos milisegundos tiene que estar el puntero sobre el
3415 <em/widget/ para que aparezca el <em/tooltip/. Por defecto se usan 1000
3416 milisegundos (1 segundo).
3419 void gtk_tooltips_set_colors( GtkTooltips *tooltips,
3420 GdkColor *background,
3421 GdkColor *foreground );
3424 Establece el color del texto y del fondo del <em/tooltip/. No se como
3425 se especifica el color.
3427 <!-- ----------------------------------------------------------------- -->
3428 <sect1> Barras de progreso <label id="sec_ProgressBar">
3430 Estas barras se usan para mostrar el estado de una operación. Son
3431 bastante sencillas de utilizar, tal y como se verá en los ejemplos
3432 siguientes. Pero primero vamos a ver cuales son las funciones que hay
3433 que utilizar para crear una nueva barra de progreso.
3435 Hay dos formas de crear una nueva barra de progreso, la sencilla no
3436 necesita de argumentos, y la otra recibe un objeto GtkAdjustment. Si
3437 se utiliza la primera forma, la barra de progreso creará su propio
3441 GtkWidget *gtk_progress_bar_new( void );
3443 GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );
3446 El segundo método tiene la ventaja de que podemos utilizar el objeto
3447 adjustment para especificar nuestro propio rango de parámetros para la
3450 El ajuste de una barra de progreso se puede cambiar de forma dinámica
3454 void gtk_progress_set_adjustment( GtkProgress *progress,
3455 GtkAdjustment *adjustment );
3458 Ahora que hemos creado la barra de progreso ya podemos utilizarla.
3461 void gtk_progress_bar_update( GtkProgressBar *pbar,
3462 gfloat percentage );
3465 El primer argumento es la barra que se quiere manejar, el segundo es
3466 tanto por ciento que ha sido `completado' (indica cuanto ha sido
3467 llenada la barra y oscila entre 0-100%). El valor que se le tiene que
3468 pasar oscila entre 0 y 1.
3470 GTK+ v1.2 ha añadido una nueva característica a la barra de progreso,
3471 y es que ahora permite mostrar su valor de varias maneras distintas, e
3472 informar al usuario del valor y rango actual.
3474 Una barra de progreso puede mostrarse con distintas orientaciones
3475 utilizando la función
3478 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3479 GtkProgressBarOrientation orientation );
3482 Donde el argumento <tt/orientación/ puede tomar uno de los valores que
3483 vienen a continuación para indicar la dirección en la que se mueve la
3487 <item> GTK_PROGRESS_LEFT_TO_RIGHT
3488 <item> GTK_PROGRESS_RIGHT_TO_LEFT
3489 <item> GTK_PROGRESS_BOTTOM_TO_TOP
3490 <item> GTK_PROGRESS_TOP_TO_BOTTOM
3493 Cuando se utiliza como una medida de cuanto se ha completado de un
3494 proceso, la barra de progreso puede configurarse para que muestre su
3495 valor de una forma continua o discreta. En modo continuo, la barra de
3496 progreso se actualiza mediante un número discreto de bloques, el
3497 número de bloques también es configurable.
3499 Se puede configurar el estilo de la barra de progreso utilizando la
3503 void gtk_progress_bar_set_bar_style( GtkProgressBar *pbar,
3504 GtkProgressBarStyle style );
3507 El parámetro <tt/style/ puede tomar uno de los dos valores siguientes:
3510 <item>GTK_PROGRESS_CONTINUOUS
3511 <item>GTK_PROGRESS_DISCRETE
3514 El número de bloques se puede establecer utilizando
3517 void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
3521 La barra de progreso también se puede utilizar, a parte de para
3522 indicar lo «avanzado» de una tarea, para indicar que hay algún tipo
3523 de actividad. Esto puede ser útil en situaciones donde no se pueda
3524 medir el progreso de una tarea con un rango de valores. Para el modo
3525 actividad, no sirve el estilo de barra que se ha descrito más
3526 arriba. Este modo hay que seleccionarlo utilizando la siguiente
3530 void gtk_progress_set_activity_mode( GtkProgress *progress,
3531 guint activity_mode );
3534 El tamaño del paso del indicador de actividad, y el número de bloques
3535 se indican usando las siguientes funciones:
3538 void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
3541 void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
3545 Cuando estamos en modo continuo, la barra de progreso puede mostrar un
3546 texto configurable dentro la barra misma, utilizando la función
3550 void gtk_progress_set_format_string( GtkProgress *progress,
3554 El argumento <tt/format/ es parecido al que se utiliza en una orden
3555 <tt/printf/ de C. Se pueden utilizar las siguientes opciones para el
3556 formateado de la cadena:
3559 <item> %p - porcentaje
3561 <item> %l - valor inferior del rango
3562 <item> %u - valor superior del rango
3565 Puede activar o desactivar el texto utilizando:
3568 void gtk_progress_set_show_text( GtkProgress *progress,
3572 El argumento <tt/show_text/ es un valor booleano TRUE/FALSE. La
3573 apariencia del texto puede modificarse utilizando:
3576 void gtk_progress_set_text_alignment( GtkProgress *progress,
3581 Los argumentos <tt/x_align/ y <tt/y_align/ toman un valor entre 0.0 y
3582 1.0. Este valor indica la posición de la cadena de texto dentro de la
3583 barra. Si ponemos 0.0 en los dos sitios la cadena de texto aparecerá
3584 en la esquina superior izquierda; un valor de 0.5 (el que se utiliza
3585 por defecto) centra el texto, y un valor de 1.0 coloca el texto en la
3586 esquina inferior derecha.
3588 Se pueden leer los parámetros actuales del texto de un objeto barra
3589 de progreso utilizando las dos funciones que se muestran a
3590 continuación. La cadena de carácteres devuelta por estas funciones
3591 debe liberarse en la aplicación (utilizando la función
3592 g_free()). Estas funciones devuelven el texto formateado que se
3593 mostrará en la barra.
3596 gchar *gtk_progress_get_current_text( GtkProgress *progress );
3598 gchar *gtk_progress_get_text_from_value( GtkProgress *progress,
3602 Hay otra forma de cambiar el rango y el valor de un objeto barra de
3603 progreso utilizando la función:
3606 void gtk_progress_configure( GtkProgress *progress,
3612 Esta función proporciona una interfaz sencilla al rango y valor de una
3615 Las funciones restantes se pueden utilizar para obtener y establecer
3616 el valor actual de una barra de progreso utilizando distintos tipos y
3617 formatos para el valor.
3620 void gtk_progress_set_percentage( GtkProgress *progress,
3621 gfloat percentage );
3623 void gtk_progress_set_value( GtkProgress *progress,
3626 gfloat gtk_progress_get_value( GtkProgress *progress );
3628 gfloat gtk_progress_get_current_percentage( GtkProgress *progress );
3630 gfloat gtk_progress_get_percentage_from_value( GtkProgress *progress,
3634 Estas funciones son autoexplicatorias. La última función utiliza el
3635 ajuste de la barra de progreso especificada para calcular el
3636 porcentaje dentro del rango de valores de la barra.
3638 Las barras de progreso se usan con otras funciones como los tiempos de
3639 espera (<em/timeouts/), sección <ref id="sec_timeouts"
3640 name="Tiempos de espera, E/S (I/O) y funciones ociosas (idle)">) para
3641 crear la ilusión de la multitarea. Todas usan la función
3642 gtk_progress_bar_update de la misma manera.
3644 Estudiemos un ejemplo de barras de progreso actualizada usando
3645 tiempos de espera. También se muestra como se debe reestablecer una
3649 /* comienzo del programa-ejemplo progressbar.c */
3651 #include <gtk/gtk.h>
3653 #include <gtk/gtk.h>
3655 typedef struct _ProgressData {
3661 /* Actualiza el valor de la barra de progreso para que
3662 * podamos ver algún movimiento */
3663 gint progress_timeout( gpointer data )
3668 /* Calcula el valor de la barra de progreso utilizando
3669 * el rango de valores establecido en el ajuste de la
3672 new_val = gtk_progress_get_value( GTK_PROGRESS(data) ) + 1;
3674 adj = GTK_PROGRESS (data)->adjustment;
3675 if (new_val > adj->upper)
3676 new_val = adj->lower;
3678 /* Establece el nuevo valor */
3680 gtk_progress_set_value (GTK_PROGRESS (data), new_val);
3682 /* Como esta es una función de espera, devolvemos TRUE
3683 * para que continue siendo llamada */
3688 /* Función de llamada que activa/desactiva el texto de dentro
3689 * de la barra de progreso */
3690 void toggle_show_text( GtkWidget *widget,
3691 ProgressData *pdata )
3693 gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
3694 GTK_TOGGLE_BUTTON (widget)->active);
3697 /* Función de llamada que activa/desactiva el modo actividad
3698 * de la barra de progreso */
3699 void toggle_activity_mode( GtkWidget *widget,
3700 ProgressData *pdata )
3702 gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
3703 GTK_TOGGLE_BUTTON (widget)->active);
3706 /* Función de llamada que activa/desactiva el modo continuo
3707 * de la barra de progreso */
3708 void set_continuous_mode( GtkWidget *widget,
3709 ProgressData *pdata )
3711 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3712 GTK_PROGRESS_CONTINUOUS);
3715 /* Función de llamada que activa/desactiva el modo discreto
3716 * de la barra de progreso */
3717 void set_discrete_mode( GtkWidget *widget,
3718 ProgressData *pdata )
3720 gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
3721 GTK_PROGRESS_DISCRETE);
3724 /* Libera la memoria y elimina el temporizador */
3725 void destroy_progress( GtkWidget *widget,
3726 ProgressData *pdata)
3728 gtk_timeout_remove (pdata->timer);
3730 pdata->ventana = NULL;
3738 ProgressData *pdata;
3740 GtkWidget *separator;
3747 gtk_init (&argc, &argv);
3749 /* Reserva memoria para los datos que se le pasan a las funciones
3751 pdata = g_malloc( sizeof(ProgressData) );
3753 pdata->ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3754 gtk_window_set_policy (GTK_WINDOW (pdata->ventana), FALSE, FALSE, TRUE);
3756 gtk_signal_connect (GTK_OBJECT (pdata->ventana), "destroy",
3757 GTK_SIGNAL_FUNC (destroy_progress),
3759 gtk_window_set_title (GTK_WINDOW (pdata->ventana), "GtkProgressBar");
3760 gtk_container_set_border_width (GTK_CONTAINER (pdata->ventana), 0);
3762 vbox = gtk_vbox_new (FALSE, 5);
3763 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
3764 gtk_container_add (GTK_CONTAINER (pdata->ventana), vbox);
3765 gtk_widget_show(vbox);
3767 /* Crea un objeto de alineamiento centrado */
3768 align = gtk_alignment_new (0.5, 0.5, 0, 0);
3769 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
3770 gtk_widget_show(align);
3772 /* Crea un objeto GtkAdjusment para albergar el rango de la barra
3774 adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
3776 /* Crea la GtkProgressBar utilizando el ajuste */
3777 pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
3779 /* Establece el formato de la cadena de texto que puede mostrarse
3780 * en la barra de progreso:
3783 * %l - valor inferior del rango
3784 * %u - valor superior del rango */
3785 gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
3786 "%v from [%l-%u] (=%p%%)");
3787 gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
3788 gtk_widget_show(pdata->pbar);
3790 /* Añade un temporizador para la actualización del valor de la
3791 * barra de progreso */
3792 pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
3794 separator = gtk_hseparator_new ();
3795 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3796 gtk_widget_show(separator);
3798 /* filas, columnas, homogéneo */
3799 table = gtk_table_new (2, 3, FALSE);
3800 gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
3801 gtk_widget_show(table);
3803 /* Añade un botón de comprobación para seleccionar si se debe
3804 * mostrar el texto dentro de la barra */
3805 check = gtk_check_button_new_with_label ("Show text");
3806 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
3807 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3809 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3810 GTK_SIGNAL_FUNC (toggle_show_text),
3812 gtk_widget_show(check);
3814 /* Añade un botón de comprobación para activar/desactivar el modo
3816 check = gtk_check_button_new_with_label ("Activity mode");
3817 gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
3818 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3820 gtk_signal_connect (GTK_OBJECT (check), "clicked",
3821 GTK_SIGNAL_FUNC (toggle_activity_mode),
3823 gtk_widget_show(check);
3825 separator = gtk_vseparator_new ();
3826 gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
3827 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3829 gtk_widget_show(separator);
3831 /* Añade un botón circular para seleccionar el modo continuo */
3832 boton = gtk_radio_button_new_with_label (NULL, "Continuous");
3833 gtk_table_attach (GTK_TABLE (table), boton, 2, 3, 0, 1,
3834 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3836 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
3837 GTK_SIGNAL_FUNC (set_continuous_mode),
3839 gtk_widget_show (boton);
3841 /* Añade un botón circular para seleccionar el modo discreto */
3842 boton = gtk_radio_button_new_with_label(
3843 gtk_radio_button_group (GTK_RADIO_BUTTON (boton)),
3845 gtk_table_attach (GTK_TABLE (table), boton, 2, 3, 1, 2,
3846 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
3848 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
3849 GTK_SIGNAL_FUNC (set_discrete_mode),
3851 gtk_widget_show (boton);
3853 separator = gtk_hseparator_new ();
3854 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
3855 gtk_widget_show(separator);
3857 /* Añade un botón para salir del programa */
3858 boton = gtk_button_new_with_label ("close");
3859 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
3860 (GtkSignalFunc) gtk_widget_destroy,
3861 GTK_OBJECT (pdata->ventana));
3862 gtk_box_pack_start (GTK_BOX (vbox), boton, FALSE, FALSE, 0);
3864 /* Esto hace que este botón sea el botón pueda utilizarse por
3865 * defecto defecto. */
3866 GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
3868 /* Esto marca este botón para que sea el botón por
3869 * defecto. Simplemente utilizando la tecla "Intro" haremos que se
3870 * active este botón. */
3871 gtk_widget_grab_default (boton);
3872 gtk_widget_show(boton);
3874 gtk_widget_show (pdata->ventana);
3880 /* final del ejemplo */
3883 <!-- ----------------------------------------------------------------- -->
3884 <sect1>Cuadros de diálogo
3886 El <em/widget/ del cuadro de diálogo es bastante simple, sólo es una
3887 ventana con algunas cosas ya preempaquetadas. Su estructura es la
3896 GtkWidget *action_area;
3900 Simplemente se crea una ventana en la cual se empaqueta una vbox, un
3901 separador y una hbox llamada «action_area».
3903 Este tipo de <em/widgets/ pueden ser usados como mensages <em/pop-up/
3904 (pequeñas ventanas con texto en su interior que aparecen cuando el
3905 usuario hace algo y queremos informarle de alguna cosa) y otras cosas
3906 parecidas. Su manejo desde el punto de vista del programador
3907 es bastante fácil, sólo hay que usar una función:
3910 GtkWidget *gtk_dialog_new( void );
3913 Para crear un nuevo cuadro de diálogo hay que llamar a:
3917 ventana = gtk_dialog_new ();
3920 Una vez que el cuadro ha sido creado sólo hay que usarlo. Por
3921 ejemplo para empaquetar un botón en la action_area escribiríamos
3926 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->action_area), boton,
3928 gtk_widget_show (boton);
3931 Otra cosa que nos puede interesar es empaquetar una etiqueta en la
3935 etiqueta = gtk_label_new ("Dialogs are groovy");
3936 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->vbox), etiqueta, TRUE,
3938 gtk_widget_show (etiqueta);
3941 Otros ejemplo posible es poner dos botones en el action_area (uno
3942 para cancelar y el otro para permitir algo) junto con una etiqueta en
3943 la vbox el usuario puede seleccionar lo que quiera.
3945 Si se precisa algo más complejo siempre se puede empaquetar otro
3946 <em/widget/ en cualquiera de las cajas (p.j. una tabla en una vbox).
3948 <!-- ----------------------------------------------------------------- -->
3949 <sect1> <em/Pixmaps/ <label id="sec_Pixmaps">
3951 Los <em/pixmaps/ son estructuras de datos que contienen dibujos. Estos
3952 pueden ser usados en diferentes lugares, pero los iconos y los
3953 cursores son los más comunes.
3955 Un <em/bitmap/ es un <em/pixmap/ que sólo tiene dos colores, y hay
3956 unas cuantas rutinas especiales para controlar este caso particular.
3958 Para comprender los <em/pixmaps/, puede ayudar entender como funciona
3959 X-windows. Bajo X-windows, las aplicaciones no tienen porque estar
3960 ejecutándose en el ordenador que está interactuando con el
3961 usuario. Las distintas aplicaciones, llamadas «clientes», comunican
3962 con un programa que muestra los gráficos y que controla el tecledo y
3963 el ratón. Este programa que interactua directamente con el usuario se
3964 llama un «<em/display server/» o «servidor X». Como la
3965 comunicación entre el servidor y el cliente puede llevarse a cabo
3966 mediante una red, es importante mantener alguna información en el
3967 servidor X. Los <em/pixmaps/ por ejemplo, se almacenan en la memoria
3968 del servidor X. Esto significa que una vez que se establecen los
3969 valores del <em/pixmap/, no tienen que estar transmitiéndose por la
3970 red; en su lugar lo único que hay que enviar es una orden del estilo
3971 «mostrar <em/pixmap/ número XYZ aquí». Incluso si no está utilizando
3972 X-windows con GTK, al utilizar construcciones como los <em/pixmaps/
3973 conseguirá que sus programas funciones de forma aceptable bajo
3976 Para usar un <em/pixmap/ en GTK primero tiene que construir una
3977 estructura del tipo GdkPixmap usando rutinas de GDK. Los <em/pixmaps/
3978 se pueden crear usando datos que se encuentren en la memoria o en un
3979 archivo. Veremos con detalle cada una de las dos posibilidades.
3982 GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *ventana,
3988 Esta rutina se utiliza para crear un <em/bitmap/ a partir de datos
3989 almacenados en la memoria. Cada bit de información indica si el
3990 <em/pixel/ luce o no. Tanto la altura como la anchura estan expresadas
3991 en <em/pixels/. El puntero del tipo GdkWindow indica la ventana en
3992 cuestión, ya que los <em/pixmaps/ sólo tienen sentido dentro de
3993 la pantalla en la que van a ser mostrados.
3996 GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *ventana,
4005 Con esto creamos un <em/pixmap/ con la profundidad (número de
4006 colores) especificada en los datos del <em/bitmap/. Los valores
4007 <tt/fg/ y <tt/bg/ son los colores del frente y del fondo
4011 GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *ventana,
4013 GdkColor *transparent_color,
4014 const gchar *filename );
4017 El formato XPM es una representacion de los <em/pixmaps/ para el
4018 sistema X Window. Es bastante popular y existen muchos programas para
4019 crear imágenes en este formato. El archivo especificado mediante
4020 <tt/filename/ debe contener una imagen en ese formato para que sea
4021 cargada en la estructura. La máscara especifica que bits son
4022 opacos. Todos los demás bits se colorean usando el color
4023 especificado en <tt/transparent_color/. Más adelante veremos un
4027 GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *ventana,
4029 GdkColor *transparent_color,
4033 Se pueden incorporar imágenes pequeñas dentro de un programa en
4034 formato XPM. Un <em/pixmap/ se crea usando esta información, en
4035 lugar de leerla de un archivo. Un ejemplo sería:
4039 static const char * xpm_data[] = {
4042 ". c #000000000000",
4043 "X c #FFFFFFFFFFFF",
4062 Cuando hayamos acabado de usar un <em/pixmap/ y no lo vayamos a usar
4063 durante un tiempo suele ser conveniente liberar el recurso mediante
4064 gdk_pixmap_unref(). (Los <em/pixmaps/ deben ser considerados recursos
4067 Una vez que hemos creado el <em/pixmap/ lo podemos mostrar como un
4068 <em/widget/ GTK. Primero tenemos que crear un <em/widget pixmap/ que
4069 contenga un <em/pixmap/ GDK. Esto se hace usando:
4072 GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
4076 Las otras funciones del <em/widget pixmap/ son:
4079 guint gtk_pixmap_get_type( void );
4081 void gtk_pixmap_set( GtkPixmap *pixmap,
4085 void gtk_pixmap_get( GtkPixmap *pixmap,
4090 La función gtk_pixmap_set se usa para cambiar los datos del
4091 <em/pixmap/ que el <em/widget/ está manejando en ese
4092 momento. <tt/val/ es el <em/pixmap/ creado usando GDK.
4094 El ejemplo siguiente usa un <em/pixmap/ en un botón:
4097 /* comienzo del ejemplo pixmap.c */
4099 #include <gtk/gtk.h>
4102 /* Datos en formato XPM del icono de apertura de archivo */
4103 static const char * xpm_data[] = {
4106 ". c #000000000000",
4107 "X c #FFFFFFFFFFFF",
4125 /* Cuando se llama a esta función (usando signal delete_event) se
4126 * termina la aplicación*/
4128 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4133 /* Al presionar el botón aparece el mensaje */
4134 void button_clicked( GtkWidget *widget, gpointer data ) {
4135 printf( "botón pulsado\n" );
4138 int main( int argc, char *argv[] )
4141 GtkWidget *ventana, *pixmapwid, *boton;
4146 /* Creamos la ventana principal y relacionamos la señal
4147 * delete_event con acabar el programa.*/
4148 gtk_init( &argc, &argv );
4149 ventana = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4150 gtk_signal_connect( GTK_OBJECT (ventana), "delete_event",
4151 GTK_SIGNAL_FUNC (close_application), NULL );
4152 gtk_container_border_width( GTK_CONTAINER (ventana), 10 );
4153 gtk_widget_show( ventana );
4155 /* Ahora para el pixmap de gdk */
4156 style = gtk_widget_get_style( ventana );
4157 pixmap = gdk_pixmap_create_from_xpm_d( ventana->window, &mask,
4158 &style->bg[GTK_STATE_NORMAL],
4159 (gchar **)xpm_data );
4161 /* Un pixmap widget que contendrá al pixmap */
4162 pixmapwid = gtk_pixmap_new( pixmap, mask );
4163 gtk_widget_show( pixmapwid );
4165 /* Un botón para contener al pixmap */
4166 boton = gtk_button_new();
4167 gtk_container_add( GTK_CONTAINER(boton), pixmapwid );
4168 gtk_container_add( GTK_CONTAINER(ventana), boton );
4169 gtk_widget_show( boton );
4171 gtk_signal_connect( GTK_OBJECT(boton), "clicked",
4172 GTK_SIGNAL_FUNC(button_clicked), NULL );
4174 /* mostramos la ventana */
4179 /* final del ejemplo */
4182 Para cargar un archivo llamado icon0.xpm con la información XPM (que
4183 se encuentra en en directorio actual) habríamos usado:
4186 /* cargar un pixmap desde un fichero */
4187 pixmap = gdk_pixmap_create_from_xpm( ventana->window, &mask,
4188 &style->bg[GTK_STATE_NORMAL],
4190 pixmapwid = gtk_pixmap_new( pixmap, mask );
4191 gtk_widget_show( pixmapwid );
4192 gtk_container_add( GTK_CONTAINER(ventana), pixmapwid );
4195 Una desventaja de los <em/pixmaps/ es que la imagen mostrada siempre
4196 es rectangular (independientemente de como sea la imagen en sí). Si
4197 queremos usar imágenes con otras formas debemos usar ventanas con
4198 forma (<em/shaped windows/).
4200 Este tipo de ventanas son pixmaps en los que el fondo es
4201 transparente. Así cuando la imagen del fondo tiene muchos colores
4202 no los sobreescribimos con el borde de nuestro icono. El ejemplo
4203 siguiente muestra la imagen de una carretilla en el escritorio.
4206 /* comienzo del ejemplo carretilla wheelbarrow.c */
4208 #include <gtk/gtk.h>
4211 static char * WheelbarrowFull_xpm[] = {
4214 ". c #DF7DCF3CC71B",
4215 "X c #965875D669A6",
4216 "o c #71C671C671C6",
4217 "O c #A699A289A699",
4218 "+ c #965892489658",
4219 "@ c #8E38410330C2",
4220 "# c #D75C7DF769A6",
4221 "$ c #F7DECF3CC71B",
4222 "% c #96588A288E38",
4223 "& c #A69992489E79",
4224 "* c #8E3886178E38",
4225 "= c #104008200820",
4226 "- c #596510401040",
4227 "; c #C71B30C230C2",
4228 ": c #C71B9A699658",
4229 "> c #618561856185",
4230 ", c #20811C712081",
4231 "< c #104000000000",
4232 "1 c #861720812081",
4233 "2 c #DF7D4D344103",
4234 "3 c #79E769A671C6",
4235 "4 c #861782078617",
4236 "5 c #41033CF34103",
4237 "6 c #000000000000",
4238 "7 c #49241C711040",
4239 "8 c #492445144924",
4240 "9 c #082008200820",
4241 "0 c #69A618611861",
4242 "q c #B6DA71C65144",
4243 "w c #410330C238E3",
4244 "e c #CF3CBAEAB6DA",
4245 "r c #71C6451430C2",
4246 "t c #EFBEDB6CD75C",
4247 "y c #28A208200820",
4248 "u c #186110401040",
4249 "i c #596528A21861",
4250 "p c #71C661855965",
4251 "a c #A69996589658",
4252 "s c #30C228A230C2",
4253 "d c #BEFBA289AEBA",
4254 "f c #596545145144",
4255 "g c #30C230C230C2",
4256 "h c #8E3882078617",
4257 "j c #208118612081",
4258 "k c #38E30C300820",
4259 "l c #30C2208128A2",
4260 "z c #38E328A238E3",
4261 "x c #514438E34924",
4262 "c c #618555555965",
4263 "v c #30C2208130C2",
4264 "b c #38E328A230C2",
4265 "n c #28A228A228A2",
4266 "m c #41032CB228A2",
4267 "M c #104010401040",
4268 "N c #492438E34103",
4269 "B c #28A2208128A2",
4270 "V c #A699596538E3",
4271 "C c #30C21C711040",
4272 "Z c #30C218611040",
4273 "A c #965865955965",
4274 "S c #618534D32081",
4275 "D c #38E31C711040",
4276 "F c #082000000820",
4285 "ty> 459@>+&& ",
4287 "%$;=* *3:.Xa.dfg> ",
4288 "Oh$;ya *3d.a8j,Xe.d3g8+ ",
4289 " Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
4290 " Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
4291 " Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
4292 " Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
4293 " Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
4294 " Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
4295 " OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
4296 " 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
4297 " :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
4298 " +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
4299 " *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
4300 " p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
4301 " OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
4302 " 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
4303 " @26MvzxNzvlbwfpdettttttttttt.c,n& ",
4304 " *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
4305 " p;<69BvwwsszslllbBlllllllu<5+ ",
4306 " OS0y6FBlvvvzvzss,u=Blllj=54 ",
4307 " c1-699Blvlllllu7k96MMMg4 ",
4308 " *10y8n6FjvllllB<166668 ",
4309 " S-kg+>666<M<996-y6n<8* ",
4310 " p71=4 m69996kD8Z-66698&& ",
4311 " &i0ycm6n4 ogk17,0<6666g ",
4312 " N-k-<> >=01-kuu666> ",
4313 " ,6ky& &46-10ul,66, ",
4314 " Ou0<> o66y<ulw<66& ",
4315 " *kk5 >66By7=xu664 ",
4316 " <<M4 466lj<Mxu66o ",
4317 " *>> +66uv,zN666* ",
4328 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4332 int main (int argc, char *argv[])
4335 GtkWidget *ventana, *pixmap, *fixed;
4336 GdkPixmap *gdk_pixmap;
4341 /* Creamos la ventana principal y relacionamos la señal
4342 * delete_event para terminar la aplicación. Conviene destacar
4343 * que la ventana no tendrá título puesto que es popup.*/
4344 gtk_init (&argc, &argv);
4345 ventana = gtk_window_new( GTK_WINDOW_POPUP );
4346 gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
4347 GTK_SIGNAL_FUNC (close_application), NULL);
4348 gtk_widget_show (ventana);
4350 style = gtk_widget_get_default_style();
4351 gc = style->black_gc;
4352 gdk_pixmap = gdk_pixmap_create_from_xpm_d( ventana->window, &mask,
4353 &style->bg[GTK_STATE_NORMAL],
4354 WheelbarrowFull_xpm );
4355 pixmap = gtk_pixmap_new( gdk_pixmap, mask );
4356 gtk_widget_show( pixmap );
4359 fixed = gtk_fixed_new();
4360 gtk_widget_set_usize( fixed, 200, 200 );
4361 gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
4362 gtk_container_add( GTK_CONTAINER(ventana), fixed );
4363 gtk_widget_show( fixed );
4365 /* Con esto cubrimos todo menos la imagen */
4366 gtk_widget_shape_combine_mask( ventana, mask, 0, 0 );
4368 /* mostramos la ventana */
4369 gtk_widget_set_uposition( ventana, 20, 400 );
4370 gtk_widget_show( ventana );
4375 /* final del ejemplo */
4378 Para que la carretilla sea más realista podríamos relacionar la
4379 pulsación del botón con que haga algo. Con las líneas
4380 siguientes la pulsación del botón hace que se acabe el programa.
4383 gtk_widget_set_events( ventana,
4384 gtk_widget_get_events( ventana ) |
4385 GDK_BUTTON_PRESS_MASK );
4387 gtk_signal_connect( GTK_OBJECT(ventana), "button_press_event",
4388 GTK_SIGNAL_FUNC(close_application), NULL );
4391 <!-- ----------------------------------------------------------------- -->
4395 Las reglas son usadas para indicar la posición del puntero del
4396 ratón en una ventana dada. Una ventana puede tener una regla
4397 vertical a lo largo de su alto y una horizontal a lo largo de su
4398 ancho. Un pequeño indicador triangular muestra la relación entre
4399 el puntero del ratón y la regla.
4401 Las reglas (horizontales y verticales) se crean usando:
4404 GtkWidget *gtk_hruler_new( void ); /* horizontal */
4405 GtkWidget *gtk_vruler_new( void ); /* vertical */
4408 Las unidades de la regla pueden ser pixels, pulgadas o centímetros
4409 (GKD_PIXELS, GDK_INCHES, GDK_CENTIMETRES). Esto se hace usando:
4412 void gtk_ruler_set_metric( GtkRuler *ruler,
4413 GtkMetricType metric );
4416 El valor por defecto es GTK_PIXELS.
4419 gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
4422 Otra característica importante de las reglas es cómo mostrar las
4423 unidades de escala y la posicion inicial dónde se situa el indicador.
4424 Todo esto se consigue mediante:
4427 void gtk_ruler_set_range( GtkRuler *ruler,
4434 Los argumentos <tt/lower/ (valor más bajo) y <tt/upper/ (más
4435 alto) delimitan la extensión de la regla. El argumento
4436 <tt/max_size/ es el número más alto que será mostrado. Como
4437 es lógico <tt/posicion/ define la posición inicial del indicador
4440 Una regla vertical puede puede llegar a ser de 800 pixels:
4443 gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4446 Las marcas dentro de la regla oscilarán entre 0 y 800 con una
4447 periodicidad de 100. Si queremos que varíe entre 7 y 16
4451 gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4454 El indicador de la regla es un pequeño triángulo que señala la
4455 posición del puntero con relación a la regla. Si la regla debe
4456 seguir al puntero del ratón la señal motion_notify_event debe estar
4457 conectada con el motion_notify_event de la regla. Para seguir todos
4458 los movimientos dentro de una ventana conviene usar:
4461 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4463 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4464 (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
4465 GTK_OBJECT(ruler) );
4468 El siguiente ejemplo crea una zona de dibujo con una regla horizontal
4469 y otra vertical. El tamaño de la zona de dibujo es de 600 x 400
4470 <em/pixels/. La regla horizontal oscila entre 7 y 13 con marcas cada
4471 100 <em/pixels/, mientras que la vertical va desde 0 a 400 con
4472 separaciones cada 100. La zona de dibujo y las reglas se sitúan
4476 /* comienzo del ejemplo rulers.c */
4478 #include <gtk/gtk.h>
4480 #define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
4485 /* Esta rutina toma el control cuando se pulsa el botón close
4487 void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
4491 int main( int argc, char *argv[] ) {
4492 GtkWidget *ventana, *table, *area, *hrule, *vrule;
4495 gtk_init( &argc, &argv );
4497 ventana = gtk_window_new( GTK_WINDOW_TOPLEVEL );
4498 gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
4499 GTK_SIGNAL_FUNC( close_application ), NULL);
4500 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
4502 /* creación de la tabla donde pondremos las reglas y la zona de
4504 table = gtk_table_new( 3, 2, FALSE );
4505 gtk_container_add( GTK_CONTAINER(ventana), table );
4507 area = gtk_drawing_area_new();
4508 gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
4509 gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
4510 GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
4511 gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
4513 /* La regla horizontal está arriba. Cuando el ratón se mueve
4514 * a lo largo de la zona de dibujo el controlador de eventos de la
4515 * regla recibe motion_notify_event. */
4516 hrule = gtk_hruler_new();
4517 gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
4518 gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
4519 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4520 (GtkSignalFunc)EVENT_METHOD(hrule,
4521 motion_notify_event),
4522 GTK_OBJECT(hrule) );
4523 /* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
4524 gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
4525 GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
4528 /* la zona de dibujo el controlador de eventos de la regla recibe
4529 * motion_notify_event. */
4530 vrule = gtk_vruler_new();
4531 gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
4532 gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
4533 gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
4535 GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->
4536 motion_notify_event,
4537 GTK_OBJECT(vrule) );
4538 gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
4539 GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
4542 /* mostramos todo */
4543 gtk_widget_show( area );
4544 gtk_widget_show( hrule );
4545 gtk_widget_show( vrule );
4546 gtk_widget_show( table );
4547 gtk_widget_show( ventana );
4552 /* final del ejemplo */
4555 <!-- ----------------------------------------------------------------- -->
4556 <sect1>Barras de estado
4558 Las barras de estado son widgets usados para mostrar un mensaje. Todo
4559 aquello que haya sido mostrado se guarda en una pila, con lo que es
4560 muy fácil repetir el último mensaje.
4562 Para permitir que diferentes partes del programa usen la misma barra
4563 de estado éstas usan Identificadores por Contexto (Context
4564 Identifiers) para identificar a los `usuarios'. El mensaje que está
4565 en lo alto de la pila será el siguiente en mostrarse, sin importar
4566 el contexto en el que se esté. Los mensajes se almacenan en el
4567 orden el último en entrar es el primero en salir, y el
4568 Identificador por Contexto no influye en este orden.
4570 Las barras de estado se crean con una llamada a:
4573 GtkWidget *gtk_statusbar_new( void );
4576 Se pide un nuevo Identificador por Contexto con una pequeña
4577 descripción textual del contexto y una llamada a la función:
4580 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4581 const gchar *context_description );
4584 Hay tres funciones que pueden manipular las barras de estado:
4587 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4591 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4594 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4599 La primera, gtk_statusbar_push, se utiliza para añadir un nuevo
4600 mensaje a la barra de estado. Devuelve un Identificador de Mensaje,
4601 que podemos pasarle más tarde a la función gtk_statusbar_remove para
4602 eliminar el mensaje con los Identificadores de Contexto y de Mensaje
4603 que hay en la pila de barras de estado.
4605 La función gtk_statusbar_pop elimina el mensaje que se encuentra
4606 más alto en pila y que contiene el Identificador por Contexto
4609 El ejemplo siguiente crea una barra de estado y dos botones, uno para
4610 meter un elemento en la barra y el otro para sacar el último elemento
4614 /* Principio del ejemplo de barras de estado statusbar.c */
4616 #include <gtk/gtk.h>
4619 GtkWidget *status_bar;
4621 void push_item (GtkWidget *widget, gpointer data)
4623 static int count = 1;
4626 g_snprintf(buff, 20, "Item %d", count++);
4627 gtk_statusbar_push( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data), buff);
4632 void pop_item (GtkWidget *widget, gpointer data)
4634 gtk_statusbar_pop( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data) );
4638 int main (int argc, char *argv[])
4647 gtk_init (&argc, &argv);
4649 /* crear una nueva ventana */
4650 ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4651 gtk_widget_set_usize( GTK_WIDGET (ventana), 200, 100);
4652 gtk_window_set_title(GTK_WINDOW (ventana), "GTK Statusbar Example");
4653 gtk_signal_connect(GTK_OBJECT (ventana), "delete_event",
4654 (GtkSignalFunc) gtk_exit, NULL);
4656 vbox = gtk_vbox_new(FALSE, 1);
4657 gtk_container_add(GTK_CONTAINER(ventana), vbox);
4658 gtk_widget_show(vbox);
4660 status_bar = gtk_statusbar_new();
4661 gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4662 gtk_widget_show (status_bar);
4664 context_id = gtk_statusbar_get_context_id(
4665 GTK_STATUSBAR(status_bar), "Statusbar example");
4667 boton = gtk_button_new_with_label("push item");
4668 gtk_signal_connect(GTK_OBJECT(boton), "clicked",
4669 GTK_SIGNAL_FUNC (push_item), &context_id);
4670 gtk_box_pack_start(GTK_BOX(vbox), boton, TRUE, TRUE, 2);
4671 gtk_widget_show(boton);
4673 boton = gtk_button_new_with_label("pop last item");
4674 gtk_signal_connect(GTK_OBJECT(boton), "clicked",
4675 GTK_SIGNAL_FUNC (pop_item), &context_id);
4676 gtk_box_pack_start(GTK_BOX(vbox), boton, TRUE, TRUE, 2);
4677 gtk_widget_show(boton);
4679 /* siempre mostramos la ventana en el último paso para que todo se
4680 * dibuje en la pantalla de un golpe. */
4681 gtk_widget_show(ventana);
4687 /* Final del ejemplo */
4690 <!-- ----------------------------------------------------------------- -->
4691 <sect1>Entrada de texto
4693 El <em/widget/ Entry permite mostrar e introducir texto en una línea
4694 de un cuadro de diálogo. El texto se puede poner con llamadas a funciones
4695 que permiten reemplazar, preañadir o añadir el texto al contenido
4696 actual del <em/widget/ Entry.
4698 Hay dos funciones para crear un <em/widget/ Entry:
4701 GtkWidget *gtk_entry_new( void );
4703 GtkWidget *gtk_entry_new_with_max_length( guint16 max );
4706 La primera sirve para crear un nuevo <em/widget/ Entry, mientras que la
4707 segunda crea el <em/widget/ y además establece un límite en la longitud
4708 del texto que irá en el mismo.
4710 hay varias funciones que sirven para alterar el que texto que se está
4711 en el <em/widget/ Entry.
4714 void gtk_entry_set_text( GtkEntry *entry,
4715 const gchar *text );
4717 void gtk_entry_append_text( GtkEntry *entry,
4718 const gchar *text );
4720 void gtk_entry_prepend_text( GtkEntry *entry,
4721 const gchar *text );
4724 La función <tt/gtk_entry_set_text/ cambia el contenido actual del
4725 <em/widget/ Entry. Las funciones <tt/gtk_entry_append_text/ y
4726 <tt/gtk_entry_prepend_text/ permiten añadir o preañadir texto.
4728 Las función siguientes permiten decir donde poner el punto de inserción.
4731 void gtk_entry_set_position( GtkEntry *entry,
4735 Se pueden obtener los contenidos del <em/widget/ llamando a la función
4736 que se describe a continuación. Obtener los contenidos del <em/widget/
4737 puede ser útil en las funciones de llamada descritas más adelante.
4740 gchar *gtk_entry_get_text( GtkEntry *entry );
4743 Si quiere impedir que alguien cambie el contenido del <em/widget/ escribiendo
4744 en él, utilice la función
4747 void gtk_entry_set_editable( GtkEntry *entry,
4748 gboolean editable );
4751 Esta función permite camiar el estado de edición de un <em/widget/ Entry,
4752 siendo el argumento <tt/editable/ TRUE o FALSE.
4754 Si estamos utilizando el <em/widget/ Entry en un sitio donde no queremos
4755 que el texto que se introduce sea visible, como por ejemplo cuando estamos
4756 introduciendo una clave, podemos utilizar la función siguiente, que también
4757 admite como argumento una bandera booleana.
4760 void gtk_entry_set_visibility( GtkEntry *entry,
4764 Se puede seleccionar una región del texto utilizando la siguiente función.
4765 Esta función se puede utilizar después de poner algún texto por defecto en
4766 el <em/widget/, haciéndole fácil al usuario eliminar este texto.
4769 void gtk_entry_select_region( GtkEntry *entry,
4774 Si queremos saber el momento en el que el usuario ha introducido el texto,
4775 podemos conectar con las señales <tt/activate/ o <tt/changed/. <tt/activate/
4776 se activa cuando el usuario aprieta la tecla enter en el <em/widget/.
4777 <tt/changed/ se activa cuando cambia algo del texto, p.e. cuando se introduce
4778 o se elimina algún carácter.
4781 /* Principio del ejemplo entry entry.c */
4783 #include <gtk/gtk.h>
4785 void enter_callback(GtkWidget *widget, GtkWidget *entry)
4788 entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
4789 printf("Entry contents: %s\n", entry_text);
4792 void entry_toggle_editable (GtkWidget *checkbutton,
4795 gtk_entry_set_editable(GTK_ENTRY(entry),
4796 GTK_TOGGLE_BUTTON(checkbutton)->active);
4799 void entry_toggle_visibility (GtkWidget *checkbutton,
4802 gtk_entry_set_visibility(GTK_ENTRY(entry),
4803 GTK_TOGGLE_BUTTON(checkbutton)->active);
4806 int main (int argc, char *argv[])
4810 GtkWidget *vbox, *hbox;
4815 gtk_init (&argc, &argv);
4817 /* crear una nueva ventana */
4818 ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
4819 gtk_widget_set_usize( GTK_WIDGET (ventana), 200, 100);
4820 gtk_window_set_title(GTK_WINDOW (ventana), "GTK Entry");
4821 gtk_signal_connect(GTK_OBJECT (ventana), "delete_event",
4822 (GtkSignalFunc) gtk_exit, NULL);
4824 vbox = gtk_vbox_new (FALSE, 0);
4825 gtk_container_add (GTK_CONTAINER (ventana), vbox);
4826 gtk_widget_show (vbox);
4828 entry = gtk_entry_new_with_max_length (50);
4829 gtk_signal_connect(GTK_OBJECT(entry), "activate",
4830 GTK_SIGNAL_FUNC(enter_callback),
4832 gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4833 gtk_entry_append_text (GTK_ENTRY (entry), " world");
4834 gtk_entry_select_region (GTK_ENTRY (entry),
4835 0, GTK_ENTRY(entry)->text_length);
4836 gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4837 gtk_widget_show (entry);
4839 hbox = gtk_hbox_new (FALSE, 0);
4840 gtk_container_add (GTK_CONTAINER (vbox), hbox);
4841 gtk_widget_show (hbox);
4843 check = gtk_check_button_new_with_label("Editable");
4844 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4845 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4846 GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
4847 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
4848 gtk_widget_show (check);
4850 check = gtk_check_button_new_with_label("Visible");
4851 gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4852 gtk_signal_connect (GTK_OBJECT(check), "toggled",
4853 GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
4854 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
4855 gtk_widget_show (check);
4857 boton = gtk_button_new_with_label ("Close");
4858 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
4859 GTK_SIGNAL_FUNC(gtk_exit),
4860 GTK_OBJECT (ventana));
4861 gtk_box_pack_start (GTK_BOX (vbox), boton, TRUE, TRUE, 0);
4862 GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
4863 gtk_widget_grab_default (boton);
4864 gtk_widget_show (boton);
4866 gtk_widget_show(ventana);
4871 /* fin del ejemplo */
4874 <!-- ----------------------------------------------------------------- -->
4875 <sect1>Botones <em/spin/
4877 El <em/widget/ botón <em/spin/ se utiliza normalmente para permitir
4878 que el usuario elija un valor de un rango de valores. Consiste en una
4879 caja para la entrada de texto con una flecha para arriba y otra para
4880 abajo justo al lado de la caja. Si utilizamos alguna de las flechas
4881 haremos que el valor suba o baje dentro del rango de los valores
4882 posibles. También podemos introducir directamente un valor específico
4883 (utilizando la caja de texto).
4885 El <em/widget/ botón <em/spin/ permite tener valores con un número de
4886 cifras decimales (o sin cifras decimales) y la posibilidad de
4887 incrementarlo/decrementarlo en pasos configurables. La acción de
4888 matener pulsado uno de los botones puede resultar (es opcional) en una
4889 aceleración del cambio en el valor de acuerdo con el tiempo que se
4892 El botón <em/spin/ utiliza un objeto <ref id="sec_Adjustment"
4893 name="Ajuste"> para conservar la información referente al rango de
4894 valores que puede tomar el botón <em/spin/. Esto hace que el
4895 <em/widget/ botón <em/spin/ sea muy poderoso.
4897 Recuerde que un <em/widget/ ajuste puede crearse con la siguiente
4898 función, que ilustra la información que se guarda:
4901 GtkObject *gtk_adjustment_new( gfloat valor,
4905 gfloat incremento_pagina,
4906 gfloat tamano_pagina );
4909 Estos atributos de un ajuste se utilizan en un botón <em/spin/ de la
4913 <item> <tt/valor/: valor inicial del botón <em/spin/
4914 <item> <tt/inferior/: valor inferior del rango
4915 <item> <tt/superior/: valor superior del rango
4916 <item> <tt/paso/: valor a incrementar/decrementar cuando pulsemos el
4917 botón 1 en una flecha
4918 <item> <tt/incremento_pagina/: valor a incrementar/decrementar cuando
4919 pulsemos el botón 2 en una flecha
4920 <item> <tt/tamano_pagina/: no se utiliza
4923 Además, se puede utilizar el botón 3 para saltar directamente a los
4924 valores <tt/superior/ o <tt/inferior/ cuando se pulsa en una de las
4925 flechas. Veamos como crear un botón <em/spin/:
4928 GtkWidget *gtk_spin_button_new( GtkAdjustment *ajuste,
4933 El argumento <tt/aceleracion/ toma un valor entre 0.0 y 1.0 e indica
4934 la aceleración que tendrá el botón <em/spin/. El argumento
4935 <tt/digitos/ especifica el número de cifras decimales con que se
4938 Se puede reconfigurar un botón <em/spin/ después de su creación
4939 utilizando la función:
4942 void gtk_spin_button_configure( GtkSpinButton *boton_spin,
4943 GtkAdjustment *ajuste,
4948 El argumento <tt/boton_spin/ especifica el botón <em/spin/ que va a
4949 reconfigurarse. El resto de argumentos son los que acabamos de
4952 Podemos establecer y obtener el ajuste utilizando las dos funciones
4956 void gtk_spin_button_set_adjustment( GtkSpinButton *boton_spin,
4957 GtkAdjustment *ajuste );
4959 GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *boton_spin );
4962 El número de cifras decimales también puede alterarse utilizando:
4965 void gtk_spin_button_set_digits( GtkSpinButton *boton_spin,
4969 El valor que un botón <em/spin/ está mostrando actualmente puede
4970 cambiarse utilizando las siguientes funciones:
4973 void gtk_spin_button_set_value( GtkSpinButton *boton_spin,
4977 El valor actual de un botón <em/spin/ puede obtenerse como un entero o
4978 como un flotante con las funciones siguientes:
4981 gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *boton_spin );
4983 gint gtk_spin_button_get_value_as_int( GtkSpinButton *boton_spin );
4986 Si quiere alterar el valor de un <em/spin/ de forma relativa a su
4987 valor actual, puede utilizar la siguiente función:
4990 void gtk_spin_button_spin( GtkSpinButton *boton_spin,
4991 GtkSpinType direccion,
4992 gfloat incremento );
4995 El parámetro <tt/direccion/ puede tomar uno de los valores siguientes:
4998 <item> GTK_SPIN_STEP_FORWARD
4999 <item> GTK_SPIN_STEP_BACKWARD
5000 <item> GTK_SPIN_PAGE_FORWARD
5001 <item> GTK_SPIN_PAGE_BACKWARD
5002 <item> GTK_SPIN_HOME
5004 <item> GTK_SPIN_USER_DEFINED
5007 Trataré de explicar todas las posibilidades que ofrece esta
5008 función. Algunos de los valores que puede utilizar <tt/direccion/
5009 hacen que se utilicen valores que están almacenados en el objeto
5010 Ajuste que está asociado con el botón <em/spin/.
5012 GTK_SPIN_STEP_FORWARD y GTK_SPIN_STEP_BACKWARD aumentan o disminuyen
5013 (respectivamente) el valor del botón <em/spin/ por la cantidad
5014 especificada por <tt/incremento/, a menos que <tt/incremento/ sea
5015 igual a 0, en cuyo caso el valor se aumentará o disminuirá por el
5016 valor especificado en <tt/paso/ dentro del Ajuste.
5018 GTK_SPIN_PAGE_FORWARD y GTK_SPIN_PAGE_BACKWARD sencillamente alteran
5019 el valor del botón <em/spin/ por la cantidad <tt/incremento/.
5021 GTK_SPIN_HOME hace que el botón <em/spin/ tenga el mismo valor que el
5022 valor inferior del rango Ajuste.
5024 GTK_SPIN_END hace que el botón <em/spin/ tenga el mismo valor que el
5025 valor superior del rango Ajuste.
5027 GTK_SPIN_USER_DEFINED cambia el valor del botón <em/spin/ por la
5028 cantidad especificada.
5030 Ahora vamos a dejar de lado las funciones para establecer y obtener el
5031 rango de los atributos del botón <em/spin/, y vamos a pasar a las
5032 funciones que afectan a la apariencia y al comportamiento del
5033 <em/widget/ botón <em/spin/ en sí mismo.
5035 La primera de estas funciones se utiliza para restringir el contenido
5036 de la caja de texto de un botón <em/spin/ a un valor numérico. Esto
5037 evita que un usuario introduzca cualquier valor no númerico.
5040 void gtk_spin_button_set_numeric( GtkSpinButton *boton_spin,
5041 gboolean numerico );
5044 Puede indicar si un botón <em/spin/ pasará del límite superior al
5045 inferior utilizando la siguiente función:
5048 void gtk_spin_button_set_wrap( GtkSpinButton *boton_spin,
5052 Puede hacer que un botón <em/spin/ redondee su valor al <tt/paso/ más
5053 cercano, que se indica cuando creamos el Ajuste que se utiliza con el
5054 botón <em/spin/. Para hacer que redondee tenemos que utilizar la
5058 void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *boton_spin,
5059 gboolean redondear );
5062 Para política de actualización de un botón <em/spin/ puede cambiarse
5063 con la siguiente función:
5066 void gtk_spin_button_set_update_policy( GtkSpinButton *boton_spin,
5067 GtkSpinButtonUpdatePolicy politica );
5070 <!-- TODO: find out what this does - TRG -->
5072 Los valores posibles de <tt/politica/ son o GTK_UPDATE_ALWAYS o
5073 GTK_UPDATE_IF_VALID.
5075 Estas políticas afectan al comportamiento de un botón <em/spin/ cuando
5076 se lee el texto insertado en la caja de texto y se sincroniza con los
5079 En el caso de GTK_UPDATE_IF_VALID el valor de un botón <em/spin/
5080 cambiará si el texto introducido es un valor numérico contenido dentro
5081 del rango especificado por el Ajuste. En caso contrario el texto
5082 introducido se convierte al valor del botón <em/spin/.
5084 En caso de utilizar GTK_UPDATE_ALWAYS se ignorarán los errores que
5085 puedan ocurrir en la conversión del texto en un valor numérico.
5087 El aspecto de los botones utilizados en un botón <em/spin/ pueden
5088 cambiarse utilizando las siguientes funciones:
5091 void gtk_spin_button_set_shadow_type( GtkSpinButton *boton_spin,
5092 GtkShadowType tipo_sombra );
5095 Como siempre, el <tt/tipo_sombra/ puede ser uno de los siguientes:
5098 <item> GTK_SHADOW_IN
5099 <item> GTK_SHADOW_OUT
5100 <item> GTK_SHADOW_ETCHED_IN
5101 <item> GTK_SHADOW_ETCHED_OUT
5104 Finalmente, puede pedir de forma explícita que un botón <em/spin/ se
5105 actualice a sí mismo:
5108 void gtk_spin_button_update( GtkSpinButton *boton_spin );
5111 Es hora de un nuevo ejemplo.
5114 /* principio del ejemplo spinbutton spinbutton.c */
5116 #include <gtk/gtk.h>
5118 static GtkWidget *spinner1;
5120 void toggle_snap( GtkWidget *widget,
5121 GtkSpinButton *spin )
5123 gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)->active);
5126 void toggle_numeric( GtkWidget *widget,
5127 GtkSpinButton *spin )
5129 gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)->active);
5132 void change_digits( GtkWidget *widget,
5133 GtkSpinButton *spin )
5135 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
5136 gtk_spin_button_get_value_as_int (spin));
5139 void get_value( GtkWidget *widget,
5144 GtkSpinButton *spin;
5146 spin = GTK_SPIN_BUTTON (spinner1);
5147 etiqueta = GTK_LABEL (gtk_object_get_user_data (GTK_OBJECT (widget)));
5148 if (GPOINTER_TO_INT (data) == 1)
5149 sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
5151 sprintf (buf, "%0.*f", spin->digits,
5152 gtk_spin_button_get_value_as_float (spin));
5153 gtk_label_set_text (etiqueta, buf);
5163 GtkWidget *main_vbox;
5166 GtkWidget *spinner2;
5169 GtkWidget *etiqueta;
5170 GtkWidget *val_label;
5173 /* Inicializar GTK */
5174 gtk_init(&argc, &argv);
5176 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5178 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
5179 GTK_SIGNAL_FUNC (gtk_main_quit),
5182 gtk_window_set_title (GTK_WINDOW (ventana), "Spin Button");
5184 main_vbox = gtk_vbox_new (FALSE, 5);
5185 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
5186 gtk_container_add (GTK_CONTAINER (ventana), main_vbox);
5188 frame = gtk_frame_new ("Not accelerated");
5189 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5191 vbox = gtk_vbox_new (FALSE, 0);
5192 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5193 gtk_container_add (GTK_CONTAINER (frame), vbox);
5195 /* spin del día, mes y año */
5197 hbox = gtk_hbox_new (FALSE, 0);
5198 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
5200 vbox2 = gtk_vbox_new (FALSE, 0);
5201 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5203 etiqueta = gtk_label_new ("Day :");
5204 gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5205 gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5207 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
5209 spinner = gtk_spin_button_new (adj, 0, 0);
5210 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5211 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5213 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5215 vbox2 = gtk_vbox_new (FALSE, 0);
5216 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5218 etiqueta = gtk_label_new ("Month :");
5219 gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5220 gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5222 adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
5224 spinner = gtk_spin_button_new (adj, 0, 0);
5225 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5226 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5227 GTK_SHADOW_ETCHED_IN);
5228 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5230 vbox2 = gtk_vbox_new (FALSE, 0);
5231 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5233 etiqueta = gtk_label_new ("Year :");
5234 gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5235 gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5237 adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
5239 spinner = gtk_spin_button_new (adj, 0, 0);
5240 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
5241 gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
5243 gtk_widget_set_usize (spinner, 55, 0);
5244 gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5246 frame = gtk_frame_new ("Accelerated");
5247 gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5249 vbox = gtk_vbox_new (FALSE, 0);
5250 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5251 gtk_container_add (GTK_CONTAINER (frame), vbox);
5253 hbox = gtk_hbox_new (FALSE, 0);
5254 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5256 vbox2 = gtk_vbox_new (FALSE, 0);
5257 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5259 etiqueta = gtk_label_new ("Value :");
5260 gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5261 gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5263 adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
5265 spinner1 = gtk_spin_button_new (adj, 1.0, 2);
5266 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
5267 gtk_widget_set_usize (spinner1, 100, 0);
5268 gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
5270 vbox2 = gtk_vbox_new (FALSE, 0);
5271 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5273 etiqueta = gtk_label_new ("Digits :");
5274 gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
5275 gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
5277 adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
5278 spinner2 = gtk_spin_button_new (adj, 0.0, 0);
5279 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
5280 gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
5281 GTK_SIGNAL_FUNC (change_digits),
5282 (gpointer) spinner2);
5283 gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
5285 hbox = gtk_hbox_new (FALSE, 0);
5286 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5288 boton = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
5289 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
5290 GTK_SIGNAL_FUNC (toggle_snap),
5292 gtk_box_pack_start (GTK_BOX (vbox), boton, TRUE, TRUE, 0);
5293 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (boton), TRUE);
5295 boton = gtk_check_button_new_with_label ("Numeric only input mode");
5296 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
5297 GTK_SIGNAL_FUNC (toggle_numeric),
5299 gtk_box_pack_start (GTK_BOX (vbox), boton, TRUE, TRUE, 0);
5300 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (boton), TRUE);
5302 val_label = gtk_label_new ("");
5304 hbox = gtk_hbox_new (FALSE, 0);
5305 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5306 boton = gtk_button_new_with_label ("Value as Int");
5307 gtk_object_set_user_data (GTK_OBJECT (boton), val_label);
5308 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
5309 GTK_SIGNAL_FUNC (get_value),
5310 GINT_TO_POINTER (1));
5311 gtk_box_pack_start (GTK_BOX (hbox), boton, TRUE, TRUE, 5);
5313 boton = gtk_button_new_with_label ("Value as Float");
5314 gtk_object_set_user_data (GTK_OBJECT (boton), val_label);
5315 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
5316 GTK_SIGNAL_FUNC (get_value),
5317 GINT_TO_POINTER (2));
5318 gtk_box_pack_start (GTK_BOX (hbox), boton, TRUE, TRUE, 5);
5320 gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
5321 gtk_label_set_text (GTK_LABEL (val_label), "0");
5323 hbox = gtk_hbox_new (FALSE, 0);
5324 gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
5326 boton = gtk_button_new_with_label ("Close");
5327 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
5328 GTK_SIGNAL_FUNC (gtk_widget_destroy),
5329 GTK_OBJECT (ventana));
5330 gtk_box_pack_start (GTK_BOX (hbox), boton, TRUE, TRUE, 5);
5332 gtk_widget_show_all (ventana);
5334 /* Entramos dentro del bucle de eventos */
5339 /* fin del ejemplo */
5342 <!-- ----------------------------------------------------------------- -->
5343 <sect1>Caja combinada (<em/Combo Box/)
5345 La caja combinada o <em/combo box/ es otro sencillo <em/widget/
5346 exclusivamente compuesto por otros <em/widgets/. Desde el punto de
5347 vista del usuario, el <em/widget/ consiste en una caja para la
5348 introducción de texto y un menú desplegable desde el que el usuario
5349 puede seleccionar una de un conjunto predefinido de entradas. De forma
5350 alternativa, el usuario puede introducir una opción diferente en la
5353 El siguiente extracto de la estructura que define un Combo Box
5354 identifica algunos de sus componentes:
5367 Como puede ver, el Combo Box tiene dos partes principales que tiene
5368 que conocer: un <em/widget entry/ y un <em/widget list/ (lista).
5370 Lo primero, para crear un combo box, utilice:
5373 GtkWidget *gtk_combo_new( void );
5376 Ahora, si quiere indicar la cadena que debe aparecer en la sección
5377 entry del combo box, podrá hacerlo manipulando directamente el
5378 <em/widget/ <tt/entry/:
5381 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "Mi cadena.");
5384 Para introducir valores en la lista desplegable, puede utilizar la
5388 void gtk_combo_set_popdown_strings( GtkCombo *combo,
5392 Antes de llamar a esta función, tiene que ensamblar una GList con las
5393 cadenas que quiere. GList es una implementación de una lista enlazada
5394 que forma parte de <ref id="sec_glib" name="glib">, una biblioteca
5395 base de GTK. Por el momento, la explicación fea y rápida es que tiene
5396 que crear un puntero GList, hacerlo igual a NULL, y añadirle cadenas
5397 de texto con la función
5400 GList *g_list_append( GList *glist,
5404 Es importante que inicialice el puntero GList a NULL antes de
5405 utilizarlo. El valor devuelto por la función g_list_append debe
5406 utilizarse como el nuevo puntero a la GList.
5408 Aquí tenemos un trozo de código típico para crear un conjunto de
5414 glist = g_list_append(glist, "Cadena 1");
5415 glist = g_list_append(glist, "Cadena 2");
5416 glist = g_list_append(glist, "Cadena 3");
5417 glist = g_list_append(glist, "Cadena 4");
5419 gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ;
5422 A partir de este momento tendrá un combo box completo funcionando. Hay
5423 unos cuantos aspectos de su funcionamiento que puede cambiar. Para
5424 hacerlo tiene las funciones siguientes:
5427 void gtk_combo_set_use_arrows( GtkCombo *combo,
5430 void gtk_combo_set_use_arrows_always( GtkCombo *combo,
5433 void gtk_combo_set_case_sensitive( GtkCombo *combo,
5437 <tt/gtk_combo_set_use_arrows()/ le deja al usuario cambiar el valor
5438 del combo box utilizando las flechas de arriba/abajo. Utilizando estas
5439 teclas no haremos salir la lista, pero se reemplazará el texto actual
5440 del combo box con el siguiente elemento de la lista (superior o
5441 inferior, según la tecla que se pulse). Esto se consigue buscando en
5442 la lista el elemento correspondiente al valor actual del combo box y
5443 seleccionando el anterior o el posterior (según corresponda).
5444 Normalmente en una caja de entrada de texto las flechas se utilizan
5445 para cambiar el foco (ie. el <em/widget/ que recibe la entrada del
5446 teclado), pero en este caso será el TAB quien se ocupe. Cuando el
5447 elemento actual sea el último de la lista y presione la flecha abajo
5448 se cambiará el foco (lo mismo se aplica cuando estamos sobre el primer
5449 elemento y pulsamos la tecla arriba).
5451 Si el valor actual en la caja de entrada de texto no está en la lista,
5452 entonces se desactiva la función de <tt/gtk_combo_set_use_arrows()/.
5454 <tt/gtk_combo_set_use_arrows_always()/ igualmente permite la
5455 utilización de las flechas arriba/abajo para cambiar el elemento
5456 seleccionado por el siguiente/anterior de la lista, pero además trata
5457 la lista como si fuese circular (ie. pasa del último al primer
5458 elemento), desactivando completamente la utilidad de las teclas arriba
5459 y abajo para cambiar el foco.
5461 <tt/gtk_combo_set_case_sensitive()/ cambia entre una búsqueda por la
5462 lista que discrimine entre mayúsculas y minúsculas y una búsqueda que
5463 no discrimine. Se utiliza cuando se quiere que el <em/widget/ combo
5464 complete el valor que se está introduciendo con un valor de la
5465 lista. Dependiendo de esta función, se completará distinguiendo entre
5466 mayúsculas y minúsculas o no. El <em/widget/ combo completará la
5467 entrada actual si el usuario presiona la combinación de teclas MOD-1 y
5468 `Tab'. MOD-1 normalmente es la tecla `Alt'. Hay algunos
5469 administradores de ventanas que también utilizan esta combinación de
5470 teclas, con lo que perderemos su posible utilización por parte de GTK.
5472 Ahora que tenemos un combo box que actua como queremos que actue, todo
5473 lo que nos queda es saber como hay que hacer para obtener los datos
5474 que nos puede proporcionar. Esto es relativamente sencillo. La mayoría
5475 del tiempo, de lo único que tiene que preocuparse es de obtener datos
5476 de la caja de texto. Podemos acceder a la caja de texto mediante
5477 GTK_ENTRY(GTK_COMBO(combo)->entry). Las dos cosas que son interesantes
5478 hacer con esta caja son: enlazarla con la señal <tt/activate/, que
5479 indica que el usuario ha presionado la tecla «Intro», y leer el
5480 texto. Lo primero podemos hacerlo utilizando algo así:
5483 gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate",
5484 GTK_SIGNAL_FUNC (mi_funcion_respuesta), mis_datos);
5487 Para conseguir el texto que hay en la caja en cualquier momento sólo
5488 tenemos que utilizar la función siguiente:
5491 gchar *gtk_entry_get_text(GtkEntry *entry);
5499 cadena = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
5502 Esto es todo lo interesante. Existe otra función,
5505 void gtk_combo_disable_activate(GtkCombo *combo);
5508 que permite desactivar la señal <tt/activate/ en el <em/widget/ entry
5509 dentro del combo box. Personalmente no se me ocurre ningún motivo para
5510 utilizarla, pero existir existe.
5512 <!-- There are also a function to set the string on a particular item, void
5513 gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
5514 *item_value), but this requires that you have a pointer to the
5515 appropriate GtkItem. Frankly, I have no idea how to do that.
5518 <!-- ************************************** -->
5520 <!-- ----------------------------------------------------------------- -->
5521 <sect1> Selección de Color
5523 El <em/widget/ selección de color, nos permite (¡sorpresa!) la selección
5524 interactiva de colores. Este <em/widget/ compuesto le permite al usuario
5525 seleccionar un color manipulando los tripletes RGB (rojo, verde y azul) y
5526 HSV (tono, saturación, valor). Para conseguirlo puede ajustar cada variable
5527 mediante las regletas o introduciendo directamente el valor deseado.
5528 También puede pinchar en la rueda de colores y seleccionar así el color
5529 deseado. También se puede establecer, opcionalmente, la transparencia
5532 El <em/widget/ de selección de color emite (por ahora) sólo una señal,
5533 <tt/color_changed/, que se emite cuando cambia el color seleccionado,
5534 ya sea mediante un cambio que haga el usuario o median el resultado
5535 de una llamada a la función <tt/gtk_color_selection_set_color()/.
5537 Echémosle un vistazo a lo que nos ofrece el <em/widget/ de selección de color.
5538 El <em/widget/ tiene dos «sabores» diferentes; <tt/gtk_color_selection/
5539 y <tt/gtk_color_selection_dialog/:
5542 GtkWidget *gtk_color_selection_new( void );
5545 Probablemente no utilizará este constructor directamente. Crea un <em/widget/
5546 GtkColorSelection huérfano al que le tendrá que asignarle un padre. El
5547 <em/widget/ GtkColorSelection está heredado del <em/widget/ GtkVBox.
5550 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
5553 Éste es el constructor del cuadro de selección de color más común. Crea un
5554 <tt/GtkColorSelectionDialog/, heredado de un <tt/GtkDialog/. Consiste en un
5555 <tt/GtkFrame/ con un <tt/GtkColorSelection/, un <tt/GtkHSeparator/ y un
5556 <tt/GtkHBox/ con tres botones, «Aceptar», «Cancelar» y «Ayuda».
5557 Puede utilizar estos botones accediendo a los <em/widgets/ <tt/ok_button/,
5558 <tt/cancel_button/ y <tt/help_button/ de la estructura GtkColorSelectionDialog,
5559 (es decir GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button).
5562 void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel,
5563 GtkUpdateType policy );
5566 Esta función se utiliza para indicar la política de actuación. La política
5567 por defecto es <tt/GTK_UPDATE_CONTINUOUS/ que significa que el color
5568 seleccionado se actualiza continuamente cuando el usuario arrastra la barra
5569 o selecciona con el ratón un color de la rueda de colores. Si tiene problemas
5570 de rendimiento, puede poner la política <tt/GTK_UPDATE_DISCONTINUOUS/ o
5571 <tt/GTK_UPDATE_DELAYED/.
5574 void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
5578 El <em/widget/ de selección de color admite el ajuste de la transparencia
5579 de un color (también conocido como el canal alfa). Esta opción está
5580 desactivada por defecto. Si se llama a esta función con <tt/use_opacity/
5581 como TRUE se activa la transparencia. Si se utiliza <tt/use_opacity/ como
5582 FALSE se desactiva la transparencia.
5585 void gtk_color_selection_set_color( GtkColorSelection *colorsel,
5589 Puede poner el color actual explicitamente haciendo uso de esta función con
5590 un puntero a un vector de colores (de tipo <tt/gdouble/). La longitud del
5591 vector depende de si está activada la transparencia. La posición 0 contiene
5592 la componente roja del color, la 1 contiene la verde, la 2 la azul y la
5593 transparencia está en la posición 3 (solamente si está activada la
5594 transparencia, ver <tt/gtk_color_selection_set_opacity()/). Todos los
5595 valores se encuentran entre 0.0 y 1.0.
5598 void gtk_color_selection_get_color( GtkColorSelection *colorsel,
5602 Cuando necesite preguntar por el color actual, normalmente cuando haya
5603 recibido una señal <tt/color_changed/, utilice esta función. <tt/color/
5604 es un puntero al vector de colores que se rellenará. Ver la descripción
5605 de la función <tt/gtk_color_selection_set_color()/ para conocer la
5606 estructura de este vector.
5608 <!-- Need to do a whole section on DnD - TRG
5612 The color sample areas (right under the hue-saturation wheel) supports
5613 drag and drop. The type of drag and drop is "application/x-color". The
5614 message data consists of an array of 4 (or 5 if opacity is enabled)
5615 gdouble values, where the value at position 0 is 0.0 (opacity on) or
5616 1.0 (opacity off) followed by the red, green and blue values at
5617 positions 1,2 and 3 respectively. If opacity is enabled, the opacity
5618 is passed in the value at position 4.
5621 Aquí tenemos un pequeño ejemplo que muestra el uso de
5622 <tt/GtkColorSelectionDialog/. El programa muestra una ventana con una
5623 zona de dibujo. Pulsando en ella se abre un cuadro de diálogo de
5624 selección del color, y cambiando el color en el cuadro de diálogo se
5625 cambia el color de fondo de la zona de dibujo.
5628 /* principio del ejemplo colorsel colorsel.c */
5631 #include <gdk/gdk.h>
5632 #include <gtk/gtk.h>
5634 GtkWidget *colorseldlg = NULL;
5635 GtkWidget *drawingarea = NULL;
5637 /* Manejador del cambio de color */
5639 void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel)
5643 GdkColormap *colormap;
5645 /* Obtener el mapa de colores de la zona de dibujo */
5647 colormap = gdk_window_get_colormap (drawingarea->window);
5649 /* Obtener el color actual */
5651 gtk_color_selection_get_color (colorsel,color);
5653 /* Meterlo en un entero sin signo de 16 bits (0..65535) e insertarlo
5654 en la estructura GdkColor */
5656 gdk_color.red = (guint16)(color[0]*65535.0);
5657 gdk_color.green = (guint16)(color[1]*65535.0);
5658 gdk_color.blue = (guint16)(color[2]*65535.0);
5660 /* Pedir memoria para el color */
5662 gdk_color_alloc (colormap, &gdk_color);
5664 /* Poner el color de fondo de la ventana */
5666 gdk_window_set_background (drawingarea->window, &gdk_color);
5668 /* Limpiar la ventana */
5670 gdk_window_clear (drawingarea->window);
5673 /* Manejador del evento Drawingarea */
5675 gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data)
5677 gint handled = FALSE;
5678 GtkWidget *colorsel;
5680 /* Comprobar si hemos recibido un evento de pulsación de botón */
5682 if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
5684 /* Sí, ¡tenemos un evento y todavía no está el colorseldlg! */
5688 /* Crear el cuadro de diálogo de selección del color */
5690 colorseldlg = gtk_color_selection_dialog_new("Select background color");
5692 /* Obtener el widget GtkColorSelection */
5694 colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
5696 /* Conectar con la señal «color_changed», darle al dato del
5697 cliente el valor del widget colorsel */
5699 gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
5700 (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
5702 /* Mostrar el cuadro de diálogo */
5704 gtk_widget_show(colorseldlg);
5710 /* Manipulador de los eventos cerrar y salir */
5712 void destroy_window (GtkWidget *widget, gpointer client_data)
5719 gint main (gint argc, gchar *argv[])
5723 /* Inicializa el toolkit, y elimina las opciones relacionadas con
5724 gtk incluidas en la línea de órdenes */
5726 gtk_init (&argc,&argv);
5728 /* Crea la ventana de más alto nivel, le da título y la política */
5730 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5731 gtk_window_set_title (GTK_WINDOW(ventana), "Color selection test");
5732 gtk_window_set_policy (GTK_WINDOW(ventana), TRUE, TRUE, TRUE);
5734 /* Enlaza con los eventos «delete» y «destroy», para que podamos
5737 gtk_signal_connect (GTK_OBJECT(ventana), "delete_event",
5738 (GtkSignalFunc)destroy_window, (gpointer)ventana);
5740 gtk_signal_connect (GTK_OBJECT(ventana), "destroy",
5741 (GtkSignalFunc)destroy_window, (gpointer)ventana);
5743 /* Crea la zona de dibujo, pone el tamaño y caza los eventos de los
5746 drawingarea = gtk_drawing_area_new ();
5748 gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
5750 gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
5752 gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
5753 (GtkSignalFunc)area_event, (gpointer)drawingarea);
5755 /* Add drawingarea to window, then show them both */
5757 gtk_container_add (GTK_CONTAINER(ventana), drawingarea);
5759 gtk_widget_show (drawingarea);
5760 gtk_widget_show (ventana);
5762 /* Entrar en el bucle principal de gtk (nunca sale de aquí) */
5766 /* Para satisfacer a los compiladores pijos */
5770 /* final del ejemplo */
5773 <!-- ----------------------------------------------------------------- -->
5774 <sect1> Selección de ficheros
5776 El <em/widget/ de selección de ficheros nos proporciona una forma
5777 rápida y sencilla de mostrar un cuadro de diálogo para la selección de
5778 un fichero. Ya viene con los botones Aceptar, Cancelar y Ayuda. Una
5779 magnifica ayuda para acortar el tiempo de programación.
5781 Para crear un nuevo cuadro de diálogo de selección de ficheros
5785 GtkWidget *gtk_file_selection_new( gchar *title );
5788 Para poner el nombre del fichero en el cuadro de diálogo, por
5789 ejemplo para poder utilizar un directorio o un fichero por defecto,
5793 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
5797 Para obtener el texto que el usuario ha introducido, utilice la función:
5800 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
5803 También hay punteros a los <em/widgets/ que contiene el cuadro de
5804 diálogo. Son los siguientes:
5809 <item>selection_entry
5810 <item>selection_text
5817 Lo más probable es que sólo utilice los punteros <tt/ok_button/,
5818 <tt/cancel_button/, y <tt/help_button/ para controlar cuando se pulsan.
5820 Aquí incluímos un ejemplo robado de <tt/testgtk.c/, modificado
5821 para que se puede ejecutar independientemente. Como puede ver, no es
5822 muy complicado crear un <em/widget/ para la selección de
5823 ficheros. Aunque aparezca el botón de ayuda en la pantalla, no hace
5824 nada y no tiene ninguna señal conectada.
5827 /* principio del ejemplo filesel filesel.c */
5829 #include <gtk/gtk.h>
5831 /* Obtener el nombre del fichero e imprimirlo en la consola */
5832 void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
5834 g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
5837 void destroy (GtkWidget *widget, gpointer data)
5842 int main (int argc, char *argv[])
5846 gtk_init (&argc, &argv);
5848 /* Crear un nuevo widget de selección de ficheros */
5849 filew = gtk_file_selection_new ("File selection");
5851 gtk_signal_connect (GTK_OBJECT (filew), "destroy",
5852 (GtkSignalFunc) destroy, &filew);
5853 /* Conectar el ok_button con la función file_ok_sel */
5854 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
5855 "clicked", (GtkSignalFunc) file_ok_sel, filew );
5857 /* Conectar el cancel_button con la destrucción del widget */
5858 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
5859 "clicked", (GtkSignalFunc) gtk_widget_destroy,
5860 GTK_OBJECT (filew));
5862 /* Damos el nombre del fichero, como si fuese un cuadro de diálogo para
5863 grabar ficheros y estuviesemos dando un nombre por defecto */
5864 gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
5867 gtk_widget_show(filew);
5871 /* fin del ejemplo */
5874 <!-- ***************************************************************** -->
5875 <sect> El <em/widget/ contenedor
5876 <!-- ***************************************************************** -->
5878 <!-- ----------------------------------------------------------------- -->
5879 <sect1> El <em/widget/ EventBox<label id="sec_EventBox">
5880 <label id="sec_The_EventBox_Widget">
5882 Algunos <em/widget/ gtk no tienen asociada una ventana X, por lo que
5883 sólo pueden dibujar en la de su padre. Debido a esto, no pueden
5884 recibir ningún evento y si tienen un tamaño incorrecto, no se
5885 recortarán correctamente por lo que puede que se sobreescriban ciertas
5886 zonas, etc... Si necesita este tipo de <em/widgets/, el EventBox es
5889 Cuando se ve por primera vez, el <em/widget/ EventBox puede parecer
5890 completamente inútil. No dibuja nada en la pantalla y no responde
5891 a ningún evento. Sin embargo, tiene una utilidad - proporciona una
5892 ventana X para su <em/widget/ hijo. Esto es importante ya que
5893 muchos <em/widgets/ GTK no tienen una ventana X asociada. No tener una
5894 ventana X ahorra memoria y mejora el rendimiento, pero tiene sus
5895 desventajas. Un <em/widget/ sin una ventana X no puede recibir
5896 eventos, y no realizará ningún recorte en sus contenidos. Aunque el
5897 nombre <em/EventBox/ enfatiza su función de manejador de eventos, el
5898 <em/widget/ también puede utilizarse para hacer los recortes.
5899 (Y más... ver el ejemplo más abajo.)
5901 Para crear un nuevo <em/widget/ EventBox, utilice:
5904 GtkWidget *gtk_event_box_new( void );
5907 Un <em/widget/ hijo puede añadirse a su EventBox así:
5910 gtk_container_add( GTK_CONTAINER(event_box), widget );
5913 El siguiente ejemplo demuestra los dos usos de EventBox - se crea
5914 una etiqueta que se recorta dentro de una pequeña caja, y hace
5915 que una pulsación del ratón en la misma finalice el programa.
5918 /* principio del ejemplo eventbox eventbox.c */
5920 #include <gtk/gtk.h>
5923 main (int argc, char *argv[])
5926 GtkWidget *event_box;
5927 GtkWidget *etiqueta;
5929 gtk_init (&argc, &argv);
5931 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5933 gtk_window_set_title (GTK_WINDOW (ventana), "Event Box");
5935 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
5936 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5938 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
5940 /* Crea un EventBox y lo añade a nuestra ventana superior */
5942 event_box = gtk_event_box_new ();
5943 gtk_container_add (GTK_CONTAINER(ventana), event_box);
5944 gtk_widget_show (event_box);
5946 /* Crea una larga etiqueta */
5948 etiqueta = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
5949 gtk_container_add (GTK_CONTAINER (event_box), etiqueta);
5950 gtk_widget_show (etiqueta);
5952 /* La recortamos. */
5953 gtk_widget_set_usize (etiqueta, 110, 20);
5955 /* Y enlazamos una acción con la etiqueta */
5956 gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
5957 gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
5958 GTK_SIGNAL_FUNC (gtk_exit), NULL);
5960 /* Otra cosa más que necesita una ventana X ... */
5962 gtk_widget_realize (event_box);
5963 gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
5965 gtk_widget_show (ventana);
5971 /* Final del ejemplo */
5974 <!-- ----------------------------------------------------------------- -->
5975 <sect1>El <em/widget/ alineamiento <label id="sec_Alignment">
5977 El <em/widget/ alineamiento (<em/alignment/) le permitirá colocar un
5978 <em/widget/ dentro de su ventana utilizando una posición y un tamaño
5979 relativos al mismo <em/widget/ de alineamiento. Por ejemplo, puede ser
5980 muy útil para centrar un <em/widget/ en la ventana.
5982 Sólo hay dos funciones asociadas con el <em/widget/ alineamiento:
5985 GtkWidget* gtk_alignment_new( gfloat xalign,
5990 void gtk_alignment_set( GtkAlignment *alignment,
5997 La primera función crea un nuevo <em/widget/ alineamiento con los
5998 parámetros especificados. La segunda función permite alterar los
5999 parámetros de un <em/widget/ alineamiento ya existente.
6001 Los cuatro parámetros de alineamiento son números en coma flotante que
6002 pueden tener variar entre 0.0 y 1.0. Los argumentos <tt/xalign/ e
6003 <tt/yalign/ afectan a la posición del <em/widget/ colocado dentro del
6004 <em/widget/ de alineamiento. Los argumentos <tt/xscale/ e <tt/yscale/
6005 afectan a la cantidad de espacio que ocupa el <em/widget/.
6007 Se le puede añadir un <em/widget/ hijo a un alineamiento utilizando:
6010 gtk_container_add( GTK_CONTAINER(alignment), child_widget );
6013 Para ver un ejemplo de utilización del <em/widget/ alineamiento,
6014 diríjase al ejemplo del <em/widget/ <ref id="sec_ProgressBar"
6015 name="Barra de progreso">.
6018 <!-- ----------------------------------------------------------------- -->
6019 <sect1> Contenedor fijo
6021 El contenedor fijo le permite situar <em/widgets/ en una posición fija
6022 dentro de su ventana, relativa a la esquina superior izquierda. La
6023 posición de los <em/widgets/ puede cambiarse dinámicamente.
6025 Sólo hay tres funciones asociadas al <em/widget/ contenedor fijo:
6028 GtkWidget* gtk_fixed_new( void );
6030 void gtk_fixed_put( GtkFixed *fixed,
6035 void gtk_fixed_move( GtkFixed *fixed,
6041 La función <tt/gtk_fixed_new/ permite la creación de un nuevo
6044 <tt/gtk_fixed_put/ situa <tt/widget/ dentro del contenedor <tt/fixed/
6045 en la posición especificada por <tt/x/ e <tt/y/.
6047 <tt/gtk_fixed_move/ permite que mover hacia una nuevo posición el
6048 <em/widget/ especificado.
6050 El ejemplo siguiente muestra como utilizar el contenedor fijo.
6053 /* principio del ejemplo fixed fixed.c */
6055 #include <gtk/gtk.h>
6057 /* Voy a ser un poco torpe y utilizar algunas variables
6058 * globales para almacenar la posición del widget que
6059 * hay dentro del contenedor */
6063 /* Esta función de llamada mueve el botón a una nueva
6064 * posición dentro del contenedor fijo. */
6065 void move_button( GtkWidget *widget,
6070 gtk_fixed_move( GTK_FIXED(fixed), widget, x, y);
6076 /* GtkWidget es el tipo de almacenamiento para los widgets */
6082 /* Inicializa GTK */
6083 gtk_init(&argc, &argv);
6085 /* Crear una nueva ventana */
6086 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6087 gtk_window_set_title(GTK_WINDOW(ventana), "Fixed Container");
6089 /* Aquí conectamos el evento "destroy" al manejador de la señal */
6090 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6091 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6093 /* Establecemos el ancho del borde la ventana */
6094 gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
6096 /* Creamos un contenedor fijo */
6097 fixed = gtk_fixed_new();
6098 gtk_container_add(GTK_CONTAINER(ventana), fixed);
6099 gtk_widget_show(fixed);
6101 for (i = 1 ; i <= 3 ; i++) {
6102 /* Crea un nuevo botón con la etiqueta "Press me" */
6103 boton = gtk_button_new_with_label ("Press me");
6105 /* Cuando el botón reciba la señal "pulsado", llamará a la función
6106 * move_button() pasándole el contenedor fijo como argumento. */
6107 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
6108 GTK_SIGNAL_FUNC (move_button), fixed);
6110 /* Esto mete el botón dentro de la ventana del window contenedor
6112 gtk_fixed_put (GTK_FIXED (fixed), boton, i*50, i*50);
6114 /* El paso final es mostrar el widget recien creado */
6115 gtk_widget_show (boton);
6118 /* Mostrar la ventana */
6119 gtk_widget_show (ventana);
6121 /* Entrar en el bucle principal */
6126 /* fin del ejemplo */
6129 <!-- ----------------------------------------------------------------- -->
6130 <sect1> Contenedor capa
6132 El contenedor capa es similar al contenedor fijo, excepto que permite
6133 implementar una zona de <em/scroll/ infinita (donde infinito significa
6134 menor de 2^32). Xwindows tiene una limitación en la que las ventanas
6135 pueden tener un máximo de 32767 <em/pixels/ de alto o de ancho. El
6136 contenedor capa sortea esta limitación con una exótica combinación de
6137 ventanas y <em/bits/ de gravedad, <!-- Si alguien entiende que
6138 significa esto: e98cuenc@criens.u-psud.fr --> para que puede tener un
6139 suave <em/scroll/ aún cuando utilice una gran cantidad de <em/widgets/
6140 hijos dentro de su zona de <em/scroll/.
6142 Podrá crear un contenedor capa utilizando:
6145 GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
6146 GtkAdjustment *vadjustment );
6149 Como puede observar, podrá especificar (de forma opcional) los objetos
6150 de ajuste que utilizará el <em/widget/ capa para hacer su <em/scroll/.
6152 Puede añadir y mover <em/widgets/ dentro del contenedor capa
6153 utilizando las dos funciones siguientes:
6156 void gtk_layout_put( GtkLayout *layout,
6161 void gtk_layout_move( GtkLayout *layout,
6167 El tamaño del contenedor capa se puede establecer utilizando la
6171 void gtk_layout_set_size( GtkLayout *layout,
6176 Los contenedores capa son uno de los poquísimos <em/widgets/ dentro de
6177 GTK que se repintan ellos mismos en la pantalla cuando se cambian
6178 utilizando las funciones anteriores (la inmensa mayoria de los
6179 <em/widgets/ mandan una petición a la cola que será procesada cuando
6180 se devuelva el control a la función <tt/gtk_main()/).
6182 Cuando quiera hacer una gran cantidad de cambios dentro del contenedor
6183 capa, podrá utilizar las dos funciones siguientes para desactivar y
6184 reactivar la característica de repintado:
6187 void gtk_layout_freeze( GtkLayout *layout );
6189 void gtk_layout_thaw( GtkLayout *layout );
6192 Las cuatro funciones finales a utilizar con los <em/widgets/capa son
6193 para la manipulación de los <em/widgets/ de ajuste horizontal y
6197 GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
6199 GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
6201 void gtk_layout_set_hadjustment( GtkLayout *layout,
6202 GtkAdjustment *adjustment );
6204 void gtk_layout_set_vadjustment( GtkLayout *layout,
6205 GtkAdjustment *adjustment);
6208 <!-- ----------------------------------------------------------------- -->
6209 <sect1> Marcos <label id="sec_Frames">
6211 Los marcos pueden utilizarse para meter uno o un grupo de
6212 <em/widgets/dentro de una caja puede ser (de forma opcional)
6213 etiquetada. La posición de la etiqueta y el estilo de la caja pueden
6216 Se puede crear un marco con la siguiente función:
6219 GtkWidget *gtk_frame_new( const gchar *etiqueta );
6222 La etiqueta se coloca por defecto en la esquina superior izquierda del
6223 marco. Si el argumento <tt/etiqueta/ es NULL no se mostrará ninguna
6224 etiqueta. Puede cambiarse el texto de la etiqueta utilizando la
6228 void gtk_frame_set_label( GtkFrame *frame,
6229 const gchar *etiqueta );
6232 La posición de la etiqueta se puede cambiar utilizado la función:
6235 void gtk_frame_set_label_align( GtkFrame *frame,
6240 <tt/xalign/ e <tt/yalign/ toman valores entre 0.0 y 1.0. <tt/yalign/
6241 no se actualmente no se utiliza. El valor por defecto de <tt/xalign/
6242 es 0.0, lo que coloca la etiqueta a la izquierda del marco.
6244 La siguiente función altera el estilo de la caja que se utiliza para
6248 void gtk_frame_set_shadow_type( GtkFrame *frame,
6249 GtkShadowType type);
6252 El argumento <tt/type/ puede tomar uno de los valores siguientes:
6255 <item> GTK_SHADOW_NONE
6256 <item> GTK_SHADOW_IN
6257 <item> GTK_SHADOW_OUT
6258 <item> GTK_SHADOW_ETCHED_IN (the default)
6259 <item> GTK_SHADOW_ETCHED_OUT
6262 El código siguiente ilustra la utilización del <em/widget/ marco.
6265 /* principio del ejemplo frame frame.c */
6267 #include <gtk/gtk.h>
6272 /* GtkWidget es el tipo de almacenamiento para los widgets */
6278 /* Inicializa GTK */
6279 gtk_init(&argc, &argv);
6281 /* Crea una nueva ventana */
6282 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6283 gtk_window_set_title(GTK_WINDOW(ventana), "Frame Example");
6285 /* Aquí conectamos el evento "destroy"al manejador de señal */
6286 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6287 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6289 gtk_widget_set_usize(ventana, 300, 300);
6291 /* Establecemos el ancho del borde de la ventana */
6292 gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
6295 frame = gtk_frame_new(NULL);
6296 gtk_container_add(GTK_CONTAINER(ventana), frame);
6298 /* Establece la etiqueta del marco */
6299 gtk_frame_set_label( GTK_FRAME(frame), "GTK Frame Widget" );
6301 /* Alinea la etiqueta a la derecha del marco */
6302 gtk_frame_set_label_align( GTK_FRAME(frame), 1.0, 0.0);
6304 /* Establece el estilo del marco */
6305 gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
6307 gtk_widget_show(frame);
6309 /* Muestra la ventana */
6310 gtk_widget_show (ventana);
6312 /* Entra dentro del bucle principal */
6317 /* fin del ejemplo */
6321 <!-- ----------------------------------------------------------------- -->
6322 <sect1> Marcos con proporciones fijas
6324 El <em/widget aspect frame/ (marco proporcional) es como el <em/widget
6325 frame/ (marco), excepto que conserva las proporciones (esto es, la
6326 relación entre el ancho y el alto) del <em/widget/ hijo, añadiendo
6327 espacio extra en caso de ser necesario. Esto es útil, por ejemplo, si
6328 quiere hacer una vista previa de una gran imagen. El tamaño de la
6329 vista previa debería variar cuando el usuario redimensione la ventana,
6330 pero la proporción tiene que coincidir con la de la imagen original.
6332 Para crear un nuevo marco proporcional utilice:
6335 GtkWidget *gtk_aspect_frame_new( const gchar *etiqueta,
6342 <tt/xalign/ e <tt/yalign/ indican la alineación exactamente igual que
6343 con los <em/widgets Alignment/. Si <tt/obey_child/ es TRUE, la
6344 proporción de un <em/widget/ hijo será la misma que la proporción del
6345 tamaño ideal que éste pida. En caso contrario, vendrá dada por
6348 Para cambiar las opciones de un marco proporcional ya existente, puede
6352 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
6359 Como por ejemplo, el siguiente programa utiliza un marco proporcional
6360 para mostrar una zona de dibujo cuyas proporciones siempre será de
6361 2:1, no importa como el usuario redimensione la ventana.
6364 /* principio del ejemplo aspectframe aspectframe.c */
6366 #include <gtk/gtk.h>
6369 main (int argc, char *argv[])
6372 GtkWidget *aspect_frame;
6373 GtkWidget *drawing_area;
6374 gtk_init (&argc, &argv);
6376 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6377 gtk_window_set_title (GTK_WINDOW (ventana), "Aspect Frame");
6378 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6379 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6380 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
6382 /* Crear un aspect_frame y añadirlo a nuestra ventana superior */
6384 aspect_frame = gtk_aspect_frame_new ("2x1", /* etiqueta */
6387 2, /* tamañox/tamañoy = 2 */
6388 FALSE /* ignorar el aspecto del hijo */);
6390 gtk_container_add (GTK_CONTAINER(ventana), aspect_frame);
6391 gtk_widget_show (aspect_frame);
6393 /* Añadir un widget hijo al marco proporcional */
6395 drawing_area = gtk_drawing_area_new ();
6397 /* Pediremos una ventana de 200x200, pero el marco proporcional
6398 * sólo no dejará una ventana de 200x100, ya que tenemos una
6399 * relación de 2x1 */
6400 gtk_widget_set_usize (drawing_area, 200, 200);
6401 gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
6402 gtk_widget_show (drawing_area);
6404 gtk_widget_show (ventana);
6408 /* fin del ejemplo */
6411 <!-- ----------------------------------------------------------------- -->
6413 <sect1> El <em/widget/ ventana dividida (<em/Paned Window/)
6415 El <em/widget/ ventana dividida es útil para cuando se quiere dividir
6416 una zona en dos partes, con un tamaño relativo controlado por el
6417 usuario. Entre las dos porciones de la ventana se dibuja un separador
6418 con un botoncito que el usuario puede arrastrar para cambiar el tamaño
6419 de cada zona. La división puede ser horizontal (HPaned) o vertical
6422 Para crear una nueva ventana dividida, utilice una de las siguientes
6426 GtkWidget *gtk_hpaned_new (void);
6428 GtkWidget *gtk_vpaned_new (void);
6431 Después de crear el <em/widget/ ventana dividida, tiene que añadirle
6432 un <em/widget/ hijo a cada mitad. Para hacerlo, utilice:
6435 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *hijo);
6437 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *hijo);
6440 <tt/gtk_paned_add1()/ añade el <em/widget/ hijo a la mitad que se
6441 encuentra en la parte izquierda o superior de la ventana
6442 dividida. <tt/gtk_paned_add2()/ añade el <em/widget/ a la mitad que
6443 hay en la parte derecha o inferior de la ventana.
6445 Por ejemplo, si queremos crear una parte del interface de usuario de
6446 un programa de correo-e imaginario. Dividiremos verticalmente una
6447 ventana en dos partes, teniendo en la parte superior una lista de los
6448 mensajes de correo-e y en la parte inferior el texto de uno de estos
6449 mensajes. El programa es bastante fácil de entender. Solo un par de
6450 cosillas: no se puede añadir texto en un <em/widget/ de texto (Text)
6451 si no se ha hecho antes <tt/gtk_widget_realize()/, pero como
6452 demostración de una técnica alternativa, para añadir el texto
6453 conectaremos un manipulador a la señal «realize». Y tenemos que
6454 añadir la opción <tt/GTK_SHRINK/ a algunos de los elementos que hay en
6455 la tabla con la ventana de texto y sus barras de desplazamiento, así
6456 cuando la porción de abajo se haga más pequeña, se encogerá
6457 correctamente en lugar de desaparecer por la parte de abajo de la
6461 /* principio del ejemplo paned paned.c */
6463 #include <gtk/gtk.h>
6465 /* Crear la lista de "messages" */
6470 GtkWidget *scrolled_window;
6472 GtkWidget *list_item;
6477 /* Crear una nueva ventana con barras de desplazamiento si hacen
6479 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6480 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6481 GTK_POLICY_AUTOMATIC,
6482 GTK_POLICY_AUTOMATIC);
6484 /* Crear una nueva lista y poner en ella la ventana con barras */
6485 list = gtk_list_new ();
6486 gtk_container_add (GTK_CONTAINER(scrolled_window), list);
6487 gtk_widget_show (list);
6489 /* Añadir algunos mensajes a la ventana */
6490 for (i=0; i<10; i++) {
6492 sprintf(buffer,"Message #%d",i);
6493 list_item = gtk_list_item_new_with_label (buffer);
6494 gtk_container_add (GTK_CONTAINER(list), list_item);
6495 gtk_widget_show (list_item);
6499 return scrolled_window;
6502 /* Añadir algún texto a nuestro widget de texto - esta función se
6503 invoca cada vez que se produce una señal realize en la
6504 ventana. Podemos forzar esta señal mediante gtk_widget_realize, pero
6505 primero tiene que formar parte de una jerarquía */
6508 realize_text (GtkWidget *text, gpointer data)
6510 gtk_text_freeze (GTK_TEXT (text));
6511 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
6512 "From: pathfinder@nasa.gov\n"
6513 "To: mom@nasa.gov\n"
6514 "Subject: Made it!\n"
6516 "We just got in this morning. The weather has been\n"
6517 "great - clear but cold, and there are lots of fun sights.\n"
6518 "Sojourner says hi. See you soon.\n"
6521 gtk_text_thaw (GTK_TEXT (text));
6524 /* Creamos una zona con texto que muestra un "message" */
6530 GtkWidget *hscrollbar;
6531 GtkWidget *vscrollbar;
6533 /* Crea una tabla para contener el widget de texto y las barras de
6535 table = gtk_table_new (2, 2, FALSE);
6537 /* Pone un widget de texto en la esquina superior izquierda.
6538 Observe la utilización de GTK_SHRINK en la dirección y */
6539 text = gtk_text_new (NULL, NULL);
6540 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
6541 GTK_FILL | GTK_EXPAND,
6542 GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
6543 gtk_widget_show (text);
6545 /* Pone una HScrollbar en la esquina inferior izquierda */
6546 hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
6547 gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
6548 GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
6549 gtk_widget_show (hscrollbar);
6551 /* Y una VScrollbar en la esquina superior derecha */
6552 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
6553 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
6554 GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
6555 gtk_widget_show (vscrollbar);
6557 /* Y un manejador para poner un mensaje en el widget de texto
6558 cuando reciba realize */
6559 gtk_signal_connect (GTK_OBJECT (text), "realize",
6560 GTK_SIGNAL_FUNC (realize_text), NULL);
6566 main (int argc, char *argv[])
6573 gtk_init (&argc, &argv);
6575 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6576 gtk_window_set_title (GTK_WINDOW (ventana), "Paned Windows");
6577 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6578 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
6579 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
6581 /* crea un widget vpaned y lo añade a nuestra ventana superior */
6583 vpaned = gtk_vpaned_new ();
6584 gtk_container_add (GTK_CONTAINER(ventana), vpaned);
6585 gtk_widget_show (vpaned);
6587 /* Ahora crea los contenidos de las dos mitades de la ventana */
6589 list = create_list ();
6590 gtk_paned_add1 (GTK_PANED(vpaned), list);
6591 gtk_widget_show (list);
6593 text = create_text ();
6594 gtk_paned_add2 (GTK_PANED(vpaned), text);
6595 gtk_widget_show (text);
6596 gtk_widget_show (ventana);
6600 /* fin del ejemplo */
6604 <!-- ----------------------------------------------------------------- -->
6605 <sect1> <em/Viewports/ <label id="sec_Viewports">
6607 Probablemente nunca le llegue a hacer falta utilizar el <em/widget/
6608 Viewport directamente. Será mucho más probable que tenga que utilizar
6609 el <em/widget/ <ref id="sec_ScrolledWindows" name="Ventanas con barras
6610 de desplazamiento"> que a su vez hace uso de <em/viewport/.
6612 Un <em/widget viewport/ le permite meter dentro un gran <em/widget/,
6613 de forma que sólo verá una parte del mismo. Utiliza
6614 <ref id="sec_Adjustment" name="ajustes"> para definir la zona que se
6615 está viendo actualmente.
6617 Para crear un <em/viewport/ hay que utilizar la función:
6620 GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
6621 GtkAdjustment *vadjustment );
6624 Como puede observar, se pueden especificar los ajustes horizontal y
6625 vertical que el <em/widget/ va a utilizar en el mismo momento de su
6626 creación. El <em/widget/ creará sus propios ajustes en caso de que
6627 reciba como argumento un valor NULL.
6629 Puede obtener y establecer los ajustes después de que se haya
6630 creado el <em/widget/ utilizado las cuatro funciones siguientes:
6633 GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );
6635 GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );
6637 void gtk_viewport_set_hadjustment( GtkViewport *viewport,
6638 GtkAdjustment *adjustment );
6640 void gtk_viewport_set_vadjustment( GtkViewport *viewport,
6641 GtkAdjustment *adjustment );
6644 La única función relativa al <em/viewport/ que queda que altera su
6648 void gtk_viewport_set_shadow_type( GtkViewport *viewport,
6649 GtkShadowType type );
6652 Los valores posibles para el argumento <tt/type/ son:
6654 <item> GTK_SHADOW_NONE,
6655 <item> GTK_SHADOW_IN,
6656 <item> GTK_SHADOW_OUT,
6657 <item> GTK_SHADOW_ETCHED_IN,
6658 <item> GTK_SHADOW_ETCHED_OUT
6661 <!-- ----------------------------------------------------------------- -->
6662 <sect1>Ventanas con barras de desplazamiento <label id="sec_ScrolledWindows">
6665 Las ventanas con barras de desplazamiento se utilizan para crear una zona
6666 con barras de desplazamiento dentro de una ventana real. Puede insertar
6667 cualquier tipo de <em/widget/ en una ventana con barras de
6668 desplazamiento, y podrá utilizarlo sin importar su tamaño gracias a
6669 las barras de desplazamiento.
6671 La función siguiente se utiliza para crear una nueva ventana con
6672 barras de desplazamiento.
6675 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
6676 GtkAdjustment *vadjustment );
6679 Donde el primer argumento es el ajuste para la dirección horizontal, y
6680 el segundo es el ajuste para la dirección vertical. Casi siempre valen
6684 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
6685 GtkPolicyType hscrollbar_policy,
6686 GtkPolicyType vscrollbar_policy );
6689 Esta función establece la política que se utilizará con respecto a las
6690 barras de desplazamiento. El primer argumento es la ventana con barras
6691 de desplazamiento sobre la que queremos actuar. El segundo establece
6692 la política para la barra de desplazamiento horizontal, y el tercero
6693 la política para la barra de desplazamiento vertical.
6695 La política puede ser GTK_POLICY_AUTOMATIC, o
6696 GTK_POLICY_ALWAYS. GTK_POLICY_AUTOMATIC decidirá automáticamente si
6697 necesita barras de desplazamiento, mientras que GTK_POLICY_ALWAYS pondrá
6698 siempre las barras de desplazamiento.
6700 Aquí tenemos un ejemplo sencillo que empaqueta 100 botones de
6701 selección en una ventana con barras de desplazamiento. Solamente he
6702 comentado las partes que debería ser nuevas para usted.
6705 /* principio del ejemplo scrolledwin scrolledwin.c */
6707 #include <gtk/gtk.h>
6709 void destroy(GtkWidget *widget, gpointer data)
6714 int main (int argc, char *argv[])
6716 static GtkWidget *ventana;
6717 GtkWidget *scrolled_window;
6723 gtk_init (&argc, &argv);
6725 /* Crea un nuevo cuadro de diálogo para que la ventana con barras de
6726 * desplazamiento se meta dentro. Un cuadro de diálogo es como una
6727 * ventana normal excepto que tiene dentro una vbox y un separador
6728 * horizontal. Es sólo un atajo para crear cuadros de diálogo */
6729 ventana = gtk_dialog_new ();
6730 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6731 (GtkSignalFunc) destroy, NULL);
6732 gtk_window_set_title (GTK_WINDOW (ventana), "dialog");
6733 gtk_container_border_width (GTK_CONTAINER (ventana), 0);
6734 gtk_widget_set_usize(ventana, 300, 300);
6736 /* crea una nueva ventana con barras de desplazamiento. */
6737 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6739 gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
6741 /* la política es GTK_POLICY_AUTOMATIC, o GTK_POLICY_ALWAYS.
6742 * GTK_POLICY_AUTOMATIC decidirá automáticamente si necesita
6743 * barras de desplazamiento, mientras que GTK_POLICY_ALWAYS pondrá
6744 * siempre las barras de desplazamiento. El primer argumento se
6745 * refiere a la barra horizontal, el segundo a la vertical. */
6746 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6747 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
6748 /* El cuadro de diálogo se crea con una vbox dentro de él. */
6749 gtk_box_pack_start (GTK_BOX (GTK_DIALOG(ventana)->vbox), scrolled_window,
6751 gtk_widget_show (scrolled_window);
6753 /* crea una tabla de 10 por 10 casillas. */
6754 table = gtk_table_new (10, 10, FALSE);
6756 /* pone el espacio en x y en y a 10 */
6757 gtk_table_set_row_spacings (GTK_TABLE (table), 10);
6758 gtk_table_set_col_spacings (GTK_TABLE (table), 10);
6760 /* empaqueta la tabla en la ventana con barras de desplazamiento */
6761 gtk_container_add (GTK_CONTAINER (scrolled_window), table);
6762 gtk_widget_show (table);
6764 /* crea una rejilla de botones de selección en la tabla para
6765 * demostrar la ventana con barras de desplazamiento. */
6766 for (i = 0; i < 10; i++)
6767 for (j = 0; j < 10; j++) {
6768 sprintf (buffer, "botón (%d,%d)\n", i, j);
6769 boton = gtk_toggle_button_new_with_label (buffer);
6770 gtk_table_attach_defaults (GTK_TABLE (table), boton,
6772 gtk_widget_show (boton);
6775 /* Añade un botón "close" en la parte de abajo del cuadro de
6777 boton = gtk_button_new_with_label ("close");
6778 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
6779 (GtkSignalFunc) gtk_widget_destroy,
6780 GTK_OBJECT (ventana));
6782 /* hace que el botón puede ser elegido por defecto. */
6784 GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
6785 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->action_area), boton, TRUE, TRUE, 0);
6787 /* Hace que el botón sea el elegido por defecto. Con pulsar la
6788 * tecla "Enter" se activará este botón. */
6789 gtk_widget_grab_default (boton);
6790 gtk_widget_show (boton);
6792 gtk_widget_show (ventana);
6798 /* fin del ejemplo */
6801 Juegue un poco redimensionando la ventana. Vea como actuan las barras
6802 de desplazamiento. También puede utilizar la función
6803 <tt/gtk_widget_set_usize()/ para poner el tamaño por defecto de la
6804 ventana o de cualquier otro <em/widget/.
6807 <!-- ----------------------------------------------------------------- -->
6808 <sect1>Cajas de botones
6810 Las cajas de botones son útiles para crear grupos de botones. Hay
6811 cajas horizontales y verticales. Puede crear una nueva caja de botones
6812 utilizando alguna de las funciones siguientes, que crean
6813 respectivamente una caja horizontal y otra vertical:
6816 GtkWidget *gtk_hbutton_box_new( void );
6818 GtkWidget *gtk_vbutton_box_new( void );
6821 Los únicos atributos pertenecientes a las cajas de botones son los
6822 que definen como se distribuyen los botones. Puede cambiar el
6823 espaciado que hay entre los botones con:
6826 void gtk_hbutton_box_set_spacing_default( gint spacing );
6828 void gtk_vbutton_box_set_spacing_default( gint spacing );
6831 Igualmente, se pueden obtener los actuales valores para el espaciado
6835 gint gtk_hbutton_box_get_spacing_default( void );
6837 gint gtk_vbutton_box_get_spacing_default( void );
6840 El segundo atributo al que podemos acceder afecta al esquema de los
6841 botones dentro de la caja. Se establece utilizando:
6844 void gtk_hbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6846 void gtk_vbutton_box_set_layout_default( GtkButtonBoxStyle layout );
6849 El argumento <tt/layout/ puede tomar uno de los siguientes valores:
6852 <item> GTK_BUTTONBOX_DEFAULT_STYLE
6853 <item> GTK_BUTTONBOX_SPREAD
6854 <item> GTK_BUTTONBOX_EDGE
6855 <item> GTK_BUTTONBOX_START
6856 <item> GTK_BUTTONBOX_END
6859 Puede obtenerse el esquema actual utilizando:
6862 GtkButtonBoxStyle gtk_hbutton_box_get_layout_default( void );
6864 GtkButtonBoxStyle gtk_vbutton_box_get_layout_default( void );
6867 Podemos añadir botones a una caja de botones utilizando (como
6868 siempre) la función:
6871 gtk_container_add( GTK_CONTAINER(button_box), child_widget );
6874 Aquí hay un ejemplo que ilustra todos los diferentes esquemas que
6875 podemos utilizar con las cajas de botones.
6878 /* principio del ejemplo buttonbox buttonbox.c */
6880 #include <gtk/gtk.h>
6882 /* Crear una Caja de Botones con los parámetros
6884 GtkWidget *create_bbox (gint horizontal,
6895 frame = gtk_frame_new (title);
6898 bbox = gtk_hbutton_box_new ();
6900 bbox = gtk_vbutton_box_new ();
6902 gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
6903 gtk_container_add (GTK_CONTAINER (frame), bbox);
6905 /* Establece la apariencia de la Caja de Botones */
6906 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
6907 gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing);
6908 gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);
6910 boton = gtk_button_new_with_label ("OK");
6911 gtk_container_add (GTK_CONTAINER (bbox), boton);
6913 boton = gtk_button_new_with_label ("Cancel");
6914 gtk_container_add (GTK_CONTAINER (bbox), boton);
6916 boton = gtk_button_new_with_label ("Help");
6917 gtk_container_add (GTK_CONTAINER (bbox), boton);
6925 static GtkWidget* ventana = NULL;
6926 GtkWidget *main_vbox;
6929 GtkWidget *frame_horz;
6930 GtkWidget *frame_vert;
6932 /* Inicializa GTK */
6933 gtk_init( &argc, &argv );
6935 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6936 gtk_window_set_title (GTK_WINDOW (ventana), "Button Boxes");
6938 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
6939 GTK_SIGNAL_FUNC(gtk_main_quit),
6942 gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
6944 main_vbox = gtk_vbox_new (FALSE, 0);
6945 gtk_container_add (GTK_CONTAINER (ventana), main_vbox);
6947 frame_horz = gtk_frame_new ("Horizontal Button Boxes");
6948 gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
6950 vbox = gtk_vbox_new (FALSE, 0);
6951 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
6952 gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
6954 gtk_box_pack_start (GTK_BOX (vbox),
6955 create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
6958 gtk_box_pack_start (GTK_BOX (vbox),
6959 create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6962 gtk_box_pack_start (GTK_BOX (vbox),
6963 create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6966 gtk_box_pack_start (GTK_BOX (vbox),
6967 create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
6970 frame_vert = gtk_frame_new ("Vertical Button Boxes");
6971 gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
6973 hbox = gtk_hbox_new (FALSE, 0);
6974 gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
6975 gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
6977 gtk_box_pack_start (GTK_BOX (hbox),
6978 create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
6981 gtk_box_pack_start (GTK_BOX (hbox),
6982 create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
6985 gtk_box_pack_start (GTK_BOX (hbox),
6986 create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
6989 gtk_box_pack_start (GTK_BOX (hbox),
6990 create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
6993 gtk_widget_show_all (ventana);
6995 /* Entra dentro del bucle de eventos */
7000 /* fin del ejemplo */
7003 <!-- ----------------------------------------------------------------- -->
7004 <sect1>Barras de herramientas
7006 Las barras de herramientas acostumbran a agrupar un conjunto de
7007 <em>widgets</em> para hacer más sencilla la personalización
7008 de su aspecto y composición. Típicamente una barra de herramientas
7009 consiste en botones con iconos, etiquetas y <em/tips/ para los iconos
7010 (pequeño texto descriptivo que aparece cuando se mantiene el ratón
7011 sobre el icono), pero en realidad en una barra se puede poner
7012 cualquier tipo de <em>widget</em>. Finalmente, los elementos se pueden
7013 disponer de forma horizontal o vertical, y los botones pueden mostrar
7014 iconos, etiquetas o ambos.
7016 La creación de una barra de herramientas se hace (como puede que ya
7017 haya sospechado) mediante la función siguiente:
7020 GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
7021 GtkToolbarStyle style );
7024 donde <tt/orientation/ puede ser:
7027 GTK_ORIENTATION_HORIZONTAL
7028 GTK_ORIENTATION_VERTICAL
7039 La variable <tt/style/ se aplica a todos los botones que se crean con las
7040 funciones `item' (pero no a los botones insertados en la barra de
7041 herramientas como <em>widgets</em> separados).
7043 Después de crear una barra de herramientas, se pueden añadir,
7044 preañadir e insertar elementos (o sea, botones) en la misma. Los
7045 campos que describen un elemento son el texto de la etiqueta, el texto
7046 del <em/tip/, un texto para el <em/tip/ privado, un icono para el
7047 botón y una función de llamada para el mismo. Por ejemplo, para añadir
7048 un elemento puede utilizar la siguiente función:
7051 GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
7053 const char *tooltip_text,
7054 const char *tooltip_private_text,
7056 GtkSignalFunc callback,
7057 gpointer user_data );
7060 Si quiere utilizar <tt/gtk_toolbar_insert_item/, el único parámetro
7061 adicional que debería especificar es la posición en la que quiere que
7062 se introduzca el elemento.
7064 Para añadir un espacio en blanco entre los elementos de la barra de
7065 herramientas, puede utilizar la función siguiente:
7068 void gtk_toolbar_append_space( GtkToolbar *toolbar );
7070 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
7072 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
7077 Y el tamaño del espacio en blanco puede establecerse globalmente
7078 para toda una barra de herramientas con la función:
7081 void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
7085 Si tiene que establecer la orientación de una barra de herramientas y
7086 su estilo, puede hacerlo `al vuelo' con las funciones siguientes:
7089 void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
7090 GtkOrientation orientation );
7092 void gtk_toolbar_set_style( GtkToolbar *toolbar,
7093 GtkToolbarStyle style );
7095 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
7099 Para mostrar algunas otras cosas que pueden hacerse con una barra de
7100 herramientas, vamos a ver el siguiente programa (interrumpiremos el
7101 listado con alguna explicación adicional):
7104 #include <gtk/gtk.h>
7108 /* Esta función está conectada al botón Close o a la acción de cerrar
7109 * la ventana desde el WM */
7110 void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
7116 Este principio ya debería de sonarle familiar, a no ser que éste sea
7117 su primer programa GTK. En nuestro programa no habrá ninguna novedad,
7118 salvo un bonito dibujo XPM que utilizaremos como icono para todos los
7122 GtkWidget* close_button; // este botón emitirá la señal de cerrar el programa
7123 GtkWidget* tooltips_button; // para activar/desactivar los tooltips
7124 GtkWidget* text_button,
7126 * both_button; // botones circulares para el estilo de la barra
7127 GtkWidget* entry; // un widget para meter texto para mostrar como
7128 // empaquetar widgets en la barra de herramientas
7131 En realidad no necesitamos todos los <em>widgets</em> que acabo de
7132 poner, pero para aclarar las cosas un poco más los he puesto todos.
7135 /* Esto es fácil... cuando uno de los botones cambia, sólo
7136 * tenemos que comprobar quien está activo y hacer que el estilo
7137 * de la barra de herramientas esté acorde con la elección
7138 * ATENCIÓN: ¡nuestra barra de herramientas es data !
7139 void radio_event (GtkWidget *widget, gpointer data)
7141 if (GTK_TOGGLE_BUTTON (text_button)->active)
7142 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
7143 else if (GTK_TOGGLE_BUTTON (icon_button)->active)
7144 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
7145 else if (GTK_TOGGLE_BUTTON (both_button)->active)
7146 gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
7149 /* todavía más fácil, sólo hay que comprobar el botón de selección
7150 * y activar/desactivar los tooltips */
7151 void toggle_event (GtkWidget *widget, gpointer data)
7153 gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
7154 GTK_TOGGLE_BUTTON (widget)->active );
7158 Lo de arriba son sólo dos funciones de llamada que se invocarán cuando
7159 se presione uno de los botones de la barra de herramientas. Todo esto
7160 ya debería resultarle familiar si ha utilizado alguna vez los botones
7161 de selección (o los botones circulares)
7164 int main (int argc, char *argv[])
7166 /* Aquí está nuestra ventana principal (un cuadro de diálogo) y una
7169 GtkWidget* handlebox;
7171 /* De acuerdo, necesitamos una barra de herramientas, un icono con
7172 * una máscara (una para todos los botones) y un widget icono donde
7173 * meter el icono (crearemos un widget diferente para cada botón) */
7174 GtkWidget * toolbar;
7179 /* a esta función se le llama en todas las aplicación GTK */
7180 gtk_init (&argc, &argv);
7182 /* crear una ventana nueva con un título y el tamaño adecuado */
7183 dialog = gtk_dialog_new ();
7184 gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
7185 gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
7186 GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
7188 /* salimos si alguien intenta cerrarnos */
7189 gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
7190 GTK_SIGNAL_FUNC ( delete_event ), NULL);
7192 /* tenemos que mandar la señalo realize porque utilizamos pixmaps
7193 * para los elementos que hay en la barra de herramientas */
7194 gtk_widget_realize ( dialog );
7196 /* para hacerlo más bonito ponemos la barra de herramientas en la
7197 * caja flotante, para que así se pueda desatar de la ventana
7199 handlebox = gtk_handle_box_new ();
7200 gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
7201 handlebox, FALSE, FALSE, 5 );
7204 Lo de arriba debería ser parecido en cualquier aplicación GTK. Sólo
7205 está la inicialización de GTK, la creación de la ventana, etc...
7206 Solamente hay una cosa que probablemente necesite una explicación:
7207 una barra de herramientas flotante. Una barra de herramientas flotante
7208 sólo es otra barra donde pueden empaquetarse <em>widgets</em>. La
7209 diferencia que tiene con una barra típica es que puede desatarse de la
7210 ventana padre (o, de hecho, la barra de herramientas flotante permanece
7211 en el padre, pero reducida a un rectángulo muy pequeño, mientras que
7212 todos sus contenidos se pasan a una nueva ventana flotante). Es bonito
7213 tener una barra de herramientas flotante, por lo que estos dos
7214 <em>widgets</em> suelen aparecer juntos.
7217 /* la barra de herramientas será horizontal, con iconos y texto, y
7218 * con un espacio de 5pxl entre elementos y finalmente, la ponemos en
7219 * nuestra caja flotante */
7220 toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
7222 gtk_container_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
7223 gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
7224 gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
7226 /* ahora creamos el icono con la máscara: utilizaremos el widget
7227 * icon con todos los elementos de la barra de herramientas */
7228 icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
7229 &dialog->style->white, gtk_xpm );
7232 Bien, lo que acabamos de escribir es la inicialización del
7233 <em>widget</em> de la barra de herramientas y la creación de un
7234 <em>pixmap</em> GDK con su máscara. Si quiere saber algo más sobre la
7235 utilización de <em>pixmaps</em>, vea la documentación de GDK o la
7236 sección <ref id="sec_Pixmaps" name="Pixmaps"> en este tutorial.
7239 /* nuestro primer elemento es el botón <close> */
7240 iconw = gtk_pixmap_new ( icon, mask ); // icon widget
7242 gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), // nuestra barra
7243 "Close", // etiqueta del botón
7244 "Closes this app", // tooltip para el botón
7245 "Private", // cadena privada del tooltip
7246 iconw, // widget del icono
7247 GTK_SIGNAL_FUNC (delete_event), // una señal
7249 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); // espacio después del elemento
7252 En el trozo de código de arriba puede ver como se hace la acción más
7253 simple: añadir un botón a la barra de herramientas. Justo antes de
7254 añadir un nuevo elemento, tenemos que construir un <em>widget
7255 pixmap</em> para que sirva como icono para este elemento; este paso
7256 tendrá que repetirse para cada nuevo elemento. Después del elemento
7257 añadiremos un espacio en blanco en la barra de herramientas, para que
7258 los elementos que añadamos a continuación no se toquen los unos a los
7259 otros. Como puede ver, <tt/gtk_toolbar_append_item/ devuelve un
7260 puntero al <em>widget</em> de nuestro nuevo botón recien creado, por
7261 lo que podremos trabajar con él como siempre.
7264 /* ahora, vamos a hacer nuestro grupo de botones circulares... */
7265 iconw = gtk_pixmap_new ( icon, mask );
7267 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7268 GTK_TOOLBAR_CHILD_RADIOBUTTON, // un tipo de elemento
7269 NULL, // puntero al widget
7271 "Only icons in toolbar", // tooltip
7272 "Private", // cadena privada del tooltip
7274 GTK_SIGNAL_FUNC (radio_event), // señal
7275 toolbar); // dato para la señal
7276 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7279 Aquí empezamos creando un grupo de botones circulares. Para hacerlo
7280 hemos utilizado <tt/gtk_toolbar_append_element/. De hecho, utilizando
7281 esta función se pueden añadir tanto elementos simples como espacios en
7282 blanco (tipo = GTK_TOOLBAR_CHILD_SPACE o GTK_TOOLBAR_CHILD_BUTTON). En
7283 el caso de arriba, hemos empezado creando un grupo de botones circulares.
7284 Para crear más botones circulares para este grupo
7285 necesitaremos un puntero al botón anterior del grupo, mediante el que
7286 podremos construir fácilmente una lista de botones (ver la sección
7287 <ref id="sec_Radio_Buttons" name="Botones circulares"> que se encuentra
7288 más adelante en este tutorial).
7291 /* los botones circulares que vienen a continuación están
7292 relacionados con los anteriores */
7293 iconw = gtk_pixmap_new ( icon, mask );
7295 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7296 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7299 "Only texts in toolbar",
7302 GTK_SIGNAL_FUNC (radio_event),
7304 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7306 iconw = gtk_pixmap_new ( icon, mask );
7308 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7309 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7312 "Icons and text in toolbar",
7315 GTK_SIGNAL_FUNC (radio_event),
7317 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7318 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(both_button),TRUE);
7321 Al final hemos activado manualmente uno de los botones (en caso
7322 contrario los botones permanecerían todos en estado activo,
7323 impidiéndonos poder cambiar de uno a otro).
7326 /* aquí tenemos un sencillo botón de selección */
7327 iconw = gtk_pixmap_new ( icon, mask );
7329 gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
7330 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
7333 "Toolbar with or without tips",
7336 GTK_SIGNAL_FUNC (toggle_event),
7338 gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
7339 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
7342 Un botón de selección puede crearse de una forma obvia (si ya sabe como
7343 crear botones circulares).
7346 /* para empaquetar un widget en la barra de herramientas, sólo
7347 * tenemos que crearlo y añadirlo en la barra con el tooltip
7349 entry = gtk_entry_new ();
7350 gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
7352 "This is just an entry",
7355 /* bien, no se ha creado con la barra, así que debemos mostrarlo
7357 gtk_widget_show ( entry );
7360 Como puede ver, añadir cualquier tipo de <em>widget</em> a la barra
7361 de herramientas es fácil. Lo único que debe recordar es que este
7362 <em>widget</em> debe mostrarse manualmente (al contrario que los demás
7363 elementos que se mostrarán junto con la barra de herramientas).
7366 /* ¡ Eso es ! mostremos algo. */
7367 gtk_widget_show ( toolbar );
7368 gtk_widget_show (handlebox);
7369 gtk_widget_show ( dialog );
7371 /* quedémonos en gtk_main y ¡esperemos a que empiece la diversión! */
7378 Y ya estamos en el final del tutorial sobre la barra de herramientas.
7379 Por supuesto, para apreciar completamente el ejemplo, necesita además
7380 del código este precioso icono XPM que le mostramos a continuación:
7384 static char * gtk_xpm[] = {
7391 "................+...............",
7392 "..............+++++.............",
7393 "............+++++@@++...........",
7394 "..........+++++@@@@@@++.........",
7395 "........++++@@@@@@@@@@++........",
7396 "......++++@@++++++++@@@++.......",
7397 ".....+++@@@+++++++++++@@@++.....",
7398 "...+++@@@@+++@@@@@@++++@@@@+....",
7399 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
7400 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
7401 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
7402 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
7403 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
7404 ".+####+++@@@+++++++@@@@@+@$$$$@.",
7405 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
7406 ".+######++++@@@@@@@++@$$$$$$$$+.",
7407 ".+#######+##+@@@@+++$$$$$$@@$$+.",
7408 ".+###+++##+##+@@++@$$$$$$++$$$+.",
7409 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
7410 ".+###++++++#+++@$$@+@$$@++$$$@+.",
7411 ".+####+++++++#++$$@+@$$++$$$$+..",
7412 ".++####++++++#++$$@+@$++@$$$$+..",
7413 ".+#####+++++##++$$++@+++$$$$$+..",
7414 ".++####+++##+#++$$+++++@$$$$$+..",
7415 ".++####+++####++$$++++++@$$$@+..",
7416 ".+#####++#####++$$+++@++++@$@+..",
7417 ".+#####++#####++$$++@$$@+++$@@..",
7418 ".++####++#####++$$++$$$$$+@$@++.",
7419 ".++####++#####++$$++$$$$$$$$+++.",
7420 ".+++####+#####++$$++$$$$$$$@+++.",
7421 "..+++#########+@$$+@$$$$$$+++...",
7422 "...+++########+@$$$$$$$$@+++....",
7423 ".....+++######+@$$$$$$$+++......",
7424 "......+++#####+@$$$$$@++........",
7425 ".......+++####+@$$$$+++.........",
7426 ".........++###+$$$@++...........",
7427 "..........++##+$@+++............",
7428 "...........+++++++..............",
7429 ".............++++..............."};
7432 <!-- ----------------------------------------------------------------- -->
7433 <sect1> Libros de notas (<em/Notebooks/)
7435 El <em/widget/ Notebook es una colección de `páginas' que se solapan
7436 las unas a las otras, cada una con un contenido diferente. Este
7437 <em/widget/ se ha vuelto cada vez más común últimamente en la
7438 programación de interfaces gráficos de usuario (GUI en inglés), y es
7439 una buena forma de mostrar bloques de información similar que
7440 necesitan aparecer de forma separada.
7442 La primera función que necesita conocer, como probablemente ya habrá
7443 adivinado, se utiliza para crear un nuevo <em/widget/ notebook.
7446 GtkWidget *gtk_notebook_new( void );
7449 Una vez haya crear el libro de notas, hay 12 funciones que se pueden
7450 utilizar para trabajar con él. Echémosles un vistazo una a una.
7452 La primera que estudiaremos será la que nos permita establecer la
7453 posición de los indicadores de la página. Estos indicadores se pueden
7454 poner en cuatro lugares diferentes: arriba, abajo, a la derecha o a la
7458 void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
7459 GtkPositionType pos );
7462 <tt/GtkPositionType/ debe tener uno de los valores siguientes (su significado
7463 está bastante claro):
7467 <item> GTK_POS_RIGHT
7469 <item> GTK_POS_BOTTOM
7472 GTK_POS_TOP es el valor por defecto.
7474 Lo siguiente que estudiaremos es como añadir páginas al libro de notas.
7475 Hay tres formas de añadirle páginas al <em/widget/. Veamos las dos primeras
7476 formas (son muy parecidas).
7479 void gtk_notebook_append_page( GtkNotebook *notebook,
7481 GtkWidget *tab_label );
7483 void gtk_notebook_prepend_page( GtkNotebook *notebook,
7485 GtkWidget *tab_label );
7488 Estas funciones le añaden páginas al libro de notas insertándolas desde
7489 el fondo del libro (añadiéndolas), o desde parte superior del libro
7490 (preañadiéndolas). <tt/hijo/ es el <em/widget/ que se mete en la página
7491 del libro de notas, y <tt/tab_label/ es la etiqueta para la página que
7494 La función que queda que sirve para añadir una página contiene todas las
7495 propiedades de las anteriores, pero además permite especificar en que
7496 posición quiere que esté la página dentro del libro de notas.
7499 void gtk_notebook_insert_page( GtkNotebook *notebook,
7501 GtkWidget *tab_label,
7505 Los parámetros son los mismos que habían en las funciones _append_ y
7506 _prepend_ excepto que hay uno más que antes, <tt/posicion/. Este
7507 parámetro se utiliza para especificar en que lugar debe introducirse
7510 Ahora que sabemos como añadir un página, veamos como podemos eliminar
7511 una página del libro de notas.
7514 void gtk_notebook_remove_page( GtkNotebook *notebook,
7518 Esta función coge la página especificada por <tt/page_num/ y la
7519 elimina del <em/widget/ al que apunta <tt/notebook/.
7521 Para saber cual es la página actual del libro de notas utilice la
7525 gint gtk_notebook_current_page( GtkNotebook *notebook );
7528 Las dos funciones siguientes sirven para ir a la página siguiente o a
7529 la anterior del libro de notas. Para utilizarlas sólo hay que
7530 proporcionar el <em/widget/ notebook que queremos manipular. Nota:
7531 cuando el libro de notas está en la última página y se llama a
7532 <tt/gtk_notebook_next_page/, se pasará a la primera página. Sin
7533 embargo, si el libro de notas está en la primera página, y se llama a
7534 <tt/gtk_notebook_prev_page/, no se pasará a la última página.
7537 void gtk_notebook_next_page( GtkNoteBook *notebook );
7539 void gtk_notebook_prev_page( GtkNoteBook *notebook );
7542 La siguiente función establece la página `activa'. Si quiere que se
7543 abra el libro de notas por la página 5, por ejemplo, debe utilizar
7544 esta función. Si no utiliza esta función el libro de notas empezará
7545 por defecto en la primera página.
7548 void gtk_notebook_set_page( GtkNotebook *notebook,
7552 Las dos funciones siguientes añaden o eliminan los indicadores de las
7553 páginas o el borde del libro, respectivamente.
7556 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
7559 void gtk_notebook_set_show_border( GtkNotebook *notebook,
7563 <tt/show_tabs/ y <tt/show_border/ puede ser TRUE o FALSE.
7565 Ahora echémosle un vistaza a un ejemplo, sacado del código de
7566 <tt/testgtk.c/ que viene con la distribución de GTK, y que muestra
7567 la utilización de las 13 funciones. Este pequeño programa crea una
7568 ventana con un libro de notas y seis botones. El libro de notas
7569 contiene 11 páginas, incluidas de tres formas diferentes, añadidas,
7570 insertadas, y preañadidas. Los botones le permiten rotar las
7571 posiciones de los indicadores, añadir y eliminar los indicadores y el
7572 borde, eliminar una página, cambiar páginas hacia delante y hacia
7573 detrás, y salir del programa.
7576 /* principio del ejemplo notebook notebook.c */
7578 #include <gtk/gtk.h>
7580 /* Esta función rota la posición de los indicadores */
7581 void rotate_book (GtkButton *boton, GtkNotebook *notebook)
7583 gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
7586 /* Añade/Elimina los indicadores de la página y los bordes */
7587 void tabsborder_book (GtkButton *boton, GtkNotebook *notebook)
7591 if (notebook->show_tabs == 0)
7593 if (notebook->show_border == 0)
7596 gtk_notebook_set_show_tabs (notebook, tval);
7597 gtk_notebook_set_show_border (notebook, bval);
7600 /* Elimina una página del libro de notas */
7601 void remove_book (GtkButton *boton, GtkNotebook *notebook)
7605 page = gtk_notebook_current_page(notebook);
7606 gtk_notebook_remove_page (notebook, page);
7607 /* Hay que redibujar el widget --
7608 Esto fuerza que el widget se autoredibuje */
7609 gtk_widget_draw(GTK_WIDGET(notebook), NULL);
7612 void delete (GtkWidget *widget, GtkWidget *event, gpointer data)
7617 int main (int argc, char *argv[])
7622 GtkWidget *notebook;
7624 GtkWidget *etiqueta;
7625 GtkWidget *checkbutton;
7630 gtk_init (&argc, &argv);
7632 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7634 gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
7635 GTK_SIGNAL_FUNC (delete), NULL);
7637 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
7639 table = gtk_table_new(2,6,TRUE);
7640 gtk_container_add (GTK_CONTAINER (ventana), table);
7642 /* Crea un nuevo libro de notas, indicando la posición de los
7644 notebook = gtk_notebook_new ();
7645 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
7646 gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
7647 gtk_widget_show(notebook);
7649 /* le añadimos un montón de páginas al libro de notas */
7650 for (i=0; i < 5; i++) {
7651 sprintf(bufferf, "Append Frame %d", i+1);
7652 sprintf(bufferl, "Page %d", i+1);
7654 frame = gtk_frame_new (bufferf);
7655 gtk_container_border_width (GTK_CONTAINER (frame), 10);
7656 gtk_widget_set_usize (frame, 100, 75);
7657 gtk_widget_show (frame);
7659 etiqueta = gtk_label_new (bufferf);
7660 gtk_container_add (GTK_CONTAINER (frame), etiqueta);
7661 gtk_widget_show (etiqueta);
7663 etiqueta = gtk_label_new (bufferl);
7664 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, etiqueta);
7668 /* Ahora añadimos una página en punto específico */
7669 checkbutton = gtk_check_button_new_with_label ("Check me please!");
7670 gtk_widget_set_usize(checkbutton, 100, 75);
7671 gtk_widget_show (checkbutton);
7673 etiqueta = gtk_label_new ("Add spot");
7674 gtk_container_add (GTK_CONTAINER (checkbutton), etiqueta);
7675 gtk_widget_show (etiqueta);
7676 etiqueta = gtk_label_new ("Add page");
7677 gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, etiqueta, 2);
7679 /* Y finalmente preañadimos páginas en el libro de notas */
7680 for (i=0; i < 5; i++) {
7681 sprintf(bufferf, "Prepend Frame %d", i+1);
7682 sprintf(bufferl, "PPage %d", i+1);
7684 frame = gtk_frame_new (bufferf);
7685 gtk_container_border_width (GTK_CONTAINER (frame), 10);
7686 gtk_widget_set_usize (frame, 100, 75);
7687 gtk_widget_show (frame);
7689 etiqueta = gtk_label_new (bufferf);
7690 gtk_container_add (GTK_CONTAINER (frame), etiqueta);
7691 gtk_widget_show (etiqueta);
7693 etiqueta = gtk_label_new (bufferl);
7694 gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, etiqueta);
7697 /* Decimos en que página empezar (página 4) */
7698 gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
7701 /* creamos un montón de botones */
7702 boton = gtk_button_new_with_label ("close");
7703 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7704 GTK_SIGNAL_FUNC (delete), NULL);
7705 gtk_table_attach_defaults(GTK_TABLE(table), boton, 0,1,1,2);
7706 gtk_widget_show(boton);
7708 boton = gtk_button_new_with_label ("next page");
7709 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7710 (GtkSignalFunc) gtk_notebook_next_page,
7711 GTK_OBJECT (notebook));
7712 gtk_table_attach_defaults(GTK_TABLE(table), boton, 1,2,1,2);
7713 gtk_widget_show(boton);
7715 boton = gtk_button_new_with_label ("prev page");
7716 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7717 (GtkSignalFunc) gtk_notebook_prev_page,
7718 GTK_OBJECT (notebook));
7719 gtk_table_attach_defaults(GTK_TABLE(table), boton, 2,3,1,2);
7720 gtk_widget_show(boton);
7722 boton = gtk_button_new_with_label ("tab position");
7723 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7724 (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
7725 gtk_table_attach_defaults(GTK_TABLE(table), boton, 3,4,1,2);
7726 gtk_widget_show(boton);
7728 boton = gtk_button_new_with_label ("tabs/border on/off");
7729 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7730 (GtkSignalFunc) tabsborder_book,
7731 GTK_OBJECT (notebook));
7732 gtk_table_attach_defaults(GTK_TABLE(table), boton, 4,5,1,2);
7733 gtk_widget_show(boton);
7735 boton = gtk_button_new_with_label ("remove page");
7736 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
7737 (GtkSignalFunc) remove_book,
7738 GTK_OBJECT(notebook));
7739 gtk_table_attach_defaults(GTK_TABLE(table), boton, 5,6,1,2);
7740 gtk_widget_show(boton);
7742 gtk_widget_show(table);
7743 gtk_widget_show(ventana);
7749 /* fin del ejemplo */
7752 Espero que la explicación le ayude de alguna manera a crear libros de
7753 notas en sus aplicaciones GTK.
7755 <!-- ***************************************************************** -->
7756 <sect> El <em/widget/ GtkCList
7757 <!-- ***************************************************************** -->
7758 <!-- ----------------------------------------------------------------- -->
7760 El <em>widget</em> GtkCList ha reemplazado al <em>widget</em> GtkList
7761 (que sigue estando disponible).
7763 El <em>widget</em> GtkCList es un <em>widget</em> de una lista
7764 multicolumna que es capaz de manejar, literalmente, miles de filas de
7765 información. Cada columna puede tener (opcionalmente) un título, que
7766 puede estar activado (opcionalmente), permitiéndonos enlazar una
7767 función con la selección.
7769 <!-- ----------------------------------------------------------------- -->
7770 <sect1>Creando un <em>widget</em> GtkCList
7772 Crear un GtkCList es algo bastante sencillo, una vez que sabe como
7773 crear un <em>widget</em> en general. Se proporcionan al menos dos
7774 formas estándar de crearlo, la forma fácil y la forma difícil. Pero
7775 antes de crear una GtkCList, hay una cosa que debemos saber: ¿Cuántas
7776 columnas va a tener?
7778 No todas las columnas tienen que ser visibles y pueden utilizarse para
7779 almacenar datos que estén relacionados con una cierta celda de la
7783 GtkWidget *gtk_clist_new ( gint columns );
7785 GtkWidget *gtk_clist_new_with_titles( gint columns,
7789 Esta primera aproximación al problema es muy sencilla, pero la segunda
7790 requerirá alguna explicación adicional. Cada columna puede tener un
7791 título asociado. Si utilizamos la segunda forma, deberemos proporcionar
7792 punteros al texto del título, y el número de punteros debe ser igual
7793 al número de columnas especificadas. Por supuesto, siempre podemos
7794 utilizar la primera forma de creación y añadir más tarde los títulos
7797 <!-- ----------------------------------------------------------------- -->
7798 <sect1>Modos de operación
7800 Hay varios atributos que pueden utilizarse para alterar el aspecto
7801 de un GtkCList. Primero tenemos
7804 void gtk_clist_set_selection_mode( GtkCList *clist,
7805 GtkSelectionMode mode );
7808 que, como el propio nombre indica, establece el modo de selección de la
7809 lista GtkCList. El primer argumento es el <em>widget</em> GtkCList, y el
7810 segundo especifica el modo de selección de la celda (están definidos
7811 en <tt/gtkenums.h/). En el momento de escribir esto, estaban
7812 disponibles los siguientes modos:
7815 <item> GTK_SELECTION_SINGLE - La selección o es NULL o contiene un
7816 puntero GList a un elemento seleccionado.
7818 <item> GTK_SELECTION_BROWSE - La selección es NULL si la lista no
7819 contiene <em>widgets</em> o si los que contiene son insensibles, en
7820 caso contrario contendrá un puntero GList hacia una estructura GList,
7821 y por tanto con exactamente un elemento.
7823 <item> GTK_SELECTION_MULTIPLE - La selección es NULL si no hay
7824 seleccionados una lista de elementos o un puntero GList para el primer
7825 elemento seleccionado.<!-- FIXME: Todo esto no se si tiene sentido -->
7826 Éste apunta de nuevo a una estructura GList para el segundo elemento
7827 seleccionado y continua así. Éste es, actualmente, el modo por
7828 <bf>defecto</bf> para el <em>widget</em> GtkCList.
7830 <item> GTK_SELECTION_EXTENDED - La selección siempre es NULL.
7833 Puede que se añadan otros modos en versiones posteriores de GTK.
7838 void gtk_clist_set_policy (GtkCList *clist,
7839 GtkPolicyType vscrollbar_policy,
7840 GtkPolicyType hscrollbar_policy);
7843 que define que es lo que ocurre con las barras de desplazamiento. Los
7844 siguientes valores son los posibles para las barras de desplazamiento
7845 horizontal y vertical:
7848 <item> GTK_POLICY_ALWAYS - La barra de desplazamiento siempre está ahí.
7850 <item> GTK_POLICY_AUTOMATIC - La barra de desplazamiento estará ahí sólo
7851 cuando el número de elementos en la GtkCList supere el número que puede
7852 mostrarse en el <em>widget</em>.
7855 También podemos definir como debería ser el aspecto del borde del
7856 <em>widget</em> GtkCList. Esto lo podemos hacer mediante
7859 void gtk_clist_set_border( GtkCList *clist,
7860 GtkShadowType border );
7863 Y los posibles valores para el segundo argumento son
7866 <item> GTK_SHADOW_NONE
7868 <item> GTK_SHADOW_IN
7870 <item> GTK_SHADOW_OUT
7872 <item> GTK_SHADOW_ETCHED_IN
7874 <item> GTK_SHADOW_ETCHED_OUT
7877 <!-- ----------------------------------------------------------------- -->
7878 <sect1>Trabajando con los títulos
7880 Cuando cree un <em>widget</em> GtkCList, también obtendrá
7881 automáticamente un conjunto de botones título. Vivirán en lo alto de
7882 una ventana CList, y pueden actuar como botones normales que responden
7883 cuando se pulsa sobre ellos, o bien pueden ser pasivos, en cuyo caso
7884 no serán nada más que un título. Hay cuatro llamadas diferentes que
7885 nos ayudarán a establecer el estado de los botones título.
7888 void gtk_clist_column_title_active( GtkCList *clist,
7891 void gtk_clist_column_title_passive( GtkCList *clist,
7894 void gtk_clist_column_titles_active( GtkCList *clist );
7896 void gtk_clist_column_titles_passive( GtkCList *clist );
7899 Un título activo es aquel que actua como un botón normal, y uno pasivo
7900 es sólo una etiqueta. Las primeras dos llamadas de arriba
7901 activarán/desactivarán el botón título correspondiente a la columna
7902 <tt/column/, mientras que las dos llamadas siguientes
7903 activarán/desactivarán todos los botones título que hayan en el
7904 <em>widget</em> <tt/clist/ que se le proporcione a la función.
7906 Pero, por supuesto, habrá casos en el que no querremos utilizar los
7907 botones título, así que también tenemos la posibilidad de ocultarlos y
7908 de volverlos a mostrar utilizando las dos llamadas siguientes:
7911 void gtk_clist_column_titles_show( GtkCList *clist );
7913 void gtk_clist_column_titles_hide( GtkCList *clist );
7916 Para que los títulos sean realmente útiles necesitamos un mecanismo
7917 que nos permita darles el valor que nosotros queramos y cambiar ese
7918 valor, y podremos hacerlo mediante
7921 void gtk_clist_set_column_title( GtkCList *clist,
7926 Debe llevar cuidado, ya que sólo se puede especificar el título de una
7927 columna a la vez, por lo que si conoce todos los títulos desde el
7928 principio, le sugiero que utilice <tt/gtk_clist_new_with_titles/ (como
7929 se describe arriba) para establecerlos adecuadamente. Le ahorrará
7930 tiempo de programación, y hará su programa más pequeño. Hay algunos
7931 casos donde es mejor utilizar la forma manual, y uno de ellos es
7932 cuando no todos los títulos son texto. GtkCList nos proporciona
7933 botones título que pueden, de hecho, incorporar un <em>widget</em>
7934 entero, por ejemplo un <em>pixmap</em>. Todo esto se hace mediante
7937 void gtk_clist_set_column_widget( GtkCList *clist,
7939 GtkWidget *widget );
7942 que no debería necesitar de explicaciones adicionales.
7944 <!-- ----------------------------------------------------------------- -->
7945 <sect1>Manipulando la lista en sí.
7947 Es posible cambiar la justificación de una columna, y esto se hace
7951 void gtk_clist_set_column_justification( GtkCList *clist,
7953 GtkJustification justification );
7956 El tipo GtkJustification puede tomar los valores siguientes:
7959 <item>GTK_JUSTIFY_LEFT - El texto en la columna empezará desde el lado
7962 <item>GTK_JUSTIFY_RIGHT - El texto en la columna empezará desde el
7965 <item>GTK_JUSTIFY_CENTER - El texto se colocará en el centro de la
7968 <item>GTK_JUSTIFY_FILL - El texto utilizará todo el espacio disponible
7969 en la columna. Normalmente se hace añadiendo espacios en blanco entre
7970 las palabras (o entre letras por separado, si se trata de una sola
7971 palabra). Más o menos de la misma forma en la que lo hace un
7972 procesador de textos WYSIWYG.
7975 La siguiente función es muy importante, y debería ser un estándar
7976 para inicializar todos los <em>widgets</em> GtkCList. Cuando se crea
7977 la lista, los anchos de las distintas columnas se eligen para que
7978 coincidan con sus títulos, y éste es el ancho adecuado que tenemos que
7982 void gtk_clist_set_column_width( GtkCList *clist,
7987 Observe que el ancho viene dado en pixeles y no en letras. Lo mismo
7988 vale para el alto de la celda en las columnas, pero como el valor por
7989 defecto es la altura del tipo de letra actual, no es algo tan crítico
7990 para la aplicación. De todas formas, la altura se cambia mediante
7993 void gtk_clist_set_row_height( GtkCList *clist,
7997 De nuevo, hay que advertir que el ancho viene dado en pixeles.
7999 También podemos ir hacia un elemento sin la intervención del usuario,
8000 sin embargo hace falta que sepamos hacia donde queremos ir. O en otras
8001 palabras, necesitamos la fila y la columna del elemento al que queremos
8005 void gtk_clist_moveto( GtkCList *clist,
8012 Es importante comprender bien el significado de <tt/gfloat
8013 row_align/. Tiene un valor entre 0.0 y 1.0, donde 0.0 significa que
8014 debemos hacer que la fila seleccionada aparezca en la alto de la
8015 lista, mientras que 1.0 significa que la fila aparecerá en la parte de
8016 abajo. El resto de valores entre 0.0 y 1.0 son válidos y harán que la
8017 fila aparezca entre la parte superior y la inferior. El último
8018 argumento, <tt/gfloat col_align/ funciona igual, siendo 0.0 la
8019 izquierda y 1.0 la derecha.
8021 Dependiendo de las necesidades de la aplicación, puede que no tengamos
8022 que hacer un desplazamiento hacia un elemento que ya sea visible. Por
8023 tanto, ¿cómo podemos saber si ya es visible? Como siempre, hay una función
8024 que sirve para averiguarlo
8027 GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
8031 El valor devuelto es uno de los siguientes:
8034 <item>GTK_VISIBILITY_NONE
8036 <item>GTK_VISIBILITY_PARTIAL
8038 <item>GTK_VISIBILITY_FULL
8041 Como puede ver, sólo nos dice si una fila es visible. Actualmente no hay
8042 ninguna forma de obtener el mismo dato para una columna. Sin embargo
8043 podemos obtener información parcial, porque si el valor devuelto es
8044 GTK_VISIBILITY_PARTIAL, entonces es que alguna parte está oculta,
8045 pero no sabemos si es la fila que está cortada por la parte de abajo
8046 de la lista, o si la fila tiene columnas que están fuera.
8048 También podemos cambiar el color del primer y del segundo plano de una
8049 fila en particular. Esto es útil para marcar la fila seleccionada por
8050 el usuario, y las dos funciones que hay que utilizar son
8053 void gtk_clist_set_foreground( GtkCList *clist,
8057 void gtk_clist_set_background( GtkCList *clist,
8062 Cuidado, ya que los colores deben estar asignados previamente en la
8065 <!-- ----------------------------------------------------------------- -->
8066 <sect1>Añadiendo filas a la lista
8068 Podemos añadir filas de dos formas. Se pueden añadir al final de la lista
8072 gint gtk_clist_append( GtkCList *clist,
8076 o podemos insertar una fila en un lugar determinado utilizando
8079 void gtk_clist_insert( GtkCList *clist,
8084 En ambas llamadas podemos proporcionar un conjunto de punteros que
8085 serán los textos que queremos poner en las columnas. El número de
8086 punteros debe ser igual al número de columnas en la lista. Si el
8087 argumento <tt/text[]/ es NULL, entonces no habrá texto en las columnas
8088 de la fila. Esto sería útil, por ejemplo, si queremos añadir
8089 <em>pixmaps</em> en lugar de texto (en general para cualquier cosa que
8090 haya que hacer manualmente).
8092 De nuevo, cuidado ya que el número de filas y de columnas comienza en
8095 Para eliminar una fila individual podemos utilizar
8098 void gtk_clist_remove( GtkCList *clist,
8102 Hay también una llamada que elimina todas las filas en la lista.
8103 Es mucho más rápido que llamar a <tt/gtk_clist_remove/ una vez por
8104 cada fila, que sería la única alternativa.
8107 void gtk_clist_clear( GtkCList *clist );
8110 También hay dos funciones que es conveniente utilizarlas cuando hay
8111 que hacerle muchos cambios a una lista. Son para evitar que la lista
8112 parpadee mientras es actualizada repetidamente, que puede ser muy
8113 molesto para el usuario. Por tanto es una buena idea congelar la
8114 lista, hacer los cambios, y descongelarla, que hará que la lista se
8115 actualice en la pantalla.
8118 void gtk_clist_freeze( GtkCList * clist );
8120 void gtk_clist_thaw( GtkCList * clist );
8123 <!-- ----------------------------------------------------------------- -->
8124 <sect1>Poniendo texto y <em>pixmaps</em> en las celdas
8126 Una celda puede contener un <em>pixmap</em>, texto o ambos. Para ponerlos
8127 en las celdas, podemos utilizar las siguientes funciones.
8130 void gtk_clist_set_text( GtkCList *clist,
8135 void gtk_clist_set_pixmap( GtkCList *clist,
8141 void gtk_clist_set_pixtext( GtkCList *clist,
8150 Son bastante sencillas de entender. Todas las llamadas tienen la
8151 GtkCList como primer argumento, seguidas por la fila y la columna
8152 de la celda, y seguidas por el dato que debe ponerse en la celda. El
8153 argumento <tt/gint8 spacing/ en <tt/gtk_clist_set_pixtext/ es el
8154 número de <em>pixels</em> entre el <em>pixmap</em> y el principio del
8157 Para leer los datos que hay en una celda, podemos utilizar
8160 gint gtk_clist_get_text( GtkCList *clist,
8165 gint gtk_clist_get_pixmap( GtkCList *clist,
8171 gint gtk_clist_get_pixtext( GtkCList *clist,
8180 No es necesario leer todos los datos en caso de que no estemos
8181 interesados. Cualquiera de los punteros que se supone contendrán los
8182 valores a devolver (cualquiera excepto el <tt/clist/) pueden ser
8183 NULL. Por lo que si sólo queremos leer el texto de una celda que es de
8184 tipo <tt/pixtext/, deberíamos hacer lo siguiente, suponiendo que
8185 <tt/clist/, <tt/row/ y <tt/column/ ya existan:
8190 gtk_clist_get_pixtext(clist, row, column, &mytext, NULL, NULL, NULL);
8193 Hay una rutina más que está relacionada con lo que está dentro
8194 de una celda de una <tt/clist/, y es
8197 GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
8202 que devuelve el tipo de datos que hay en la celda. El valor devuelto es
8203 uno de los siguientes
8206 <item>GTK_CELL_EMPTY
8210 <item>GTK_CELL_PIXMAP
8212 <item>GTK_CELL_PIXTEXT
8214 <item>GTK_CELL_WIDGET
8217 También hay una función que nos permite especificar la indentación de
8218 un celda (horizontal o vertical). El valor de la indentación es del
8219 tipo <tt/gint/, viene dado en <em>pixeles</em>, y puede ser positivo o
8223 void gtk_clist_set_shift( GtkCList *clist,
8230 <!-- ----------------------------------------------------------------- -->
8231 <sect1>Almacenando punteros a datos
8233 Con una GtkCList es posible poner un puntero a datos en una
8234 fila. Este puntero no será visible al usuario, pero puede serle útil
8237 De nuevo, las funciones son lo suficientemente autoexplicativas
8240 void gtk_clist_set_row_data( GtkCList *clist,
8244 void gtk_clist_set_row_data_full( GtkCList *clist,
8247 GtkDestroyNotify destroy );
8249 gpointer gtk_clist_get_row_data( GtkCList *clist,
8252 gint gtk_clist_find_row_from_data( GtkCList *clist,
8256 <!-- ----------------------------------------------------------------- -->
8257 <sect1>Trabajando con la selección
8259 También hay funciones que nos permiten forzar la (de)selección de una
8263 void gtk_clist_select_row( GtkCList *clist,
8267 void gtk_clist_unselect_row( GtkCList *clist,
8272 Y también una función que tomará las coordenadas x e y (por ejemplo,
8273 recibidas del ratón), mirará en la lista y devolverá la fila y la
8274 columna que les corresponden.
8277 gint gtk_clist_get_selection_info( GtkCList *clist,
8284 Cuando detectemos algo interesante, como por ejemplo el movimiento del
8285 ratón, o una pulsación en cualquier lugar de la lista, podemos leer
8286 las coordenadas del ratón y encontrar en que elemento de la lista se
8287 encuentra. ¿Engorroso? Afortunadamente, hay una forma más sencilla de
8290 <!-- ----------------------------------------------------------------- -->
8291 <sect1>Las señales que lo hacen todo
8293 Como con el resto de <em>widgets</em>, hay unas cuantas señales que
8294 podemos utilizar. El <em>widget</em> GtkCList está derivado del
8295 <em>widget</em> GtkContainer, y por tanto tiene las mismas
8296 señales que éste, pero además añade las siguientes:
8299 <item><tt/select_row/ - Esta señal enviará la siguiente información,
8300 en este orden: GtkCList *clist, gint row, gint column, GtkEventButton
8303 <item><tt/unselect_row/ - Cuando el usuario deselecciona una fila, se
8304 activará esta señal. Envia la misma información que <tt/select_row/
8306 <item><tt/click_column/ - Envia GtkCList *clist, gint column
8309 Por tanto si queremos conectar una llamada a <tt/select_row/, la
8310 llamada se deberá declarar como
8313 void select_row_callback(GtkWidget *widget,
8316 GdkEventButton *event,
8320 La llamada se conectará, como siempre, con
8323 gtk_signal_connect(GTK_OBJECT( clist),
8325 GTK_SIGNAL_FUNC(select_row_callback),
8329 <!-- ----------------------------------------------------------------- -->
8330 <sect1>Un ejemplo GtkCList
8334 /* principio del ejemplo clist clist.c */
8336 #include <gtk/gtk.h>
8339 /* Aquí tenemos algunos prototipos de las funciones de llamada */
8340 void button_add_clicked( GtkWidget *boton, gpointer data);
8341 void button_clear_clicked( GtkWidget *boton, gpointer data);
8342 void button_hide_show_clicked( GtkWidget *boton, gpointer data);
8343 void selection_made( GtkWidget *clist, gint row, gint column,
8344 GdkEventButton *event, gpointer data);
8346 gint main (int argc, gchar *argv[])
8349 GtkWidget *vbox, *hbox;
8351 GtkWidget *button_add, *button_clear, *button_hide_show;
8352 gchar *titles[2] = {"Ingredients","Amount"};
8354 gtk_init(&argc, &argv);
8357 ventana=gtk_window_new(GTK_WINDOW_TOPLEVEL);
8358 gtk_widget_set_usize(GTK_WIDGET(ventana), 300, 150);
8360 gtk_window_set_title(GTK_WINDOW(ventana), "GtkCList Example");
8361 gtk_signal_connect(GTK_OBJECT(ventana),
8363 GTK_SIGNAL_FUNC(gtk_main_quit),
8366 vbox=gtk_vbox_new(FALSE, 5);
8367 gtk_container_border_width(GTK_CONTAINER(vbox), 5);
8368 gtk_container_add(GTK_CONTAINER(ventana), vbox);
8369 gtk_widget_show(vbox);
8371 /* Crear el GtkCList. Para este ejemplo utilizaremos 2 columnas */
8372 clist = gtk_clist_new_with_titles( 2, titles);
8374 /* Cuando se hace una selección, queremos saber algo acerca de
8375 * ella. La función de llamada utilizada es selection_made, y su
8376 * código lo podemos encontrar más abajo */
8377 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
8378 GTK_SIGNAL_FUNC(selection_made),
8381 /* No es necesario ponerle sombra al borde, pero es bonito :) */
8382 gtk_clist_set_border(GTK_CLIST(clist), GTK_SHADOW_OUT);
8384 /* Lo que sí que es importante, es poner el ancho de las columnas
8385 * ya no tendrán el valor correcto en caso contrario. Recuerde que
8386 * las columnas se numeran desde el 0 en adelante (hasta el 1 en
8389 gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
8391 /* Scollbars _only when needed_ */
8392 gtk_clist_set_policy(GTK_CLIST(clist), GTK_POLICY_AUTOMATIC,
8393 GTK_POLICY_AUTOMATIC);
8395 /* Añade el widget GtkCList a la caja vertical y lo muestra. */
8396 gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
8397 gtk_widget_show(clist);
8399 /* Crea los botones y los añade a la ventana. Ver la parte del
8400 * tutorial sobre botones para ver más ejemplos y comentarios
8401 * acerca de todo esto.
8403 hbox = gtk_hbox_new(FALSE, 0);
8404 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
8405 gtk_widget_show(hbox);
8407 button_add = gtk_button_new_with_label("Add List");
8408 button_clear = gtk_button_new_with_label("Clear List");
8409 button_hide_show = gtk_button_new_with_label("Hide/Show titles");
8411 gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
8412 gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
8413 gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
8415 /* Conectar nuestras funciones de llamada a los tres botones */
8416 gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
8417 GTK_SIGNAL_FUNC(button_add_clicked),
8419 gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
8420 GTK_SIGNAL_FUNC(button_clear_clicked),
8422 gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
8423 GTK_SIGNAL_FUNC(button_hide_show_clicked),
8426 gtk_widget_show(button_add);
8427 gtk_widget_show(button_clear);
8428 gtk_widget_show(button_hide_show);
8430 /* Ahora hemos terminado el interface y sólo nos queda mostrar la
8431 * ventana y entrar en el bucle gtk_main.
8433 gtk_widget_show(ventana);
8439 /* El usuario pulsó el botón "Add List". */
8440 void button_add_clicked( GtkWidget *boton, gpointer data)
8444 /* Algo tonto que añadir a la lista. 4 filas con 2 columnas cada
8447 gchar *drink[4][2] = {{"Milk", "3 Oz"},
8452 /* Aquí hacemos la adición del texto. Se hace una vez por cada
8455 for( indx=0; indx < 4; indx++)
8456 gtk_clist_append( (GtkCList*) data, drink[indx]);
8461 /* El usuario pulsó el botón "Clear List" */
8462 void button_clear_clicked( GtkWidget *boton, gpointer data)
8464 /* Borrar la lista utilizando gtk_clist_clear. Esto es mucho más
8465 * rápido que llamar a gtk_clist_remove una vez por cada fila.
8467 gtk_clist_clear((GtkCList*) data);
8472 /* El usuario pulsó el botón "Hide/Show titles". */
8473 void button_hide_show_clicked( GtkWidget *boton, gpointer data)
8475 /* Una bandera para recordar el estado. 0 = actualmente visible */
8476 static short int flag = 0;
8480 /* Oculta los títulos y pone la bandera a 1 */
8481 gtk_clist_column_titles_hide((GtkCList*) data);
8486 /* Muestra los títulos y pone la bandera a 0 */
8487 gtk_clist_column_titles_show((GtkCList*) data);
8494 /* Se llegamos aquí, entonces el usuario ha seleccionado una fila de
8497 void selection_made( GtkWidget *clist, gint row, gint column,
8498 GdkEventButton *event, gpointer data)
8502 /* Obtiene el texto que se ha almacenado en la fila y columna
8503 * sobre las que se ha pulsado. Lo recibiremos como un puntero en
8504 * el argumento text.
8506 gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
8508 /* Imprime alguna información sobre la fila seleccionada */
8509 g_print("You selected row %d. More specifically you clicked in column %d, and the text in this cell is %s\n\n", row, column, text);
8513 /* final del ejemplo */
8516 <!-- ***************************************************************** -->
8517 <sect> El <em>widget</em> árbol<label id="sec_Tree_Widgets">
8518 <!-- ***************************************************************** -->
8521 El propósito del <em>widget</em> GtkTree es mostrar datos organizados
8522 de forma jerárquica. El <em>widget</em> GtkTree en sí es un contenedor
8523 vertical para los <em>widgets</em> del tipo GtkTreeItem. GtkTree en
8524 sí mismo no es muy diferente de GtkList - ambos están derivados
8525 directamente de GtkContainer, y los métodos GtkContainer funcionan
8526 igual en los <em>widgets</em> GtkTree que en los GtkList. La
8527 diferencia es que los <em>widgets</em> GtkTree pueden anidarse
8528 dentro de otros <em>widgets</em> GtkTree. Vamos a verlo de forma
8531 El <em>widget</em> GtkTree tiene su propia ventana, y tiene por
8532 defecto un fondo de color blanco, como GtkList. La mayoría de los
8533 métodos de GtkTree funcionan igual que sus correspondientes de
8534 GtkList. Sin embargo, GtkTree no está derivado de GtkList, por lo que
8535 no puede intercambiarlos.
8537 <sect1> Creando un árbol
8539 Puede crear un GtkTree de la forma usual, utilizando:
8542 GtkWidget* gtk_tree_new( void );
8545 Como el <em>widget</em> GtkList, un GtkTree crecerá cuando le añadan
8546 elementos o cuando crezca alguno de sus subárboles. Por esta razón,
8547 suelen venir dentro de una GtkScrolledWindow. Puede que quiera
8548 utilizar <tt/gtk_widget_set_usize()/ con la ventana para asegurarse de
8549 que es lo suficientemente grande como para poder ver todos los
8550 elementos del árbol, ya que el valor por defecto de GtkScrolledWindow
8551 es bastante pequeño.
8553 Ahora que ya sabemos como crear un árbol, probablemente quiera
8554 añadirle algunos elementos. <ref id="sec_Tree_Item_Widget" name="El
8555 widget elemento de árbol"> más adelante explica todos los
8556 detalles de GtkTreeItem. Por ahora, es suficiente con saber como crear
8560 GtkWidget* gtk_tree_item_new_with_label( gchar *etiqueta );
8563 Puede añadirlo al árbol utilizando una de las siguientes funciones
8564 (ver <ref id="sec_GtkTree_Functions" name="Funciones y macros">
8565 más adelante para leer más opciones):
8568 void gtk_tree_append( GtkTree *arbol,
8569 GtkWidget *elemento_arbol );
8571 void gtk_tree_prepend( GtkTree *arbol,
8572 GtkWidget *elemento_arbol );
8575 Observe que debe añadir elementos a un GtkTree de uno en uno - no
8576 hay un equivalente a <tt/gtk_list_*_items()/.
8578 <sect1> Añadiendo un Subárbol
8580 Un subárbol se crea como cualquier otro <em>widget</em> GtkTree. Un
8581 subárbol se añade a otro árbol bajo un elemento del mismo, utilizando:
8584 void gtk_tree_item_set_subtree( GtkTreeItem *elemento_arbol,
8585 GtkWidget *subarbol );
8588 No necesita llamar a <tt/gtk_widget_show()/ en un subárbol ni antes ni
8589 después de añadirlo a GtkTreeItem. Sin embargo, <em>deberá</em> haber
8590 añadido el GtkTreeItem en cuestión a un árbol padre antes de llamar a
8591 <em/gtk_tree_item_set_subtree()/. Esto se debe a que, técnicamente,
8592 el padre del subárbol <em>no</em> es el GtkTreeItem «propietario»,
8593 sino el GtkTree que contiene al GtkTreeItem.
8595 Cuando le añade un subárbol a un GtkTreeItem, aparece el signo de un
8596 más o de un menos a su lado, donde puede pinchar el usuario para
8597 «expandirlo» u «contraerlo», o sea, para mostrar u ocultar su
8598 subárbol. Los GtkTreeItems están contraídos por defecto. Observe que
8599 cuando contrae un GtkTreeItem, cualquier elemento seleccionado en el
8600 subárbol permanece seleccionado, que puede no coincidir con lo que el
8603 <sect1> Manejando la lista de selección
8605 Como con GtkList, GtkTree tiene un campo <tt>selection</tt>, y
8606 es posible controlar el comportamiento del árbol (de alguna manera)
8607 estableciendo el tipo de selección, utilizando:
8610 void gtk_tree_set_selection_mode( GtkTree *arbol,
8611 GtkSelectionMode mode );
8614 La semántica asociada con los distintos modos de selección está
8615 descrita en la sección del <em>widget</em> GtkList. Como ocurría con
8616 el <em>widget</em> GtkList, se enviarán las señales <tt/select_child/,
8617 <tt/unselect_child/ (realmente no - ver <ref id="sec_GtkTree_Signals"
8618 name="Señales"> más adelante para una explicación), y
8619 <tt/selection_changed/ cuando los elementos de la lista sean
8620 seleccionados o deseleccionados. Sin embargo, para aprovechar estas
8621 señales, necesita conocer por medio <em>de que</em> <em>widget</em>
8622 GtkTree serán emitidas, y donde encontrar una lista con los elementos
8625 Todo esto es una potencial fuente de confusión. La mejor manera de
8626 entenderlo es imaginarse que aunque todos los <em>widgets</em> GtkTree
8627 son creados iguales, algunos son más iguales que otros. Todos los
8628 <em>widgets</em> GtkTree tienen su propia ventana X, y por tanto
8629 pueden recibir eventos como pulsaciones de ratón (¡si sus hijos o
8630 GtkTreeItems no las capturan primero!). Sin embargo, para hacer
8631 que GTK_SELECTION_SINGLE y GTK_SELECTION_BROWSE funcionen bien, la
8632 lista de elementos seleccionados debe ser específica al <em>widget</em>
8633 GtkTree superior de la jerarquia, conocido como el «árbol raíz».
8635 Por tanto no es una buena idea acceder al campo <tt>selection</tt>
8636 directamente en un <em>widget</em> GtkTree arbitrario, a menos que
8637 <em>sepa</em> que es el árbol raíz. En vez de eso, utilice la
8638 macro GTK_TREE_SELECTION (arbol), que da la lista selección del árbol
8639 raíz como un puntero <tt/GList/. Por supuesto, esta lista puede
8640 incluir elementos que no estén en el subárbol en cuestión si el tipo
8641 de selección es GTK_SELECTION_MULTIPLE.
8643 Para terminar, las señales <tt/select_child/ (y tt/unselect_child/, en
8644 teoría) son emitidas por todos los árboles, pero la señal
8645 <em/selection_changed/ es emitida sólo por el árbol raíz. En
8646 consecuencia, si quiere manipular la señal <tt/select_child/ de un
8647 árbol y todos sus subárboles, tendrá que llamar a
8648 <tt/gtk_signal_connect()/ una vez por cada subárbol.
8650 <sect1> Estructura interna del <em>widget</em> árbol
8652 La definición de la estructura GtkTree es ls siguiente:
8657 GtkContainer container;
8661 GtkTree* root_tree; /* propietario de la lista de selección */
8662 GtkWidget* tree_owner;
8666 guint current_indent;
8667 guint selection_mode : 2;
8668 guint view_mode : 1;
8669 guint view_line : 1;
8673 Ya se han mencionado los peligros asociados con el acceso directo al
8674 campo <tt>selection</tt>. Se puede acceder a los otros campos
8675 importantes de la estructura mediante macros manipuladoras o
8676 funciones de clase. GTK_TREE_IS_ROOT_TREE (arbol) devuelve un valor
8677 booleano que indica si un árbol es árbol raíz de una jerarquia
8678 GtkTree, mientras que GTK_TREE_ROOT_TREE (arbol) devuelve el árbol
8679 raíz, un objeto de tipo GtkTree (recuerde transformarlo utilizando
8680 GTK_WIDGET (arbol) si quiere utilizar con él alguna de la funciones
8681 <tt/gtk_widget_*()/).
8683 En lugar de acceder directamente al campo hijo de un <em>widget</em>
8684 GtkTree, probablemente sea mejor transformarlo utilizando
8685 GTK_CONTAINER (arbol), y pasárselo a la función
8686 <tt/gtk_container_children()/. Con esto crearemos un duplicado de la
8687 lista original, por lo que deberá eliminarlo de la memoria utilizando
8688 <tt/g_list_free()/ después haber hecho con él lo que tenga que hacer,
8689 o bien crear un bucle que lo vaya destruyendo de elemento en elemento,
8690 como por ejemplo así:
8693 hijo = gtk_container_children (GTK_CONTAINER (arbol));
8695 do_something_nice (GTK_TREE_ITEM (hijo->data));
8696 hijo = g_list_remove_link (hijo, hijo);
8700 El campo <tt>tree_owner</tt> sólo está definido en subárboles, donde
8701 apunta al <em>widget</em> GtkTreeItem que contiene al árbol en
8702 cuestión. El campo <tt>level</tt> indica el nivel de profundidad de un
8703 árbol en particular; los árboles raíz tienen un nivel 0, y cada nivel
8704 sucesivo de subárboles tiene un nivel superior al del padre. Sólo se
8705 puede asegurar que este campo contiene un valor correcto después de
8706 que el <em>widget</em> GtkTree se dibuje en la pantalla.
8708 <sect2> Señales<label id="sec_GtkTree_Signals">
8711 void selection_changed( GtkTree *arbol );
8714 Esta señal se emitirá cuando cambie el campo <tt>selection</tt> de
8715 un GtkTree. Esto ocurre cuando se selecciona o deselecciona un hijo del
8719 void select_child( GtkTree *arbol,
8723 Esta señal se emite cuando se está seleccionando un hijo del GtkTree.
8724 Esto ocurre en las llamadas a <tt/gtk_tree_select_item()/,
8725 <tt/gtk_tree_select_child()/, en <em>todas</em> las pulsaciones de
8726 botón y llamadas a <tt/gtk_tree_item_toggle()/ y
8727 <tt/gtk_item_toggle()/. Puede que a veces se invoque indirectamente en
8728 otras ocasiones, cuando el hijo se añada o elimine del GtkTree.
8731 void unselect_child (GtkTree *arbol,
8735 Esta señal se emite cuando se deselecciona un hijo del GtkTree. Con
8736 GTK+ 1.0.4, esto sólo parece ocurrir en las llamadas a
8737 <tt/gtk_tree_unselect_item()/ o a <tt/gtk_tree_unselect_child()/, y quizás
8738 en otras ocasiones, pero <em>no</em> cuando la pulsación de un botón
8739 deselecciona un hijo, y tampoco por la emisión de la señal «toggle»
8740 por <tt/gtk_item_toggle()/.
8742 <sect2> Funciones y macros<label id="sec_GtkTree_Functions">
8745 guint gtk_tree_get_type( void );
8748 Devuelve el identificador de tipo de `GtkTree'.
8751 GtkWidget* gtk_tree_new( void );
8754 Crea un nuevo objeto GtkTree. El nuevo <em>widget</em> se devuelve como
8755 un puntero a un objeto GtkWidget. Se devolverá NULL si se produce algún
8759 void gtk_tree_append( GtkTree *arbol,
8760 GtkWidget *elemento_arbol );
8763 Añade un árbol a un GtkTree.
8766 void gtk_tree_prepend( GtkTree *arbol,
8767 GtkWidget *elemento_arbol );
8770 Preañade un árbol a un GtkTree.
8773 void gtk_tree_insert( GtkTree *arbol,
8774 GtkWidget *elemento_arbol,
8778 Inserta un árbol en un GtkTree en la posición de la lista especificada
8779 por <tt>posicion.</tt>
8782 void gtk_tree_remove_items( GtkTree *arbol,
8786 Elimina una lista de elementos (en forma de una <tt/GList */) de un
8787 GtkTree. Eliminar un elemento de un árbol lo dereferencia (y por tanto
8788 normalmente) lo destruye (""), a él <em>y</em> a su subárbol, de
8789 haberlo, <em>y</em> a todos los subárboles que contenga ese
8790 subárbol. Si quiere eliminar sólo un elemento, deberá utilizar
8791 <tt/gtk_container_remove()/.
8794 void gtk_tree_clear_items( GtkTree *arbol,
8799 Elimina los elementos de un GtkTree desde la posición <tt>start</tt>
8800 hasta la posición <tt>end</tt>. De nuevo hay que llevarse cuidado
8801 con donde se aplica la dereferencia, ya que <tt/gtk_tree_clear_items()/
8802 simplemente construye una lista y se la pasa a
8803 <tt/gtk_tree_remove_items()/.
8806 void gtk_tree_select_item( GtkTree *arbol,
8810 Emite la señal <tt/select_item/ para el hijo que se encuentra en la
8811 posición <tt>item</tt>, y por tanto selecciona a ese hijo (a menos que
8812 lo deseleccione en un manejador de señal...)
8815 void gtk_tree_unselect_item( GtkTree *arbol,
8819 Emite la señal <tt/unselect_item/ para el hijo en la posición
8820 <tt>item</tt>, y por tanto deselecciona al hijo.
8823 void gtk_tree_select_child( GtkTree *arbol,
8824 GtkWidget *elemento_arbol );
8827 Emite la señal <tt/select_item/ para el hijo <tt>elemento_arbol</tt>, y por tanto
8831 void gtk_tree_unselect_child( GtkTree *arbol,
8832 GtkWidget *elemento_arbol );
8835 Emite la señal <tt/unselect_item/ para el hijo <tt>elemento_arbol</tt>, y por
8836 tanto lo deselecciona.
8839 gint gtk_tree_child_position( GtkTree *arbol,
8843 Devuelve la posición en el árbol de <tt>child</tt>, a menos que
8844 <tt>child</tt> no esté en el árbol, en cuya caso devuelve -1.
8847 void gtk_tree_set_selection_mode( GtkTree *arbol,
8848 GtkSelectionMode mode );
8851 Establece el modo de selección, que puede ser uno de los siguientes
8852 GTK_SELECTION_SINGLE (por defecto), GTK_SELECTION_BROWSE,
8853 GTK_SELECTION_MULTIPLE, o GTK_SELECTION_EXTENDED. Esto sólo está
8854 definido para los árboles raíz, que es donde tiene sentido, ya que el
8855 árbol raíz es el «propietario» de la selección. Establecer este
8856 valor en un subárbol no tiene ningún efecto en absoluto; el valor
8857 simplemente será ignorado.
8860 void gtk_tree_set_view_mode( GtkTree *arbol,
8861 GtkTreeViewMode mode );
8864 Establece el «modo de visión», que puede ser o GTK_TREE_VIEW_LINE
8865 (por defecto) o GTK_TREE_VIEW_ITEM. El modo de visión se propaga
8866 de un árbol a sus subárboles, y no puede establecerse en exclusiva
8867 para un subárbol (esto no es exacto del todo - vea los comentarios en el
8870 El termino «modo de visión» es algo ambiguo - básicamente, controla
8871 la forma en que se resalta a uno de los hijos del árbol cuando es
8872 seleccionado. Si es GTK_TREE_VIEW_LINE, se resaltará el
8873 <em>widget</em> GtkTreeItem completo, mientras que si es
8874 GTK_TREE_VIEW_ITEM, sólo se resaltará el <em>widget</em> hijo (es
8875 decir, lo que normalmente es la etiqueta).
8878 void gtk_tree_set_view_lines( GtkTree *arbol,
8882 Controla si se dibujarán las líneas de conexión entre los elementos
8883 del árbol. <tt>flag</tt> es o TRUE, en cuyo caso se dibujarán, o
8884 FALSE, en cuyo caso no se dibujarán.
8887 GtkTree *GTK_TREE (gpointer obj);
8890 Convierte un puntero genérico a `GtkTree *'.
8893 GtkTreeClass *GTK_TREE_CLASS (gpointer class);
8896 Convierte un puntero genérico a `GtkTreeClass *'.
8899 gint GTK_IS_TREE (gpointer obj);
8902 Determina si un puntero genérico se refiere a un objeto `GtkTree'.
8905 gint GTK_IS_ROOT_TREE (gpointer obj)
8908 Determina si un puntero genérico se refiere a un objeto `GtkTree'
8909 <em>y</em> es un árbol raíz. Aunque la función acepta cualquier
8910 puntero, los resultados de pasarle un puntero que no se refiera
8911 a un GtkTree no están definidos y probablemente no tengan ningún
8915 GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
8918 Devuelve el árbol raíz de un puntero a un objeto `GtkTree'. Seguimos
8919 con el mismo problema que en el caso anterior.
8922 GList *GTK_TREE_SELECTION(gpointer obj)
8925 Devuelve la lista de selección del árbol raíz de un objeto
8926 `GtkTree'. Seguimos con el mismo problema que antes.
8928 <sect1> El <em>widget</em> elemento de árbol<label id="sec_Tree_Item_Widget">
8930 El <em>widget</em> GtkTreeItem, cómo el GtkListItem, está derivado
8931 de GtkItem, que de nuevo, está derivado de GtkBin. Sin embargo, el
8932 elemento en sí mismo es un contenedor genérico que contiene un
8933 <em>widget</em> hijo, que puede ser de cualquier tipo. El <em>widget</em>
8934 GtkTreeItem tiene ciertos campos extra, pero el único que nos
8935 interesa ahora es el campo <em>subárbol</em>.
8937 La definición de la estructura GtkTreeItem es así:
8945 GtkWidget *pixmaps_box;
8946 GtkWidget *plus_pix_widget, *minus_pix_widget;
8948 GList *pixmaps /* nodo pixmap para esta profundidad de color */
8954 El campo <tt>pixmaps_box</tt> es un GtkEventBox que caza las pulsaciones
8955 en el símbolo más/menos que controla la expansión y contracción. El
8956 campo <tt>pixmaps</tt> apunta a una estructura de datos interna. Ya que
8957 siempre puede obtener el subárbol de un GtkTreeItem de una forma
8958 (relativamente) segura mediante la macro GTK_TREE_ITEM_SUBTREE (Item),
8959 es aconsejable no tocar las tripas de un GtkTreeItem a menos que
8960 <em>realmente</em> sepa que es lo que está haciendo.
8962 Ya que está derivado directamente de un GtkItem, puede tratarse como
8963 tal utilizando la macro GTK_ITEM (ElementoArbol). Un GtkTreeItem normalmente
8964 tiene una etiqueta, por lo que tenemos a nuestra disposición la
8965 función gtk_list_item_new_with_label(). Podemos conseguir el mismo
8966 efecto utilizando código como el siguiente, que por ahora es sólo
8967 una copia de la función gtk_tree_item_new_with_label():
8970 elemento_arbol = gtk_tree_item_new ();
8971 etiqueta_widget = gtk_label_new (etiqueta);
8972 gtk_misc_set_alignment (GTK_MISC (etiqueta_widget), 0.0, 0.5);
8974 gtk_container_add (GTK_CONTAINER (elemento_arbol), etiqueta_widget);
8975 gtk_widget_show (etiqueta_widget);
8978 Cómo no es obligatorio añadir una GtkLabel a un GtkTreeItem, puede
8979 también añadirle un GtkHBox o una GtkArrow, o hasta un GtkNotebook
8980 (aunque en esos casos su aplicación no será muy popular).
8982 Si elimina todos los elementos de un subárbol, será destruido
8983 y se eliminará la información sobre su padre, a menos que lo
8984 referencie de antemano, además el GtkTreeItem que sea su propietario
8985 se colapsará. Por lo tanto, si quiere que se mantenga el subárbol
8986 tendrá que hacer algo así:
8989 gtk_widget_ref (arbol);
8990 propietario = GTK_TREE(arbol)->tree_owner;
8991 gtk_container_remove (GTK_CONTAINER(arbol), item);
8992 if (arbol->parent == NULL){
8993 gtk_tree_item_expand (GTK_TREE_ITEM(propietario));
8994 gtk_tree_item_set_subtree (GTK_TREE_ITEM(propietario), arbol);
8997 gtk_widget_unref (arbol);
9000 Finalmente, hay que mencionar que la opción de drag-n-drop (arrastar y
9001 soltar) <em>funciona</em> con los GtkTreeItems. Sólo tiene que
9002 asegurarse de que el GtkTreeItem que quiere convertir en un elemento
9003 de arrastre o en un lugar en el que, además de haber sido añadido a
9004 GtkTree, sino que además cada su <em>widget</em> padre tiene a su vez
9005 un padre, y así hasta llegar al nivel más alto o ventana de diálogo,
9006 cuando llamamos a <tt/gtk_widget_dnd_drag_set()/ o
9007 <tt/gtk_widget_dnd_drop_set()/. En caso contrario, podrían ocurrir
9012 GtkTreeItem hereda las señales <tt/select/, <tt/deselect/, y
9013 <tt/toggle/ de GtkItem. Además, añade dos señales propias, <tt/expand/
9017 void select( GtkItem *elemento_arbol );
9020 Esta señal se emite cuando un elemento está siendo seleccionado,
9021 o bien después de que el usuario pinche en él, o bien cuando
9022 el programa llame a <tt/gtk_tree_item_select()/,
9023 <tt/gtk_item_select()/, o a <tt/gtk_tree_select_child()/.
9026 void deselect( GtkItem *elemento_arbol );
9029 Esta señal se emite cuando un elemento está siendo deseleccionado,
9030 o bien después de que el usuario pinche en él, o bien cuando
9031 el programa llame a <tt/gtk_tree_item_deselect()/ o a
9032 <tt/gtk_item_deselect()/. En el caso de GtkTreeItems, también se
9033 emitirá por <tt/gtk_tree_unselect_child()/, y a veces por
9034 <tt/gtk_tree_select_child()/.
9037 void toggle( GtkItem *elemento_arbol );
9040 Esta señal se emite cuando el programa llama a <tt/gtk_item_toggle()/. El
9041 efecto que tiene cuando se emite en un GtkTreeItem es llamar a
9042 <tt/gtk_tree_select_child()/ (y nunca a
9043 <tt/gtk_tree_unselect_child()/) en el árbol padre del elemento, si el
9044 elemento tiene un árbol padre. Si no lo tiene, entonces se cambiará el
9045 resaltado del elemento.
9048 void expand( GtkTreeItem *elemento_arbol );
9051 Esta señal se emite cuando se está expandiendo el subárbol del
9052 elemento, esto es, cuando el usuario pincha en el signo más que
9053 hay al lado del elemento, o cuando el programa llama a
9054 <tt/gtk_tree_item_expand()/.
9057 void collapse( GtkTreeItem *elemento_arbol );
9060 Esta señal se emite cuando se está contrayendo el subárbol del
9061 elemento, esto es, cuando el usuario pincha en el signo menos que hay
9062 al lado del elemento, o cuando el programa llama a
9063 <tt/gtk_tree_item_collapse()/.
9065 <sect2> Funciones y Macros
9068 guint gtk_tree_item_get_type( void );
9071 Devuelve el identificador de tipo de `GtkTreeItem'.
9074 GtkWidget* gtk_tree_item_new( void );
9077 Crea un nuevo objeto GtkTreeItem. El nuevo <em>widget</em> se devuelve
9078 como un puntero a un objeto GtkWidget. Se devolverá NULL si hay algún
9082 GtkWidget* gtk_tree_item_new_with_label (gchar *etiqueta);
9085 Crea un nuevo objeto GtkTreeItem, teniendo una simple GtkLabel
9086 como único hijo. El nuevo <em>widget</em> se devolverá como
9087 un puntero a un objeto GtkWidget. Se devolverá NULL en caso
9088 de haber algún fallo.
9091 void gtk_tree_item_select( GtkTreeItem *elemento_arbol );
9094 Esta función es básicamente un recubrimiento de una llamada a
9095 gtk_item_select (GTK_ITEM (elemento_arbol)) que emitirá la
9099 void gtk_tree_item_deselect( GtkTreeItem *elemento_arbol );
9102 Esta función es básicamente un recubrimiento de una llamada a
9103 gtk_item_deselect (GTK_ITEM (elemento_arbol)) que emitirá la
9107 void gtk_tree_item_set_subtree( GtkTreeItem *elemento_arbol,
9108 GtkWidget *subarbol );
9111 Esta función añade <tt/subarbol/ a <tt/elemento_arbol/, mostrándolo si
9112 <tt/elemento_arbol/ está expandido, u ocultándolo si <tt/elemento_arbol/ está
9113 contraído. De nuevo, recuerde que el <tt/elemento_arbol/ ya debe de haber
9114 sido añadido a un árbol para que esto funcione.
9117 void gtk_tree_item_remove_subtree( GtkTreeItem *elemento_arbol );
9120 Esto elimina todos los hijos de los subárboles del <tt/elemento_arbol/
9121 (esto es, dereferencia y destruye a los subárboles hijos, y a los
9122 hijos de los hijos y...), entonces elimina el subárbol en si mismo, y
9123 oculta el signo más/menos.
9126 void gtk_tree_item_expand( GtkTreeItem *elemento_arbol );
9129 Esto emite la señal «expand» para el <tt/elemento_arbol/, que lo
9133 void gtk_tree_item_collapse( GtkTreeItem *elemento_arbol );
9136 Esto emite la señal «collapse» en el <tt/elemento_arbol/, que lo
9140 GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
9143 Convierte un puntero genérico en un `GtkTreeItem *'.
9146 GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
9149 Convierte un puntero genérico en un `GtkTreeItemClass'.
9152 gint GTK_IS_TREE_ITEM (gpointer obj)
9155 Determina si un puntero genérico se refiere a un objeto `GtkTreeItem'.
9158 GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
9161 Devuelve un subárbol del elemento (<tt/obj/ debería apuntar a un
9162 objeto `GtkTreeItem').
9164 <sect1> Árbol ejemplo
9166 Este ejemplo es muy parecido al árbol ejemplo que hay en
9167 <tt/testgtk.c/, pero mucho menos completo (aunque mucho mejor
9168 comentado). Pone una ventana con un árbol, y conecta todas las señales
9169 de los objetos relevantes, con lo que podrá ver cuando se emiten.
9171 <!-- Hay un comentario en el código que no se traducir -->
9173 /* principio del ejemplo tree tree.c */
9175 #include <gtk/gtk.h>
9177 /* para todas las señales GtkItem:: y GtkTreeItem:: */
9178 static void cb_itemsignal (GtkWidget *item, gchar *signame)
9183 /* Es un GtkBin, por lo que tiene un hijo, que sabemos que es una
9184 * etiqueta, por lo que la cogemos */
9185 etiqueta = GTK_LABEL (GTK_BIN (item)->child);
9186 /* Conseguimos el texto de la etiqueta */
9187 gtk_label_get (etiqueta, &name);
9188 /* Conseguimos el nivel del árbol en el que se encuentra el elemento */
9189 g_print ("%s called for item %s->%p, level %d\n", signame, name,
9190 item, GTK_TREE (item->parent)->level);
9193 /* nunca se llamará a esta función */
9194 static void cb_unselect_child (GtkWidget *arbol_raiz, GtkWidget *hijo,
9195 GtkWidget *subarbol)
9197 g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
9198 arbol_raiz, subarbol, hijo);
9201 /* Se llamará a esta función cada vez que el usuario pulse en un
9202 * elemento, esté o no seleccionado. */
9203 whether it is already selected or not. */
9204 static void cb_select_child (GtkWidget *arbol_raiz, GtkWidget *hijo,
9205 GtkWidget *subarbol)
9207 g_print ("select_child called for root tree %p, subtree %p, child %p\n",
9208 arbol_raiz, subarbol, hijo);
9211 static void cb_selection_changed (GtkWidget *arbol)
9215 g_print ("selection_change called for tree %p\n", arbol);
9216 g_print ("selected objects are:\n");
9218 i = GTK_TREE_SELECTION(arbol);
9224 /* Get a GtkWidget pointer from the list node */
9225 item = GTK_WIDGET (i->data);
9226 etiqueta = GTK_LABEL (GTK_BIN (item)->child);
9227 gtk_label_get (etiqueta, &name);
9228 g_print ("\t%s on level %d\n", name, GTK_TREE
9229 (item->parent)->level);
9234 int main (int argc, char *argv[])
9236 GtkWidget *ventana, *scrolled_win, *arbol;
9237 static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
9241 gtk_init (&argc, &argv);
9243 /* una ventana general */
9244 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9245 gtk_signal_connect (GTK_OBJECT(ventana), "delete_event",
9246 GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
9247 gtk_container_border_width (GTK_CONTAINER(ventana), 5);
9249 /* una ventana con barras de desplazamiento */
9250 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
9251 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
9252 GTK_POLICY_AUTOMATIC,
9253 GTK_POLICY_AUTOMATIC);
9254 gtk_widget_set_usize (scrolled_win, 150, 200);
9255 gtk_container_add (GTK_CONTAINER(ventana), scrolled_win);
9256 gtk_widget_show (scrolled_win);
9258 /* Crear el árbol raíz */
9259 arbol = gtk_tree_new();
9260 g_print ("root tree is %p\n", arbol);
9261 /* connect all GtkTree:: signals */
9262 gtk_signal_connect (GTK_OBJECT(arbol), "select_child",
9263 GTK_SIGNAL_FUNC(cb_select_child), arbol);
9264 gtk_signal_connect (GTK_OBJECT(arbol), "unselect_child",
9265 GTK_SIGNAL_FUNC(cb_unselect_child), arbol);
9266 gtk_signal_connect (GTK_OBJECT(arbol), "selection_changed",
9267 GTK_SIGNAL_FUNC(cb_selection_changed), arbol);
9268 /* Añadirlo a la ventana con barras de desplazamiento */
9269 gtk_container_add (GTK_CONTAINER(scrolled_win), arbol);
9270 /* Poner el modo de selección */
9271 gtk_tree_set_selection_mode (GTK_TREE(arbol),
9272 GTK_SELECTION_MULTIPLE);
9273 /* mostrar el árbol */
9274 gtk_widget_show (arbol);
9276 for (i = 0; i < 5; i++){
9277 GtkWidget *subarbol, *item;
9280 /* Crear un elemento del árbol */
9281 item = gtk_tree_item_new_with_label (itemnames[i]);
9282 /* Conectar todas las señales GtkItem:: y GtkTreeItem:: */
9283 gtk_signal_connect (GTK_OBJECT(item), "select",
9284 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9285 gtk_signal_connect (GTK_OBJECT(item), "deselect",
9286 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9287 gtk_signal_connect (GTK_OBJECT(item), "toggle",
9288 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9289 gtk_signal_connect (GTK_OBJECT(item), "expand",
9290 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9291 gtk_signal_connect (GTK_OBJECT(item), "collapse",
9292 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9293 /* Añadirlo al árbol padre */
9294 gtk_tree_append (GTK_TREE(arbol), item);
9295 /* Mostrarlo - esto se puede hacer en cualquier momento */
9296 gtk_widget_show (item);
9297 /* Crear el subárbol de este elemento */
9298 subarbol = gtk_tree_new();
9299 g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
9302 /* Esto todavía es necesario si quiere que se llamen a están
9303 * señales en el subárbol hijo. Note that selection_change will
9304 * be signalled for the root tree regardless. */
9305 gtk_signal_connect (GTK_OBJECT(subarbol), "select_child",
9306 GTK_SIGNAL_FUNC(cb_select_child), subarbol);
9307 gtk_signal_connect (GTK_OBJECT(subarbol), "unselect_child",
9308 GTK_SIGNAL_FUNC(cb_unselect_child), subarbol);
9309 /* Esto no tiene absolutamente ningún efecto, ya que se ignora
9310 * completamente en los subárboles */
9311 gtk_tree_set_selection_mode (GTK_TREE(subarbol),
9312 GTK_SELECTION_SINGLE);
9313 /* Esto tampoco hace nada, pero por una razón diferente - los
9314 * valores view_mode y view_line de un árbol se propagan a los
9315 * subárboles cuando son mapeados. Por tanto, establecer los
9316 * valores después actualmente tendría (algún impredecible) efecto
9318 gtk_tree_set_view_mode (GTK_TREE(subarbol), GTK_TREE_VIEW_ITEM);
9319 /* Establecer este subárbol del elemento - ¡Recuerde que no puede
9320 * hacerlo hasta que se haya añadido a su árbol padre! */
9321 gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subarbol);
9323 for (j = 0; j < 5; j++){
9326 /* Crea un elemento subárbol, más o menos lo mismo de antes */
9327 subitem = gtk_tree_item_new_with_label (itemnames[j]);
9328 /* Conectar todas las señales GtkItem:: y GtkTreeItem:: */
9329 gtk_signal_connect (GTK_OBJECT(subitem), "select",
9330 GTK_SIGNAL_FUNC(cb_itemsignal), "select");
9331 gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
9332 GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
9333 gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
9334 GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
9335 gtk_signal_connect (GTK_OBJECT(subitem), "expand",
9336 GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
9337 gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
9338 GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
9339 g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
9340 /* Añadirlo a su árbol padre */
9341 gtk_tree_append (GTK_TREE(subarbol), subitem);
9343 gtk_widget_show (subitem);
9347 /* Mostrar la ventana y entrar en el bucle final */
9348 gtk_widget_show (ventana);
9352 /* fin del ejemplo */
9355 <!-- ***************************************************************** -->
9356 <sect> El <em>widget</em> menú
9357 <!-- ***************************************************************** -->
9359 Hay dos formas de crear menús, la fácil, y la difícil. Ambas tienen su
9360 utilidad, aunque lo más probable es que normalmente utilice la
9361 menufactory (la forma fácil). La forma «difícil» consiste en crear
9362 todos los menús utilizando las llamadas directamente. La forma fácil
9363 consiste en utilizar las llamadas de <tt/gtk_item_factory/. Es mucho
9364 más fácil, pero aun así cada aproximación tiene sus ventajas y sus
9367 La menufactory es mucho más fácil de utilizar, y tambíen es más fácil
9368 añadir nuevos menús, aunque a larga, escribiendo unas cuántas
9369 funciones de recubrimiento para crear menús utilizando el método
9370 manual puede acabar siendo más útil. Con la itemfactory, no es posible
9371 añadir imágenes o el carácter `/' a los menús.
9373 <!-- ----------------------------------------------------------------- -->
9374 <sect1>Creación manual de menús
9376 Siguiendo la auténtica tradición de la enseñanza, vamos a enseñarle
9377 primero la forma difícil. <tt>:)</tt>
9379 Se utilizan tres <em>widgets</em> para hacer una barra de menús y
9382 <item>un elemento del menú, que es lo que el usuario quiere seleccionar,
9384 <item>un menú, que actua como un contenedor para los elementos del menú, y
9385 <item>una barra de menú, que es un contenedor para cada uno de los menús,
9388 Todo esto se complica ligeramente por el hecho de que los
9389 <em>widgets</em> de los elementos del menú se utilizan para dos cosas
9390 diferentes. Están los <em>widgets</em> que se empaquetan en el menú, y
9391 los que se empaquetan en una barra de menús, que cuando se selecciona,
9394 Vamos a ver las funciones que se utilizan para crear menús y barras
9395 de menús. ésta primera función se utiliza para crear una barra de menús.
9398 GtkWidget *gtk_menu_bar_new( void );
9401 Como el propio nombre indica, esta función crea una nueva barra de
9402 menús. Utilice <tt/gtk_container_add/ para empaquetarla en una
9403 ventana, o las funciones <tt/box_pack/ para empaquetarla en una caja -
9404 exactamente igual que si fuesen botones.
9407 GtkWidget *gtk_menu_new( void );
9410 Esta función devuelve un puntero a un nuevo menú, que no se debe
9411 mostrar nunca (no hace falta utilizar <tt/gtk_widget_show/), es sólo
9412 un contenedor para los elementos del menú. Espero que todo esto se
9413 aclare un poco cuando vea en el ejemplo que hay más abajo.
9415 Las siguientes dos llamadas se utilizan para crear elementos de menú
9416 que se empaquetarán en el menú (y en la barra de menú).
9419 GtkWidget *gtk_menu_item_new( void );
9425 GtkWidget *gtk_menu_item_new_with_label( const char *etiqueta );
9428 Estas llamadas se utilizan para crear los elementos del menú que
9429 van a mostrarse. Recuerde que hay que distinguir entre un «menú»
9430 creado con <tt/gtk_menu_new/ y un «elemento del menú» creado con las
9431 funciones <tt/gtk_menu_item_new/. El elemento de menú será un botón
9432 con una acción asociada, y un menú será un contenedor con los
9435 Las funciones <tt/gtk_menu_new_with_label/ y <tt/gtk_menu_new/ son
9436 sólo lo que espera que sean después de leer lo de los botones. Una
9437 crea un nuevo elemento del menú con una etiqueta ya dentro, y la otra
9438 crea un elemento del menú en blanco.
9440 Una vez ha creado un elemento del menú tiene que ponerlo en un menú.
9441 Esto se hace utilizando la función <tt/gtk_menu_append/. Para capturar
9442 el momento en el que el elemento se selecciona por el usuario,
9443 necesitamos conectar con la señal <tt/activate/ de la forma usual. Por
9444 tanto, si quiere crear un menú estándar <tt/File/, con las opciones
9445 <tt/Open/, <tt/Save/ y <tt/Quit/ el código debería ser algo como
9448 file_menu = gtk_menu_new(); /* No hay que mostrar menús */
9450 /* Crear los elementos del menú */
9451 open_item = gtk_menu_item_new_with_label("Open");
9452 save_item = gtk_menu_item_new_with_label("Save");
9453 quit_item = gtk_menu_item_new_with_label("Quit");
9455 /* Añadirlos al menú */
9456 gtk_menu_append( GTK_MENU(file_menu), open_item);
9457 gtk_menu_append( GTK_MENU(file_menu), save_item);
9458 gtk_menu_append( GTK_MENU(file_menu), quit_item);
9460 /* Enlazar las función de llamada a la señal "activate" */
9461 gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
9462 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
9463 gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
9464 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
9466 /* Podemos enlazar el elemento de menú Quit con nuestra función de
9468 gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
9469 GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
9471 /* Tenemos que mostrar los elementos del menú */We do need to show menu items */
9472 gtk_widget_show( open_item );
9473 gtk_widget_show( save_item );
9474 gtk_widget_show( quit_item );
9477 En este momento tendremos nuestro menú. Ahora necesitamos crear una
9478 barra de menús y un elemento de menú para el elemento <tt/File/, que
9479 vamos a añadir a nuestro menú. El código es el siguiente
9482 menu_bar = gtk_menu_bar_new();
9483 gtk_container_add( GTK_CONTAINER(ventana), menu_bar);
9484 gtk_widget_show( menu_bar );
9486 file_item = gtk_menu_item_new_with_label("File");
9487 gtk_widget_show(file_item);
9490 Ahora necesitamos asociar el menú con <tt/file_item/. Esto se hace con
9494 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
9495 GtkWidget *submenu );
9498 Por lo que nuestro ejemplo continua con
9501 gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
9504 Todo lo que queda por hacer es añadir el menú a la barra de menús, que
9505 se hace mediante la función
9508 void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
9511 que en nuestro caso habrá que utilizar así:
9514 gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
9517 Si queremos que el menú esté alineado a la derecha en la barra de
9518 menús, como suele estar la opción de ayuda, podemos utilizar la
9519 función siguiente (otra vez en <tt/file_item/ en el ejemplo actual)
9520 antes de enlazarla en la barra de menú.
9523 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
9526 Aquí hay un resumen de los pasos que son necesarios para crear una
9527 barra de menús con los menús correspondientes ya enlazados:
9530 <item> Crear un nuevo menú utilizando <tt/gtk_menu_new()/
9531 <item> Utilizar multiples llamadas a <tt/gtk_menu_item_new()/ para
9532 cada elemento que desee tener en su menú. Y utilizar
9533 <tt/gtk_menu_append()/ para poner cada uno de esos nuevos elementos en
9535 <item> Crear un elemento de menú utilizando
9536 <tt/gtk_menu_item_new()/. Ésta será la raíz del menú, el texto que
9537 aparezca aquí estará en la barra de menús.
9538 <item> Utilizar <tt/gtk_menu_item_set_submenu()/ para enlazar el menú
9539 al elemento del menú raíz (el creado en el paso anterior).
9540 <item> Crear una nueva barra de menús utilizando
9541 <tt/gtk_menu_bar_new/. Este paso solo necesita hacerse una vez cuando
9542 se crea una serie de menús en una barra de menús.
9543 <item> Utilizar <tt/gtk_menu_bar_append/ para poner el menú raíz en la
9547 Para hacer un menú desplegable hay que seguir prácticamente los mismos
9548 pasos. La única diferencia es que el menú no estará conectado
9549 `automáticamente' a una barra de menú, sino que para que aparezca
9550 deberá llamarse explícitamente a la función <tt/gtk_menu_popup()/
9551 utilizando, por ejemplo, un evento de pulsación de botón. Siga los
9555 <item>Cree una función manejadora de eventos. Tiene que tener el
9558 static gint handler( GtkWidget *widget,
9562 y utilice el evento para encontrar donde debe aparecer el menú.
9564 <item>En el manejador de eventos, si el evento es una pulsación de un
9565 botón del ratón, tratar <tt>event</tt> como un evento de botón
9566 (que lo es) y utilizarlo como se indica en el código ejemplo para
9567 pasarle información a <tt/gtk_menu_popup()/.
9568 <item>Enlazar este manejador de eventos con el <em>widget</em> con
9570 gtk_signal_connect_object(GTK_OBJECT(widget), "event",
9571 GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
9573 donde <tt>widget</tt> es el <em>widget</em> con el que esta conectando,
9574 <tt>handler</tt> es la función manejadora, y <tt>menu</tt> es un menú
9575 creado con <tt/gtk_menu_new()/. Éste puede ser un menú que esté
9576 contenido en una barra de menús, como se puede ver en el código de
9580 <!-- ----------------------------------------------------------------- -->
9581 <sect1>Ejemplo de la creación manual de un menú
9583 Esto debería funcionar. Échele un vistazo al ejemplo para aclarar los
9587 /* principio del ejemplo menu menu.c */
9589 #include <gtk/gtk.h>
9591 static gint button_press (GtkWidget *, GdkEvent *);
9592 static void menuitem_response (gchar *);
9594 int main (int argc, char *argv[])
9599 GtkWidget *menu_bar;
9600 GtkWidget *root_menu;
9601 GtkWidget *menu_items;
9607 gtk_init (&argc, &argv);
9609 /* crear una nueva ventana */
9610 ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
9611 gtk_widget_set_usize( GTK_WIDGET (ventana), 200, 100);
9612 gtk_window_set_title(GTK_WINDOW (ventana), "GTK Menu Test");
9613 gtk_signal_connect(GTK_OBJECT (ventana), "delete_event",
9614 (GtkSignalFunc) gtk_main_quit, NULL);
9616 /* Inicializar el widget-menu, y recuerde -- ¡¡Nunca haga
9617 * gtk_show_widget() con el widget menu!!
9618 * Éste es el menú que contiene todos los elementos del menú, el
9619 * que se desplegará cuando pulse en el "Root Menu" en la
9622 menu = gtk_menu_new();
9624 /* Ahora hacemos un pequeño bucle que crea tres elementos de menú
9625 * para "test-menu". Recuerde llamar a gtk_menu_append. Aquí
9626 * estamos añadiendo una lista de elementos de menú a nuestro
9627 * menú. Normalmente tendríamos que cazar aquí la señal "clicked"
9628 * de cada uno de los elementos del menú y le deberíamos dar una
9629 * función de llamada a cada uno, pero lo vamos a omitimos para
9630 * ahorrar espacio. */
9632 for(i = 0; i < 3; i++)
9634 /* Copia los nombres al búfer. */
9635 sprintf(buf, "Test-undermenu - %d", i);
9637 /* Crea un nuevo elemento de menú con un nombre... */
9638 menu_items = gtk_menu_item_new_with_label(buf);
9640 /* ...y lo añade al menú. */
9641 gtk_menu_append(GTK_MENU (menu), menu_items);
9643 /* Hace algo interesante cuando se selecciona el menuitem */
9644 gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
9645 GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
9647 /* Muestra el widget */
9648 gtk_widget_show(menu_items);
9651 /* Ésta es el menú raíz, y será la etiqueta mostrada en la
9652 * barra de menús. No habrá ningún manejador de señal conectado, ya que
9653 * lo único que hace es desplegar el resto del menú. */
9654 root_menu = gtk_menu_item_new_with_label("Root Menu");
9656 gtk_widget_show(root_menu);
9658 /* Ahora especificamos que queremos que el recien creado "menu"
9659 * sea el menú para el "root menu" */
9660 gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
9662 /* Un vbox para poner dentro un menú y un botón */
9663 vbox = gtk_vbox_new(FALSE, 0);
9664 gtk_container_add(GTK_CONTAINER(ventana), vbox);
9665 gtk_widget_show(vbox);
9667 /* Crear una barra de menú para que contenga al menú y la añadamos
9668 * a nuestra ventana principal */
9669 menu_bar = gtk_menu_bar_new();
9670 gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
9671 gtk_widget_show(menu_bar);
9673 /* Crear un botón al que atar los menús como un popup */
9674 boton = gtk_button_new_with_label("press me");
9675 gtk_signal_connect_object(GTK_OBJECT(boton), "event",
9676 GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
9677 gtk_box_pack_end(GTK_BOX(vbox), boton, TRUE, TRUE, 2);
9678 gtk_widget_show(boton);
9680 /* Y finalmente añadimos el elemento de menú y la barra de menú --
9681 * éste es el elemento de menú "raíz" sobre el que he estado
9683 gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
9685 /* siempre mostramos la ventana como último paso para que todo se
9686 * pongo en pantalla a la vez. */
9687 gtk_widget_show(ventana);
9694 /* Responde a una pulsación del botón enviando un menú como un widget
9695 * Recuerde que el argumento "widget" es el menú que se está enviando,
9696 * NO el botón que se ha pulsado.
9699 static gint button_press (GtkWidget *widget, GdkEvent *event)
9702 if (event->type == GDK_BUTTON_PRESS) {
9703 GdkEventButton *bevent = (GdkEventButton *) event;
9704 gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
9705 bevent->button, bevent->time);
9706 /* Le dice al que llamó a la rutina que hemos manejado el
9707 * evento; la historia termina aquí. */
9711 /* Le dice al que llamó a la rutina que no hemos manejado el
9717 /* Imprime una cadena cuando se selecciona un elemento del menú */
9719 static void menuitem_response (gchar *string)
9721 printf("%s\n", string);
9723 /* final del ejemplo */
9726 También puede hacer que un elemento del menú sea insensible y, utilizando
9727 una tabla de teclas aceleradoras, conectar las teclas con las funciones
9730 <!-- XXX Las dos sect1 que vienen han cambiado -->
9731 <!-- ----------------------------------------------------------------- -->
9732 <sect1>Utilizando GtkItemFactory
9734 Ahora que le hemos enseñado la forma difícil, le mostraremos como
9735 utilizar las llamadas <tt/gtk_item_factory/.
9737 <!-- ----------------------------------------------------------------- -->
9738 <sect1>Ejemplo de la fábrica de elementos
9740 Aquí hay un ejemplo de cómo utilizar la fábrica de elementos
9744 /* principio del ejemplo menu itemfactory.h */
9746 #include <gtk/gtk.h>
9747 #include <strings.h>
9749 /* La obligatoria función de llamada */
9750 static void print_hello( GtkWidget *w,
9753 g_message ("Hello, World!\n");
9756 /* Esta es la estructura GtkItemFactoryEntry utilizada para crear
9759 This is the GtkItemFactoryEntry structure used to generate new menus.
9760 Elemento 1: La dirección del menú. La letra que hay
9761 después del subrayado indica una tecla aceleradora
9762 una vez que el menú esté abierto.
9763 Elemento 2: La tecla aceleradora para la entrada del menú.
9764 Elemento 3: La función de llamada.
9765 Elemento 4: La acción de llamada. Cambia los parámetros que
9766 se le pasan a la función de llamada. El valor por
9768 Elemento 5: El tipo de elemento, se utiliza para definir de que
9769 tipo de elemento se trata. Los valores posibles son:
9773 "<Title>" -> crea un elemento título
9774 "<Item>" -> crea un simple elemento
9775 "<CheckItem>" -> crea un elemento de comprobación
9776 "<ToggleItem>" -> crea un elemento de selección
9777 "<RadioItem>" -> crea un elemento circular
9778 <path> -> dirección de un elemento circular
9780 "<Separator>" -> crea un separador
9781 "<Branch>" -> crea un elemento para contener
9782 subelementos (de forma opcional)
9783 "<LastBranch>" -> crea una rama justificada a la
9787 static GtkItemFactoryEntry menu_items[] = {
9788 { "/_File", NULL, NULL, 0, "<Branch>" },
9789 { "/File/_New", "<control>N", print_hello, 0, NULL },
9790 { "/File/_Open", "<control>O", print_hello, 0, NULL },
9791 { "/File/_Save", "<control>S", print_hello, 0, NULL },
9792 { "/File/Save _As", NULL, NULL, 0, NULL },
9793 { "/File/sep1", NULL, NULL, 0, "<Separator>" },
9794 { "/File/Quit", "<control>Q", gtk_main_quit, 0, NULL },
9795 { "/_Options", NULL, NULL, 0, "<Branch>" },
9796 { "/Options/Test", NULL, NULL, 0, NULL },
9797 { "/_Help", NULL, NULL, 0, "<LastBranch>" },
9798 { "/_Help/About", NULL, NULL, 0, NULL },
9802 void get_main_menu( GtkWidget *ventana,
9803 GtkWidget **menubar )
9805 GtkItemFactory *item_factory;
9806 GtkAccelGroup *accel_group;
9807 gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
9809 accel_group = gtk_accel_group_new ();
9811 /* Esta función inicializa la fábrica de elementos
9812 Param 1: El tipo de menú - puede ser GTK_TYPE_MENU_BAR,
9813 GTK_TYPE_MENU, o GTK_TYPE_OPTION_MENU.
9814 Param 2: La dirección del menú.
9815 Param 3: Un puntero a un gtk_accel_group. La fábrica de
9816 elementos actualiza la tabla de teclas aceleradoras
9817 mientras genera los menúes.
9820 item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
9823 /* Esta función genera los elementos de menú. Pasa la
9824 fábrica de elementos (item_factory), el número de elementos
9825 del vector, el vector en sí, y cualquier dato de llamada para
9826 los elementos de menú. */
9827 gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9829 /* Enlaza el nuevo grupo acelerador a la ventana. */
9830 gtk_accel_group_attach (accel_group, GTK_OBJECT (ventana));
9833 /* Finalmente, devuelve la barra de menú creada por la
9834 * fábrica de elementos. */
9835 *menubar = gtk_item_factory_get_widget (item_factory, "<main>");
9842 GtkWidget *main_vbox;
9845 gtk_init (&argc, &argv);
9847 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9848 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
9849 GTK_SIGNAL_FUNC (gtk_main_quit),
9851 gtk_window_set_title (GTK_WINDOW(ventana), "Item Factory");
9852 gtk_widget_set_usize (GTK_WIDGET(ventana), 300, 200);
9854 main_vbox = gtk_vbox_new (FALSE, 1);
9855 gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
9856 gtk_container_add (GTK_CONTAINER (ventana), main_vbox);
9857 gtk_widget_show (main_vbox);
9859 get_main_menu (ventana, &menubar);
9860 gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
9861 gtk_widget_show (menubar);
9863 gtk_widget_show (ventana);
9868 /* fin del ejemplo */
9871 Por ahora, sólo está este ejemplo. Ya llegará una
9872 explicación del mismo y más comentarios.
9874 <!-- ***************************************************************** -->
9875 <sect> El <em>widget</em> texto
9876 <!-- ***************************************************************** -->
9878 El <em>widget</em> texto permite mostrar y editar multiples líneas de
9879 texto. Admite texto en varios colores y con varios tipos de letra,
9880 permitiendo mezclarlos de cualquier forma que desee. También hay un
9881 gran número de teclas para la edición de textos, que son compatibles
9884 El <em>widget</em> texto admite copiar-y-pegar, incluyendo la
9885 utilización de doble y triple-click para seleccionar una palabra y una
9886 línea completa, respectivamente.
9888 <!-- ----------------------------------------------------------------- -->
9889 <sect1>Creando y configurando un cuadro de texto
9891 Sólo hay una función para crear un nuevo <em>widget</em> texto.
9893 GtkWidget *gtk_text_new( GtkAdjustment *hadj,
9894 GtkAdjustment *vadj );
9897 Los argumentos nos permitirán dar al <em>widget</em> texto punteros a
9898 <tt/GtkAdjustement/ que pueden ser utilizados para controlar la visión
9899 de la posición del <em>widget</em>. Si le ponemos un valor NULL en
9900 cualquiera de los dos argumentos (o en los dos), la función
9901 <tt/gtk_text_new/ creará su propio ajuste.
9904 void gtk_text_set_adjustments( GtkText *text,
9905 GtkAdjustment *hadj,
9906 GtkAdjustment *vadj );
9909 La función de arriba permite cambiar en cualquier momento el ajuste
9910 horizontal y vertical de un <em>widget</em> texto.
9912 El <em>widget</em> texto no crea automáticamente sus propiar barras
9913 de desplazamiento cuando el texto a mostrar es demasiado largo
9914 para la ventana en la que se encuentra. Tenemos que crearlas y
9915 añadirlas a la capa del <em>display</em> nosotros mismos.
9918 vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
9919 gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
9920 gtk_widget_show (vscrollbar);
9923 El trozo de código de arriba crea una nueva barra de desplazamiento
9924 vertical, y la conecta con el ajuste vertical del <em>widget</em>
9925 de texto, <tt/text/. Entonces la empaqueta en un cuadro de la forma
9928 Observe que, actualmente el <em>widget</em> GtkText no admite barras
9929 de desplazamiento horizontal.
9931 Principalmente hay dos maneras de utilizar un <em>widget</em> de
9932 texto: permitiendo al usuario editar el texto, o permitiéndonos
9933 mostrar varias líneas de texto al usuario. Para cambiar entre estos
9934 dos modos de operación, el <em>widget</em> de texto tiene las
9935 siguientes funciones:
9938 void gtk_text_set_editable( GtkText *text,
9942 El argumento <tt/editable/ es un valor TRUE o FALSE que especifica si se
9943 permite al usuario editar los contenidos del <em>widget</em> texto.
9944 Cuando el <em>widget</em> texto se pueda editar, mostrará un cursor
9945 en la posición actual de inserción.
9947 Sin embargo la utilización del <em>widget</em> en estos dos modos no
9948 es algo permanente, ya que puede cambiar el estado editable del
9949 <em>widget</em> texto e insertar texto en cualquier momento.
9951 El <em>widget</em> texto corta las líneas de texto que son demasiado
9952 largas para que quepan en una sólo línea en la ventana. Su
9953 comportamiento por defecto es cortar las palabras donde se terminan
9954 las líneas. Esto puede cambiarse utilizando la siguiente función:
9957 void gtk_text_set_word_wrap( GtkText *text,
9961 Utilizando esta función podremos especificar que el <em>widget</em>
9962 texto debería cortar las líneas largas en los límites de las
9963 palabras. El argumento <tt/word_wrap/ es un valor TRUE o FALSE.
9965 <!-- ----------------------------------------------------------------- -->
9966 <sect1>Manipulación de texto
9968 El punto actual de inserción en un <em>widget</em> texto puede
9969 cambiarse utilizando
9971 void gtk_text_set_point( GtkText *text,
9975 donde <tt/index/ es la posición en la que poner el punto de inserción.
9977 Análogamente tenemos la función para obtener la posición del punto
9981 guint gtk_text_get_point( GtkText *text );
9984 Una función que es útil en combinación con las dos anteriores es
9987 guint gtk_text_get_length( GtkText *text );
9990 que devuelve la longitud actual del <em>widget</em> texto. La
9991 longitud es el número de caracteres que hay en el bloque de texto,
9992 incluyendo caracteres como el retorno de carro, que marca el final de
9995 Para insertar texto en la posición actual del cursor, tendrá que
9996 utilizar la función <tt/gtk_text_insert/, que nos permitirá
9997 especificar los colores de fondo y de la letra y un tipo de letra para
10001 void gtk_text_insert( GtkText *text,
10009 Pasar un valor <tt/NULL/ como el color de la letra (<tt/fore/), el
10010 color de fondo (<tt/back/) o el tipo de letra (<tt/font/) hará que
10011 se utilicen los valores que indiquen el estilo del <em>widget</em>.
10012 Utilizar un valor de <tt/-1/ para el parámetro <tt/length/ hará
10013 que se inserte todo el texto.
10015 El <em/widget/ texto es uno de los pocos de GTK que se redibuja
10016 a sí mismo dinámicamente, fuera de la función <tt/gtk_main/. Esto
10017 significa que todos los cambios en el contenido del <em/widget/ texto
10018 se manifestarán inmediatamente. Para permitirnos realizar varias
10019 actualizaciones del <em/widget/ de texto sin que se redibuje
10020 continuamente, podemos congelar el <em/widget/, lo que hará que pare
10021 momentaneamente de redibujarse a sí mismo cada vez que haya algún
10022 cambio. Podemos descongelarlo cuando hayamos acabado con nuestras
10025 Las siguientes dos funciones realizarán la acción de congelar y
10026 descongelar el <em/widget/:
10029 void gtk_text_freeze( GtkText *text );
10031 void gtk_text_thaw( GtkText *text );
10034 Se puede borrar el texto que se encuentra en el punto actual de
10035 inserción del <em/widget/ de texto mediante dos funciones. El valor
10036 devuelto es TRUE o FALSE en función del éxito de la operación.
10039 gint gtk_text_backward_delete( GtkText *text,
10042 gint gtk_text_forward_delete ( GtkText *text,
10046 Si quiere recuperar el contenido del <em/widget/ de texto, entonces
10047 la macro <tt/GTK_TEXT_INDEX(t, index)/ le permitirá obtener el
10048 carácter que se encuentra en la posición <tt/index/ del <em/widget/
10051 Para obtener mayores bloques de texto, podemos utilizar la función
10054 gchar *gtk_editable_get_chars( GtkEditable *editable,
10059 Esta es una función de la clase padre del <em/widget/ texto. Un valor
10060 de -1 en <tt/end_pos/ significa el final del texto. El índice del
10061 texto empieza en 0.
10063 La función reserva un espacio de memoria para el bloque de texto,
10064 por lo que no debe olvidarse de liberarlo con una llamada a
10065 <tt/g_free/ cuando haya acabado el bloque.
10067 <!-- ----------------------------------------------------------------- -->
10068 <sect1>Atajos por teclado
10070 El <em/widget/ texto tiene ciertos atajos de teclado preinstalados
10071 para las funciones de edición estándar, movimiento y selección. Pueden
10072 utilizarse mediante combinaciones de las teclas Control y Alt.
10074 Además, si se mantiene apretada la tecla de Control y se utilizan las
10075 teclas de movimiento, el cursor se moverá por palabras en lugar de por
10076 caracteres. Manteniendo apretada la tecla Shift, las teclas de movimiento
10077 harán que se extienda la selección.
10079 <sect2>Atajos para el movimiento
10082 <item> Ctrl-A Principio de línea
10083 <item> Ctrl-E Final de línea
10084 <item> Ctrl-N Línea siguiente
10085 <item> Ctrl-P Línea anterior
10086 <item> Ctrl-B Retrasarse un carácter
10087 <item> Ctrl-F Adelantarse un carácter
10088 <item> Alt-B Retrasarse una palabra
10089 <item> Alt-F Adelantarse una palabra
10092 <sect2>Atajos para la edición
10095 <item> Ctrl-H Borrar el carácter anterior (Backspace)
10096 <item> Ctrl-D Borrar el carácter siguiente (Suprimir)
10097 <item> Ctrl-W Borrar la palabra anterior
10098 <item> Alt-D Borrar la palabra siguiente
10099 <item> Ctrl-K Borrar hasta el fin de la línea
10100 <item> Ctrl-U Borrar la línea
10103 <sect2>Atajos de selección
10106 <item> Ctrl-X Cortar al portapapeles
10107 <item> Ctrl-C Copiar al portapapeles
10108 <item> Ctrl-V Pegar desde el portapapeles
10111 <!-- ----------------------------------------------------------------- -->
10112 <sect1>Un ejemplo de GtkText
10115 /* principio del ejemplo text text.c */
10120 #include <gtk/gtk.h>
10122 void text_toggle_editable (GtkWidget *checkbutton,
10125 gtk_text_set_editable(GTK_TEXT(text),
10126 GTK_TOGGLE_BUTTON(checkbutton)->active);
10129 void text_toggle_word_wrap (GtkWidget *checkbutton,
10132 gtk_text_set_word_wrap(GTK_TEXT(text),
10133 GTK_TOGGLE_BUTTON(checkbutton)->active);
10136 void close_application( GtkWidget *widget, gpointer data )
10141 int main (int argc, char *argv[])
10143 GtkWidget *ventana;
10149 GtkWidget *separator;
10151 GtkWidget *vscrollbar;
10155 GdkFont *fixed_font;
10159 gtk_init (&argc, &argv);
10161 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10162 gtk_widget_set_usize (ventana, 600, 500);
10163 gtk_window_set_policy (GTK_WINDOW(ventana), TRUE, TRUE, FALSE);
10164 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
10165 GTK_SIGNAL_FUNC(close_application),
10167 gtk_window_set_title (GTK_WINDOW (ventana), "Text Widget Example");
10168 gtk_container_border_width (GTK_CONTAINER (ventana), 0);
10171 caja1 = gtk_vbox_new (FALSE, 0);
10172 gtk_container_add (GTK_CONTAINER (ventana), caja1);
10173 gtk_widget_show (caja1);
10176 caja2 = gtk_vbox_new (FALSE, 10);
10177 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
10178 gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
10179 gtk_widget_show (caja2);
10182 table = gtk_table_new (2, 2, FALSE);
10183 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
10184 gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
10185 gtk_box_pack_start (GTK_BOX (caja2), table, TRUE, TRUE, 0);
10186 gtk_widget_show (table);
10188 /* Crear el widget GtkText */
10189 text = gtk_text_new (NULL, NULL);
10190 gtk_text_set_editable (GTK_TEXT (text), TRUE);
10191 gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
10192 GTK_EXPAND | GTK_SHRINK | GTK_FILL,
10193 GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10194 gtk_widget_show (text);
10196 /* Añadir una barra de desplazamiento vertical al widget GtkText */
10197 vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
10198 gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
10199 GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
10200 gtk_widget_show (vscrollbar);
10202 /* Obtener el mapa de colores del sistema y conseguir el color rojo */
10203 cmap = gdk_colormap_get_system();
10204 colour.red = 0xffff;
10207 if (!gdk_color_alloc(cmap, &colour)) {
10208 g_error("couldn't allocate colour");
10211 /* Cargar un fuente de tamaño fijo */
10212 fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
10214 /* Al enviar la señal relize a un widget se crea una ventana para el
10215 * mismo, y nos permite insertar texto */
10216 gtk_widget_realize (text);
10218 /* Congela el widget text, lo que nos permite hacer varias
10219 * actualizaciones */
10220 gtk_text_freeze (GTK_TEXT (text));
10222 /* Insertamos algún texto coloreado */
10223 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10225 gtk_text_insert (GTK_TEXT (text), NULL, &colour, NULL,
10227 gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
10228 "text and different ", -1);
10229 gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
10232 /* Cargamos el fichero text.c en la ventana de texto */
10234 infile = fopen("text.c", "r");
10242 nchars = fread(buffer, 1, 1024, infile);
10243 gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
10244 NULL, buffer, nchars);
10253 /* Descongelamos el widget text, permitiéndonos ver todos los
10255 gtk_text_thaw (GTK_TEXT (text));
10257 hbox = gtk_hbutton_box_new ();
10258 gtk_box_pack_start (GTK_BOX (caja2), hbox, FALSE, FALSE, 0);
10259 gtk_widget_show (hbox);
10261 check = gtk_check_button_new_with_label("Editable");
10262 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
10263 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10264 GTK_SIGNAL_FUNC(text_toggle_editable), text);
10265 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
10266 gtk_widget_show (check);
10267 check = gtk_check_button_new_with_label("Wrap Words");
10268 gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
10269 gtk_signal_connect (GTK_OBJECT(check), "toggled",
10270 GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
10271 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE);
10272 gtk_widget_show (check);
10274 separator = gtk_hseparator_new ();
10275 gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 0);
10276 gtk_widget_show (separator);
10278 caja2 = gtk_vbox_new (FALSE, 10);
10279 gtk_container_border_width (GTK_CONTAINER (caja2), 10);
10280 gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, TRUE, 0);
10281 gtk_widget_show (caja2);
10283 boton = gtk_button_new_with_label ("close");
10284 gtk_signal_connect (GTK_OBJECT (boton), "clicked",
10285 GTK_SIGNAL_FUNC(close_application),
10287 gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
10288 GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
10289 gtk_widget_grab_default (boton);
10290 gtk_widget_show (boton);
10292 gtk_widget_show (ventana);
10298 /* fin del ejemplo */
10301 <!-- ***************************************************************** -->
10302 <sect> Los <em>widgets</em> no documentados
10303 <!-- ***************************************************************** -->
10305 ¡Todos ellos necesitan de gente que los documente! :) Por favor,
10306 considere el contribuir a nuestro tutorial.
10308 Si debe utilizar uno de estos <em/widgets/, que permanecen no
10309 documentados, le sugiero que le eche un vistazo a su fichero de
10310 cabecera respectivo en la distribución GTK. Los nombre de las
10311 funciones GTK son muy descriptivos. Una vez haya comprendido como
10312 funcionan las cosas, no le será difícil ver como hay que utilizar un
10313 <em/widget/ simplemente mirando su declaración de funciones. Con esto,
10314 y unos cuántos ejemplos del código de otros, no debería tener
10317 Cuando haya comprendido todas las funciones de un nuevo <em/widget/
10318 no documentado, por favor considere el hecho de escribir un tutorial
10319 para él, para que así otros se puedan beneficiar del tiempo que usted
10323 <!-- ----------------------------------------------------------------- -->
10326 <!-- ----------------------------------------------------------------- -->
10329 <!-- ----------------------------------------------------------------- -->
10332 <!-- ----------------------------------------------------------------- -->
10333 <sect1> Drawing Area
10335 <!-- ----------------------------------------------------------------- -->
10336 <sect1> Font Selection Dialog
10338 <!-- ----------------------------------------------------------------- -->
10339 <sect1> Gamma Curve
10341 <!-- ----------------------------------------------------------------- -->
10344 <!-- ----------------------------------------------------------------- -->
10347 <!-- ----------------------------------------------------------------- -->
10348 <sect1> Plugs and Sockets
10350 <!-- ----------------------------------------------------------------- -->
10356 (This may need to be rewritten to follow the style of the rest of the tutorial)
10360 Previews serve a number of purposes in GIMP/GTK. The most important one is
10361 this. High quality images may take up to tens of megabytes of memory - easy!
10362 Any operation on an image that big is bound to take a long time. If it takes
10363 you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
10364 you make an error) to choose the desired modification, it make take you
10365 literally hours to make the right one - if you don't run out of memory
10366 first. People who have spent hours in color darkrooms know the feeling.
10367 Previews to the rescue!
10369 But the annoyance of the delay is not the only issue. Oftentimes it is
10370 helpful to compare the Before and After versions side-by-side or at least
10371 back-to-back. If you're working with big images and 10 second delays,
10372 obtaining the Before and After impressions is, to say the least, difficult.
10373 For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
10374 out for most people, while back-to-back is more like back-to-1001, 1002,
10375 ..., 1010-back! Previews to the rescue!
10377 But there's more. Previews allow for side-by-side pre-previews. In other
10378 words, you write a plug-in (e.g. the filterpack simulation) which would have
10379 a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
10380 An approach like this acts as a sort of a preview palette and is very
10381 effective for subtle changes. Let's go previews!
10383 There's more. For certain plug-ins real-time image-specific human
10384 intervention maybe necessary. In the SuperNova plug-in, for example, the
10385 user is asked to enter the coordinates of the center of the future
10386 supernova. The easiest way to do this, really, is to present the user with a
10387 preview and ask him to interactively select the spot. Let's go previews!
10389 Finally, a couple of misc uses. One can use previews even when not working
10390 with big images. For example, they are useful when rendering complicated
10391 patterns. (Just check out the venerable Diffraction plug-in + many other
10392 ones!) As another example, take a look at the colormap rotation plug-in
10393 (work in progress). You can also use previews for little logos inside you
10394 plug-ins and even for an image of yourself, The Author. Let's go previews!
10396 When Not to Use Previews
10398 Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
10399 previews only for rendered images!
10403 You can stick a preview into just about anything. In a vbox, an hbox, a
10404 table, a button, etc. But they look their best in tight frames around them.
10405 Previews by themselves do not have borders and look flat without them. (Of
10406 course, if the flat look is what you want...) Tight frames provide the
10411 Previews in many ways are like any other widgets in GTK (whatever that
10412 means) except they possess an additional feature: they need to be filled with
10413 some sort of an image! First, we will deal exclusively with the GTK aspect
10414 of previews and then we'll discuss how to fill them.
10416 GtkWidget *preview!
10420 /* Create a preview widget,
10421 set its size, an show it */
10422 GtkWidget *preview;
10423 preview=gtk_preview_new(GTK_PREVIEW_COLOR)
10425 GTK_PREVIEW_GRAYSCALE);*/
10426 gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
10427 gtk_widget_show(preview);
10428 my_preview_rendering_function(preview);
10430 Oh yeah, like I said, previews look good inside frames, so how about:
10432 GtkWidget *create_a_preview(int Width,
10436 GtkWidget *preview;
10439 frame = gtk_frame_new(NULL);
10440 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
10441 gtk_container_set_border_width (GTK_CONTAINER(frame),0);
10442 gtk_widget_show(frame);
10444 preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
10445 :GTK_PREVIEW_GRAYSCALE);
10446 gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
10447 gtk_container_add(GTK_CONTAINER(frame),preview);
10448 gtk_widget_show(preview);
10450 my_preview_rendering_function(preview);
10454 That's my basic preview. This routine returns the "parent" frame so you can
10455 place it somewhere else in your interface. Of course, you can pass the
10456 parent frame to this routine as a parameter. In many situations, however,
10457 the contents of the preview are changed continually by your application. In
10458 this case you may want to pass a pointer to the preview to a
10459 "create_a_preview()" and thus have control of it later.
10461 One more important note that may one day save you a lot of time. Sometimes
10462 it is desirable to label you preview. For example, you may label the preview
10463 containing the original image as "Original" and the one containing the
10464 modified image as "Less Original". It might occur to you to pack the
10465 preview along with the appropriate label into a vbox. The unexpected caveat
10466 is that if the label is wider than the preview (which may happen for a
10467 variety of reasons unforseeable to you, from the dynamic decision on the
10468 size of the preview to the size of the font) the frame expands and no longer
10469 fits tightly over the preview. The same problem can probably arise in other
10470 situations as well.
10474 The solution is to place the preview and the label into a 2x1 table and by
10475 attaching them with the following parameters (this is one possible variations
10476 of course. The key is no GTK_FILL in the second attachment):
10478 gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
10480 GTK_EXPAND|GTK_FILL,
10482 gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
10488 And here's the result:
10494 Making a preview clickable is achieved most easily by placing it in a
10495 boton. It also adds a nice border around the preview and you may not even
10496 need to place it in a frame. See the Filter Pack Simulation plug-in for an
10499 This is pretty much it as far as GTK is concerned.
10501 Filling In a Preview
10503 In order to familiarize ourselves with the basics of filling in previews,
10504 let's create the following pattern (contrived by trial and error):
10509 my_preview_rendering_function(GtkWidget *preview)
10512 #define HALF (SIZE/2)
10514 guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
10515 gint i, j; /* Coordinates */
10516 double r, alpha, x, y;
10518 if (preview==NULL) return; /* I usually add this when I want */
10519 /* to avoid silly crashes. You */
10520 /* should probably make sure that */
10521 /* everything has been nicely */
10523 for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape? */
10524 /* glib.h contains ABS(x). */
10525 row[i*3+0] = sqrt(1-r)*255; /* Define Red */
10526 row[i*3+1] = 128; /* Define Green */
10527 row[i*3+2] = 224; /* Define Blue */
10528 } /* "+0" is for alignment! */
10530 row[i*3+0] = r*255;
10531 row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
10532 row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
10535 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
10536 /* Insert "row" into "preview" starting at the point with */
10537 /* coordinates (0,j) first column, j_th row extending SIZE */
10538 /* pixels to the right */
10541 free(row); /* save some space */
10542 gtk_widget_draw(preview,NULL); /* what does this do? */
10543 gdk_flush(); /* or this? */
10546 Non-GIMP users can have probably seen enough to do a lot of things already.
10547 For the GIMP users I have a few pointers to add.
10551 It is probably wise to keep a reduced version of the image around with just
10552 enough pixels to fill the preview. This is done by selecting every n'th
10553 pixel where n is the ratio of the size of the image to the size of the
10554 preview. All further operations (including filling in the previews) are then
10555 performed on the reduced number of pixels only. The following is my
10556 implementation of reducing the image. (Keep in mind that I've had only basic
10559 (UNTESTED CODE ALERT!!!)
10571 SELECTION_IN_CONTEXT,
10575 ReducedImage *Reduce_The_Image(GDrawable *drawable,
10580 /* This function reduced the image down to the the selected preview size */
10581 /* The preview size is determine by LongerSize, i.e. the greater of the */
10582 /* two dimensions. Works for RGB images only! */
10583 gint RH, RW; /* Reduced height and reduced width */
10584 gint width, height; /* Width and Height of the area being reduced */
10585 gint bytes=drawable->bpp;
10586 ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
10588 guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
10589 gint i, j, whichcol, whichrow, x1, x2, y1, y2;
10590 GPixelRgn srcPR, srcMask;
10591 gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire */
10594 gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
10597 /* If there's a SELECTION, we got its bounds!)
10599 if (width != drawable->width && height != drawable->height)
10600 NoSelectionMade=FALSE;
10601 /* Become aware of whether the user has made an active selection */
10602 /* This will become important later, when creating a reduced mask. */
10604 /* If we want to preview the entire image, overrule the above! */
10605 /* Of course, if no selection has been made, this does nothing! */
10606 if (Selection==ENTIRE_IMAGE) {
10608 x2=drawable->width;
10610 y2=drawable->height;
10613 /* If we want to preview a selection with some surrounding area we */
10614 /* have to expand it a little bit. Consider it a bit of a riddle. */
10615 if (Selection==SELECTION_IN_CONTEXT) {
10616 x1=MAX(0, x1-width/2.0);
10617 x2=MIN(drawable->width, x2+width/2.0);
10618 y1=MAX(0, y1-height/2.0);
10619 y2=MIN(drawable->height, y2+height/2.0);
10622 /* How we can determine the width and the height of the area being */
10627 /* The lines below determine which dimension is to be the longer */
10628 /* side. The idea borrowed from the supernova plug-in. I suspect I */
10629 /* could've thought of it myself, but the truth must be told. */
10630 /* Plagiarism stinks! */
10631 if (width>height) {
10633 RH=(float) height * (float) LongerSize/ (float) width;
10637 RW=(float)width * (float) LongerSize/ (float) height;
10640 /* The entire image is stretched into a string! */
10641 tempRGB = (guchar *) malloc(RW*RH*bytes);
10642 tempmask = (guchar *) malloc(RW*RH);
10644 gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height,
10646 gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height,
10649 /* Grab enough to save a row of image and a row of mask. */
10650 src_row = (guchar *) malloc (width*bytes);
10651 src_mask_row = (guchar *) malloc (width);
10653 for (i=0; i < RH; i++) {
10654 whichrow=(float)i*(float)height/(float)RH;
10655 gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
10656 gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
10658 for (j=0; j < RW; j++) {
10659 whichcol=(float)j*(float)width/(float)RW;
10661 /* No selection made = each point is completely selected! */
10662 if (NoSelectionMade)
10663 tempmask[i*RW+j]=255;
10665 tempmask[i*RW+j]=src_mask_row[whichcol];
10667 /* Add the row to the one long string which now contains the image! */
10668 tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
10669 tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
10670 tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
10672 /* Hold on to the alpha as well */
10674 tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
10681 temp->mask=tempmask;
10685 The following is a preview function which used the same ReducedImage type!
10686 Note that it uses fakes transparency (if one is present by means of
10687 fake_transparency which is defined as follows:
10689 gint fake_transparency(gint i, gint j)
10691 if ( ((i%20)- 10) * ((j%20)- 10)>0 )
10697 Now here's the preview function:
10700 my_preview_render_function(GtkWidget *preview,
10704 gint Inten, bytes=drawable->bpp;
10707 gint RW=reduced->width;
10708 gint RH=reduced->height;
10709 guchar *row=malloc(bytes*RW);;
10712 for (i=0; i < RH; i++) {
10713 for (j=0; j < RW; j++) {
10715 row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
10716 row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
10717 row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
10720 for (k=0; k<3; k++) {
10721 float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
10722 row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
10725 gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
10729 gtk_widget_draw(preview,NULL);
10733 Applicable Routines
10735 guint gtk_preview_get_type (void);
10737 void gtk_preview_uninit (void);
10739 GtkWidget* gtk_preview_new (GtkPreviewType type);
10740 /* Described above */
10741 void gtk_preview_size (GtkPreview *preview,
10744 /* Allows you to resize an existing preview. */
10745 /* Apparently there's a bug in GTK which makes */
10746 /* this process messy. A way to clean up a mess */
10747 /* is to manually resize the window containing */
10748 /* the preview after resizing the preview. */
10750 void gtk_preview_put (GtkPreview *preview,
10751 GdkWindow *ventana,
10761 void gtk_preview_put_row (GtkPreview *preview,
10769 void gtk_preview_draw_row (GtkPreview *preview,
10774 /* Described in the text */
10776 void gtk_preview_set_expand (GtkPreview *preview,
10780 /* No clue for any of the below but */
10781 /* should be standard for most widgets */
10782 void gtk_preview_set_gamma (double gamma);
10783 void gtk_preview_set_color_cube (guint nred_shades,
10784 guint ngreen_shades,
10785 guint nblue_shades,
10786 guint ngray_shades);
10787 void gtk_preview_set_install_cmap (gint install_cmap);
10788 void gtk_preview_set_reserved (gint nreserved);
10789 GdkVisual* gtk_preview_get_visual (void);
10790 GdkColormap* gtk_preview_get_cmap (void);
10791 GtkPreviewInfo* gtk_preview_get_info (void);
10799 <!-- ***************************************************************** -->
10800 <sect>Estableciendo los atributos de un <em/widget/<label id="sec_setting_widget_attributes">
10801 <!-- ***************************************************************** -->
10803 En este capítulo se describen las funciones utilizadas para manejar los
10804 <em/widgets/. Pueden utilizarse para establecer el estilo, relleno,
10807 (Puede que deba hacer una sección completa para los aceleradores.)
10810 void gtk_widget_install_accelerator( GtkWidget *widget,
10811 GtkAcceleratorTable *table,
10812 gchar *signal_name,
10814 guint8 modifiers );
10816 void gtk_widget_remove_accelerator ( GtkWidget *widget,
10817 GtkAcceleratorTable *table,
10818 gchar *signal_name);
10820 void gtk_widget_activate( GtkWidget *widget );
10822 void gtk_widget_set_name( GtkWidget *widget,
10825 gchar *gtk_widget_get_name( GtkWidget *widget );
10827 void gtk_widget_set_sensitive( GtkWidget *widget,
10830 void gtk_widget_set_style( GtkWidget *widget,
10833 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
10835 GtkStyle *gtk_widget_get_default_style( void );
10837 void gtk_widget_set_uposition( GtkWidget *widget,
10841 void gtk_widget_set_usize( GtkWidget *widget,
10845 void gtk_widget_grab_focus( GtkWidget *widget );
10847 void gtk_widget_show( GtkWidget *widget );
10849 void gtk_widget_hide( GtkWidget *widget );
10852 <!-- ***************************************************************** -->
10853 <sect>Tiempos de espera, ES (<em/IO/) y funciones ociosas (<em/idle/)<label id="sec_timeouts">
10854 <!-- ***************************************************************** -->
10856 <!-- ----------------------------------------------------------------- -->
10857 <sect1>Tiempos de espera
10859 Puede que se esté preguntando como hacer que GTK haga algo útil
10860 cuando se encuentra en <tt/gtk_main/. Bien, tiene varias
10861 opciones. Utilizando las rutinas siguientes puede crear una función
10862 a la que se llamará cada <tt/interval/ milisegundos.
10865 gint gtk_timeout_add( guint32 interval,
10866 GtkFunction function,
10870 El primer argumento es el número de milisegundos que habrá entre dos
10871 llamadas a su función. El segundo argumento es la función a la que
10872 desea llamar, y el tercero, los datos que le pasará a ésta función.
10873 El valor devuelto es un «identificador» (un valor entero) que puede
10874 utilizar para detener las llamadas haciendo:
10877 void gtk_timeout_remove( gint tag );
10880 También puede hacer que cesen las llamadas a la función haciendo que
10881 la misma devuelva cero o FALSE. Obviamente esto significa que si
10882 quiere que se continue llamando a su función, deberá devolver un valor
10883 distinto de cero, es decir TRUE.
10885 La declaración de su función debería ser algo como:
10888 gint timeout_callback( gpointer data );
10891 <!-- ----------------------------------------------------------------- -->
10892 <sect1>Monitorizando la ES
10894 Otra característica divertida de GTK, es la habilidad que tiene de
10895 comprobar datos por usted en un descriptor de fichero (tal y como
10896 se devuelven por <tt/open(2)/ o <tt/socket(2)/). Esto es especialmente
10897 útil para las aplicaciones de red. La función:
10900 gint gdk_input_add( gint source,
10901 GdkInputCondition condition,
10902 GdkInputFunction function,
10906 Donde el primer argumento es el descriptor de fichero que desea vigilar,
10907 y el segundo especifica que es lo que quiere que GDK busque. Puede ser uno
10911 <item>GDK_INPUT_READ - Llama a su función cuando hay datos listos para
10912 leerse del fichero.
10914 <item>GDK_INPUT_WRITE - Llama a su función cuando el descriptor del
10915 fichero está listo para la escritura.
10918 Tal y como se habrá imaginado, el tercer argumento es la función a la
10919 que desea que se llame cuando se den las condiciones anteriores, y el
10920 cuarto son los datos que se le pasarán a ésta función.
10922 El valor devuelto es un identificador que puede utilizarse para que GDK
10923 pare de vigilar ese fichero, utilizando la función
10926 void gdk_input_remove( gint tag );
10929 La función a la que quiere que se llame deberá declararse así:
10932 void input_callback( gpointer data,
10934 GdkInputCondition condition );
10937 Donde <tt/source/ y <tt/condition/ están especificados más arriba.
10939 <!-- ----------------------------------------------------------------- -->
10940 <sect1>Funciones ociosas
10942 <!-- Need to check on idle priorities - TRG -->
10943 ¿Qué le parece si tuviese una función a la que se llamase cuando
10947 gint gtk_idle_add( GtkFunction function,
10951 Esto hace que GTK llame a la función especificada cuando no ocurra
10955 void gtk_idle_remove( gint tag );
10958 No voy a explicar el significado de los argumentos ya que se parece
10959 mucho a los que he explicado más arriba. La función a la que se apunta
10960 mediante el primer argumento de <tt/gtk_idle_add/ será a la que se
10961 llame cuando llegue el momento. Como antes, si devuelve FALSE hará que
10962 cese de llamarse a la función.
10964 <!-- ***************************************************************** -->
10965 <sect>Manejo avanzado de eventos y señales<label id="sec_Adv_Events_and_Signals">
10966 <!-- ***************************************************************** -->
10968 <!-- ----------------------------------------------------------------- -->
10969 <sect1>Funciones señal
10971 <!-- ----------------------------------------------------------------- -->
10972 <sect2>Conectando y desconectando los manejadores de señal
10976 guint gtk_signal_connect( GtkObject *object,
10978 GtkSignalFunc func,
10979 gpointer func_data );
10981 guint gtk_signal_connect_after( GtkObject *object,
10983 GtkSignalFunc func,
10984 gpointer func_data );
10986 guint gtk_signal_connect_object( GtkObject *object,
10988 GtkSignalFunc func,
10989 GtkObject *slot_object );
10991 guint gtk_signal_connect_object_after( GtkObject *object,
10993 GtkSignalFunc func,
10994 GtkObject *slot_object );
10996 guint gtk_signal_connect_full( GtkObject *object,
10998 GtkSignalFunc func,
10999 GtkCallbackMarshal marshal,
11001 GtkDestroyNotify destroy_func,
11002 gint object_signal,
11005 guint gtk_signal_connect_interp( GtkObject *object,
11007 GtkCallbackMarshal func,
11009 GtkDestroyNotify destroy_func,
11012 void gtk_signal_connect_object_while_alive( GtkObject *object,
11013 const gchar *signal,
11014 GtkSignalFunc func,
11015 GtkObject *alive_object );
11017 void gtk_signal_connect_while_alive( GtkObject *object,
11018 const gchar *signal,
11019 GtkSignalFunc func,
11020 gpointer func_data,
11021 GtkObject *alive_object );
11023 void gtk_signal_disconnect( GtkObject *object,
11024 guint handler_id );
11026 void gtk_signal_disconnect_by_func( GtkObject *object,
11027 GtkSignalFunc func,
11031 <!-- ----------------------------------------------------------------- -->
11032 <sect2>Bloqueando y desbloqueando los manejadores de señal
11035 void gtk_signal_handler_block( GtkObject *object,
11038 void gtk_signal_handler_block_by_func( GtkObject *object,
11039 GtkSignalFunc func,
11042 void gtk_signal_handler_block_by_data( GtkObject *object,
11045 void gtk_signal_handler_unblock( GtkObject *object,
11046 guint handler_id );
11048 void gtk_signal_handler_unblock_by_func( GtkObject *object,
11049 GtkSignalFunc func,
11052 void gtk_signal_handler_unblock_by_data( GtkObject *object,
11056 <!-- ----------------------------------------------------------------- -->
11057 <sect2>Emitiendo y deteniendo señales
11060 void gtk_signal_emit( GtkObject *object,
11064 void gtk_signal_emit_by_name( GtkObject *object,
11068 void gtk_signal_emitv( GtkObject *object,
11072 void gtk_signal_emitv_by_name( GtkObject *object,
11076 guint gtk_signal_n_emissions( GtkObject *object,
11079 guint gtk_signal_n_emissions_by_name( GtkObject *object,
11080 const gchar *name );
11082 void gtk_signal_emit_stop( GtkObject *object,
11085 void gtk_signal_emit_stop_by_name( GtkObject *object,
11086 const gchar *name );
11089 <!-- ----------------------------------------------------------------- -->
11090 <sect1>Emisión y propagación de señales
11092 La emisión de señales es el proceso mediante el cual GTK+ ejecuta
11093 todos los manejadores de un objeto y una señal en especial.
11095 Primero, observe que el valor devuelto por la emisión de una
11096 señal es el mismo que el valor devuelto por el <em>último</em>
11097 manipulador ejecutado. Ya que las señales de los eventos son todas
11098 del tipo GTK_RUN_LAST, el manejador por defecto (proporcionado por
11099 GTK+) será de este tipo, a menos que lo conecte con
11100 <tt/gtk_signal_connect_after()/.
11102 La forma en que se maneja un evento (digamos GTK_BUTTON_PRESS), es la
11106 <item>Empieza con el <em>widget</em> donde ocurrió el evento.
11108 <item>Emite la señal genérica <tt/event/. Si esta señal devuelve un
11109 valor TRUE, detiene todo el proceso.
11111 <item>En caso contrario, emite una señal especifica,
11112 «button_press_event» en nuestro caso. Si ésta devuelve TRUE, detiene
11115 <item>En caso contrario, va al <em>widget</em> padre y repite los
11118 <item>Continua hasta que algún manejador de señal devuelva TRUE, o
11119 hasta que se llegue al <em>widget</em> de más alto nivel.
11122 Algunas consecuencias son:
11124 <item>El valor que devuelva su manejador no tendrá ningún efecto si
11125 hay un manejador por defecto, a menos que lo conecte mediante
11126 <tt/gtk_signal_connect_after()/.
11128 <item>Para evitar que el manejador por defecto se ejecute, necesita
11129 conectar mediante <tt/gtk_signal_connect()/ y utilizar
11130 <tt/gtk_signal_emit_stop_by_name()/ - el valor devuelto sólo se ve
11131 afectado si la señal se propaga, y no sólo por el hecho de emitirse.
11134 <!-- ***************************************************************** -->
11135 <sect>Manejando selecciones
11136 <!-- ***************************************************************** -->
11138 <!-- ----------------------------------------------------------------- -->
11141 Un tipo de comunicación entre procesos que se puede utilizar con GTK
11142 son las <em/selecciones/. Una selección identifica un conjunto de
11143 datos, por ejemplo, un trozo de texto, seleccionado por el usuario de
11144 alguna manera, por ejemplo, cogiéndolo con el ratón. Sólo una
11145 aplicación en un <em/display/ (la <em>propietaria</em>) puede tener
11146 una selección en particular en un momento dado, por lo que cuando una
11147 aplicación pide una selección, el propietario previo debe indicar al
11148 usuario que la selección ya no es válida. Otras aplicaciones pueden
11149 pedir el contenido de la selección de diferentes formas, llamadas
11150 <em/objetivos/. Puede haber cualquier número de selecciones, pero la
11151 mayoría de las aplicacion X sólo pueden manejar una, la <em/selección
11154 En muchos casos, no es necesario para una aplicación GTK tratar por
11155 sí misma con las selecciones. Los <em/widgets/ estándar, como el
11156 <em/widget/ Entry, ya tienen la posibilidad de crear la selección
11157 cuando sea necesario (p.e., cuando el usuario pase el ratón sobre el
11158 texto manteniendo el botón derecho del ratón pulsado), y de recoger
11159 los contenidos de la selección propiedad de otro <em/widget/, o de
11160 otra aplicación (p.e., cuando el usuario pulsa el segundo botón del
11161 ratón). Sin embargo, pueden haber casos en los que quiera darle a
11162 otros <em/widgets/ la posibilidad de proporcionar la selección, o
11163 puede que quiera recuperar objetivos que no estén admitidos por
11166 Un concepto fundamental que es necesario para comprender el manejo de
11167 la selección es el de <em>átomo</em>. Un átomo es un entero que
11168 identifica de una manera unívoca una cadena (en un cierto
11169 <em/display/). Ciertos átomos están predefinidos por el servidor X, y
11170 en algunos casos hay constantes en <tt>gtk.h</tt> que corresponden a
11171 estos átomos. Por ejemplo la constante <tt>GDK_PRIMARY_SELECTION</tt>
11172 corresponde a la cadena «PRIMARY». En otros casos, debería utilizar
11173 las funciones <tt>gdk_atom_intern()</tt>, para obtener el átomo
11174 correspondiente a una cadena, y <tt>gdk_atom_name()</tt>, para obtener
11175 el nombre de un átomo. Ambas, selecciones y objetivos, están
11176 identificados por átomos.
11178 <!-- ----------------------------------------------------------------- -->
11179 <sect1> Recuperando la selección
11181 Recuperar la selección es un proceso asíncrono. Para comenzar el
11182 proceso, deberá llamar a:
11185 gint gtk_selection_convert( GtkWidget *widget,
11191 Este proceso <em/convierte/ la selección en la forma especificada por
11192 <tt/target/. Si es posible, el campo <tt/time/ debe ser el tiempo
11193 desde que el evento lanzó la selección. Esto ayuda a asegurarse de que
11194 los eventos ocurran en el orden en que el usuario los ha pedido. Sin
11195 embargo, si no está disponible (por ejemplo, si se empezó la
11196 conversión por una señal de «pulsación»), entonces puede utilizar la
11197 constante <tt>GDK_CURRENT_TIME</tt>.
11199 Cuando el propietario de la selección responda a la petición, se
11200 enviará una señal «selection_received» a su aplicación. El manejador
11201 de esta señal recibe un puntero a una estructura
11202 <tt>GtkSelectionData</tt>, que se define como:
11205 struct _GtkSelectionData
11216 <tt>selection</tt> y <tt>target</tt> son los valores que dió en su
11217 llamada a <tt>gtk_selection_convert()</tt>. <tt>type</tt> es un átomo
11218 que identifica el tipo de datos devueltos por el propietario de la
11219 selección. Algunos valores posibles son «STRING», un cadena de
11220 caracteres latin-1, «ATOM», una serie de átomos, «INTEGER», un
11221 entero, etc. Muchos objetivos sólo pueden devolver un
11222 tipo. <tt/format/ da la longitud de las unidades (por ejemplo
11223 caracteres) en bits. Normalmente, no tiene porque preocuparse de todo
11224 esto cuando recibe datos. <tt/data/ es un puntero a los datos
11225 devueltos, y <tt/length/ da la longitud de los datos devueltos, en
11226 bytes. Si <tt/length/ es negativo, es que a ocurrido un error y no se
11227 puede obtener la selección. Esto podría ocurrir si no hay ninguna
11228 aplicación que sea la propietaria de la selección, o si pide un
11229 objetivo que la aplicación no admite. Actualmente se garantiza que el
11230 búfer tendrá un byte más que <tt/length/; el byte extra siempre será
11231 cero, por lo que no es necesario hacer una copia de las cadenas sólo
11232 para añadirles un carácter nulo al final.
11234 En el siguiente ejemplo, recuperamos el objetivo especial «TARGETS»,
11235 que es una lista de todos los objetivos en los que se puede convertir
11239 /* principio del ejemplo selection gettargets.c */
11241 #include <gtk/gtk.h>
11243 void selection_received (GtkWidget *widget,
11244 GtkSelectionData *selection_data,
11247 /* Manejador de señal invocado cuando el usuario pulsa en el botón
11250 get_targets (GtkWidget *widget, gpointer data)
11252 static GdkAtom targets_atom = GDK_NONE;
11254 /* Obtener el atom correpondiente a la cadena "TARGETS" */
11255 if (targets_atom == GDK_NONE)
11256 targets_atom = gdk_atom_intern ("TARGETS", FALSE);
11258 /* Y pide el objetivo "TARGETS" de la selección primaria */
11259 gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
11263 /* Manipulador de señal llamado cuando el propietario de la señal
11264 * devuelve los datos */
11266 selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
11273 /* **** IMPORTANTE **** Comprobar si se da la recuperación de los
11275 if (selection_data->length < 0)
11277 g_print ("Selection retrieval failed\n");
11280 /* Asegurarse de que obtenemos los datos de la forma esperada */
11281 if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
11283 g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
11287 /* Imprimir los atoms que hemos recibido */
11288 atoms = (GdkAtom *)selection_data->data;
11291 for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
11294 name = gdk_atom_name (atoms[i]);
11296 g_print ("%s\n",name);
11298 g_print ("(bad atom)\n");
11305 main (int argc, char *argv[])
11307 GtkWidget *ventana;
11310 gtk_init (&argc, &argv);
11312 /* Crear la ventana superior */
11314 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11315 gtk_window_set_title (GTK_WINDOW (ventana), "Event Box");
11316 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
11318 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
11319 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11321 /* Crear un botón que el usuario puede pulsar para obtener los
11324 boton = gtk_button_new_with_label ("Get Targets");
11325 gtk_container_add (GTK_CONTAINER (ventana), boton);
11327 gtk_signal_connect (GTK_OBJECT(boton), "clicked",
11328 GTK_SIGNAL_FUNC (get_targets), NULL);
11329 gtk_signal_connect (GTK_OBJECT(boton), "selection_received",
11330 GTK_SIGNAL_FUNC (selection_received), NULL);
11332 gtk_widget_show (boton);
11333 gtk_widget_show (ventana);
11339 /* fin del ejemplo */
11342 <!-- ----------------------------------------------------------------- -->
11343 <sect1> Proporcionando la selección
11345 Proporcionar la selección es un poco más complicado. Debe registrar
11346 los manejadores a los que se llamarán cuando se le pida la
11347 selección. Por cada par selección/objetivo que quiera manejar, deberá
11348 hacer una llamada a:
11351 void gtk_selection_add_handler( GtkWidget *widget,
11354 GtkSelectionFunction function,
11355 GtkRemoveFunction remove_func,
11359 <tt/widget/, <tt/selection/, y <tt/target/ identifican las peticiones
11360 que este manejador puede manipular. Si <tt/remove_func/ no es NULL, se
11361 le llamará cuando se elimine el manejador de la señal. Esto es útil,
11362 por ejemplo, para los lenguajes interpretados que necesitan mantener
11363 una memoria de las referencias a <tt/data/.
11365 La función de llamada tiene el prototipo:
11368 typedef void (*GtkSelectionFunction)( GtkWidget *widget,
11369 GtkSelectionData *selection_data,
11374 El <tt/GtkSelectionData/ es el mismo que hay más arriba, pero esta
11375 vez, seremos nosotros los responsables de rellenar los campos
11376 <tt/type/, <tt/format/, <tt/data/, y <tt/length/. (El campo
11377 <tt/format/ es importante - el servidor X lo utiliza para saber si
11378 tienen que intercambiarse los bytes que forman los datos o
11379 no. Normalmente será 8 - es decir un carácter - o 32 - es decir un
11380 entero.) Esto se hace llamando a la función:
11383 void gtk_selection_data_set( GtkSelectionData *selection_data,
11390 Esta función tiene la responsabilidad de hacer una copia de los datos
11391 para que no tenga que preocuparse de ir guardándolos. (No debería
11392 rellenar los campos de la estructura <tt/GtkSelectionData/ a mano.)
11394 Cuando haga falta, puede pedir el propietario de la selección llamando
11398 gint gtk_selection_owner_set( GtkWidget *widget,
11403 Si otra aplicación pide el propietario de la selección, recibira un
11404 «selection_clear_event».
11406 Como ejemplo de proporciar la selección, el programa siguiente le añade
11407 la posibilidad de selección a un botón de comprobación. Cuando se presione
11408 el botón de comprobación, el programa pedirá la selección primaria. El
11409 único objetivo que admite es un objetivo «STRING» (aparte de ciertos
11410 objetivos como "TARGETS", proporcionados por GTK). Cuando se pida este
11411 objetivo, se devolverá una representación del tiempo.
11414 /* principio del ejemplo selection setselection.c */
11416 #include <gtk/gtk.h>
11419 /* Función de llamada para cuando el usuario cambia la selección */
11421 selection_toggled (GtkWidget *widget, gint *have_selection)
11423 if (GTK_TOGGLE_BUTTON(widget)->active)
11425 *have_selection = gtk_selection_owner_set (widget,
11426 GDK_SELECTION_PRIMARY,
11428 /* Si la demanda de la selección ha fallado, ponemos el botón en
11429 * estado apagado */
11430 if (!*have_selection)
11431 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
11435 if (*have_selection)
11437 /* Antes de eliminar la seleción poniendo el propietario a
11438 * NULL, comprobamos si somos el propietario actual */
11439 if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
11440 gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
11442 *have_selection = FALSE;
11447 /* Llamado cuando otra aplicación pide la selección */
11449 selection_clear (GtkWidget *widget, GdkEventSelection *event,
11450 gint *have_selection)
11452 *have_selection = FALSE;
11453 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
11458 /* Proporciona el tiempo actual como selección. */
11460 selection_handle (GtkWidget *widget,
11461 GtkSelectionData *selection_data,
11465 time_t current_time;
11467 current_time = time (NULL);
11468 timestr = asctime (localtime(&current_time));
11469 /* Cuando devolvemos una cadena, no debe terminar en NULL. La
11470 * función lo hará por nosotros */
11472 gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
11473 8, timestr, strlen(timestr));
11477 main (int argc, char *argv[])
11479 GtkWidget *ventana;
11481 GtkWidget *selection_button;
11483 static int have_selection = FALSE;
11485 gtk_init (&argc, &argv);
11487 /* Crear la ventana superior */
11489 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11490 gtk_window_set_title (GTK_WINDOW (ventana), "Event Box");
11491 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
11493 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
11494 GTK_SIGNAL_FUNC (gtk_exit), NULL);
11496 /* Crear un botón de selección para que actue como la selección */
11498 selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
11499 gtk_container_add (GTK_CONTAINER (ventana), selection_button);
11500 gtk_widget_show (selection_button);
11502 gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
11503 GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
11504 gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
11505 GTK_SIGNAL_FUNC (selection_clear), &have_selection);
11507 gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
11508 GDK_SELECTION_TYPE_STRING,
11509 selection_handle, NULL);
11511 gtk_widget_show (selection_button);
11512 gtk_widget_show (ventana);
11518 /* fin del ejemplo */
11522 <!-- ***************************************************************** -->
11523 <sect>Glib<label id="sec_glib">
11524 <!-- ***************************************************************** -->
11526 Glib proporciona muchas definiciones y funciones útiles disponibles
11527 para su utilización cuando se crean aplicaciones GDK y GTK. Haré una
11528 lista con todas ellas incluyendo una pequeña explicación. Muchas no
11529 son más que duplicados de funciones estándar de libc por lo que no
11530 entraré en detalle en la explicación de las mismas. Esta sección está
11531 pensada principalmente para que se utilice como referencia, para que
11532 sepa que es lo que puede utilizar.
11534 <!-- ----------------------------------------------------------------- -->
11535 <sect1>Definiciones
11537 Las definiciones para los límites de muchos de los tipos estándar son:
11552 Y también, los siguientes <tt/typedefs/. Cuando no se especifica el
11553 tipo que debería aparecer a la izquierda significa que el mismo se
11554 establecerá dinámicamente en función de la arquitectura. ¡Recuerde
11555 evitar los calculos relativos al tamaño de un puntero si quiere que
11556 su aplicación sea portable! P.e., un puntero en un Alpha tiene 8
11557 bytes, pero 4 en Intel.
11566 unsigned char guchar;
11567 unsigned short gushort;
11568 unsigned long gulong;
11569 unsigned int guint;
11573 long double gldouble;
11585 <!-- ----------------------------------------------------------------- -->
11586 <sect1>Listas doblemente enlazadas
11588 Las funciones siguientes se utilizan para crear, manipular, y destruir
11589 listas doblemente enlazadas. Supondré que sabe lo que son las listas
11590 enlazadas, ya que explicarlas va más allá del objetivo de este
11591 documento. Por supuesto, no es necesario que conozca como manejar
11592 todo esto para utilizar GTK, pero siempre es bonito aprender cosas.
11595 GList *g_list_alloc( void );
11597 void g_list_free( GList *list );
11599 void g_list_free_1( GList *list );
11601 GList *g_list_append( GList *list,
11604 GList *g_list_prepend( GList *list,
11607 GList *g_list_insert( GList *list,
11611 GList *g_list_remove( GList *list,
11614 GList *g_list_remove_link( GList *list,
11617 GList *g_list_reverse( GList *list );
11619 GList *g_list_nth( GList *list,
11622 GList *g_list_find( GList *list,
11625 GList *g_list_last( GList *list );
11627 GList *g_list_first( GList *list );
11629 gint g_list_length( GList *list );
11631 void g_list_foreach( GList *list,
11633 gpointer user_data );
11636 <!-- ----------------------------------------------------------------- -->
11637 <sect1>Listas simplemente enlazadas
11639 Muchas de las funciones para las listas enlazadas son idénticas a las
11640 de más arriba. Aquí hay una lista completa:
11643 GSList *g_slist_alloc( void );
11645 void g_slist_free( GSList *list );
11647 void g_slist_free_1( GSList *list );
11649 GSList *g_slist_append( GSList *list,
11652 GSList *g_slist_prepend( GSList *list,
11655 GSList *g_slist_insert( GSList *list,
11659 GSList *g_slist_remove( GSList *list,
11662 GSList *g_slist_remove_link( GSList *list,
11665 GSList *g_slist_reverse( GSList *list );
11667 GSList *g_slist_nth( GSList *list,
11670 GSList *g_slist_find( GSList *list,
11673 GSList *g_slist_last( GSList *list );
11675 gint g_slist_length( GSList *list );
11677 void g_slist_foreach( GSList *list,
11679 gpointer user_data );
11683 <!-- ----------------------------------------------------------------- -->
11684 <sect1>Control de la memoria
11687 gpointer g_malloc( gulong size );
11690 Reemplaza a <tt/malloc()/. No necesita comprobar el valor devuelto, ya
11691 que ya lo hace por usted esta función.
11694 gpointer g_malloc0( gulong size );
11697 Lo mismo que antes, pero rellena con ceros la memoria antes de
11698 devolver un puntero a ella.
11701 gpointer g_realloc( gpointer mem,
11705 Vuelve a reservar <tt/size/ bites de memoria empezando en
11706 <tt/mem/. Obviamente, la memoria debe haber sido previamente reservada.
11709 void g_free( gpointer mem );
11712 Libera la memoria. Fácil.
11715 void g_mem_profile( void );
11718 Crea un fichero donde vuelca la memoria que se está utilizando, pero
11719 tiene que añadir <tt/#define MEM_PROFILE/ en lo alto de
11720 <tt>glib/gmem.c</tt> y tendrá que hacer un make y un make install.
11723 void g_mem_check( gpointer mem );
11726 Comprueba que una dirección de memoria es válida. Tiene que añadir
11727 <tt/#define MEM_CHECK/ en lo alto de <tt/gmem.c/ y tiene que hacer un
11728 make y un make install.
11730 <!-- ----------------------------------------------------------------- -->
11736 GTimer *g_timer_new( void );
11738 void g_timer_destroy( GTimer *timer );
11740 void g_timer_start( GTimer *timer );
11742 void g_timer_stop( GTimer *timer );
11744 void g_timer_reset( GTimer *timer );
11746 gdouble g_timer_elapsed( GTimer *timer,
11747 gulong *microseconds );
11750 <!-- ----------------------------------------------------------------- -->
11751 <sect1>Manejo de cadenas de texto
11753 Un puñado de funciones para manejar cadenas de texto. Parecen muy
11754 interesantes, y probablemente sean mejores en muchos aspectos que las
11755 funciones estándar de C, pero necesitan documentación.
11758 GString *g_string_new( gchar *init );
11760 void g_string_free( GString *string,
11761 gint free_segment );
11763 GString *g_string_assign( GString *lval,
11766 GString *g_string_truncate( GString *string,
11769 GString *g_string_append( GString *string,
11772 GString *g_string_append_c( GString *string,
11775 GString *g_string_prepend( GString *string,
11778 GString *g_string_prepend_c( GString *string,
11781 void g_string_sprintf( GString *string,
11785 void g_string_sprintfa ( GString *string,
11790 <!-- ----------------------------------------------------------------- -->
11791 <sect1>Funciones de error y funciones varias
11794 gchar *g_strdup( const gchar *str );
11797 Reemplaza a la función <tt/strdup/. Copia el contenido de la cadena
11798 original en un nuevo lugar en memoria, y devuelve un puntero al nuevo
11802 gchar *g_strerror( gint errnum );
11805 Recomiendo utilizar esta función para todos los mensages de error. Es
11806 mucho más bonita, y más portable que <tt/perror()/ y demás funciones
11807 clásicas. La salida es normalmente de la forma:
11810 nombre del programa:función que falló:fichero o descripción adicional:strerror
11813 Aquí hay un ejemplo de una llamada utilizada en nuestro programa
11817 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
11821 void g_error( gchar *format, ... );
11824 Imprime un mensaje de error. El formato es como el de <tt/printf/,
11825 pero le añade <tt/** ERROR **: / a su mensaje, y sale del
11826 programa. Sólo para errores fatales.
11829 void g_warning( gchar *format, ... );
11832 El mismo que el anterior, pero añade "** WARNING **: ", y no sale del
11836 void g_message( gchar *format, ... );
11839 Imprime <tt/message: / antes de la cadena que le pase.
11842 void g_print( gchar *format, ... );
11845 Reemplazo de <tt/printf()/.
11847 Y nuestra última función:
11850 gchar *g_strsignal( gint signum );
11853 Imprime el nombre de la señal del sistema Unix que corresponde con el
11854 número <tt/signum/. Útil para las funciones genéricas de manejo de señal.
11856 Todo lo anterior está más o menos robado de <tt/glib.h/. Si alguien
11857 quiere documentar una función, ¡sólo tiene que enviarme un correo-e!
11859 <!-- ***************************************************************** -->
11860 <sect>Ficheros rc de GTK
11861 <!-- ***************************************************************** -->
11863 GTK tiene su propia forma de conseguir los valores por defecto de una
11864 aplicación, y es utilizando los ficheros <tt/rc/. Pueden ser
11865 utilizados para poner los colores de cualquier <em/widget/, y también
11866 pueden utilizarse para poner imágenes como fondos de algunos <em/widgets/.
11868 <!-- ----------------------------------------------------------------- -->
11869 <sect1>Funciones para los ficheros <tt/rc/
11871 Cuando empiece su aplicación, debería incluir una llamada a:
11874 void gtk_rc_parse( char *filename );
11877 Poniendo el nombre del fichero de su rc. Esto hará que GTK analice
11878 este fichero, y utilice el estilo para los <em/widgets/ que se definan
11881 Si desea tener un conjunto especial de <em/widgets/ con un estilo
11882 diferente de los otros, o realizar cualquier otra división lógica de
11883 los <em/widgets/, haga una llamada a:
11886 void gtk_widget_set_name( GtkWidget *widget,
11890 Pasándole su nuevo <em/widget/ como primer argumento, y el nombre que
11891 desea darle como el segundo. Mediante este nombre podrá cambiar los
11892 atributos de ese <em/widget/.
11894 Si hacemos algo así:
11897 boton = gtk_button_new_with_label ("Botón especial");
11898 gtk_widget_set_name (boton, "botón especial");
11901 El botón tendrá el nombre «botón especial» y podría hacersele
11902 referencia en el fichero <tt/rc/ como «botón especial.GtkButton».
11903 [<--- ¡Verificadme! ]
11905 El fichero de ejemplo <tt/rc/ que mostramos a continuación, establece las
11906 propiedades de la ventana principal, y deja que todos los hijos de la
11907 ventana principal hereden el estilo descrito por «main button». El
11908 código utilizado en la aplicación es:
11911 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11912 gtk_widget_set_name (ventana, "main window");
11915 Y el estilo se define en el fichero <tt/rc/ utilizando:
11918 widget "main window.*GtkButton*" style "main_button"
11921 Qué hace que todos los <em/widgets/ GtkButton de la «main window»
11922 (ventana principal) tengan el estilo "main_buttons" tal y como se
11923 define en el fichero <tt/rc/.
11925 Como puede ver, es un sistema muy poderoso y flexible. Utilice su
11926 imaginación para aprovecharse al máximo de este sistema.
11928 <!-- ----------------------------------------------------------------- -->
11929 <sect1>Formato de los ficheros <tt/rc/ de GTK
11931 El formato de los ficheros GTK se muestra en el ejemplo de más
11932 abajo. Éste es el fichero <tt/testgtkrc/ de la distribución GTK, pero he
11933 añadido unos cuantos comentarios y alguna cosilla. Puede que quiera
11934 incluir esta explicación en su aplicación para permitir al usuario
11935 personalizar su aplicación.
11937 Hay varias directivas para cambiar los atributos de un <em/widget/.
11940 <item>fg - Establece el color de primer plano de un <em/widget/.
11941 <item>bg - Establece el color de fondo de un <em/widget/.
11942 <item>bg_pixmap - Establece la imagen que servirá de fondo al
11943 <em/widget/ (como mosaico).
11944 <item>font - Establece el tipo de letra que se utilizará con el
11948 Además de esto, hay varios estados en el que puede estar un
11949 <em/widget/, y puede especificar diferentes colores, imágenes y tipos
11950 de letra para cada estado. Estos estados son:
11953 <item>NORMAL - El estado normal de un <em/widget/, sin el ratón sobre
11954 él, y no siendo presionado, etc...
11955 <item>PRELIGHT - Cuando el ratón esté sobre este <em/widget/ se
11956 utilizarán los colores definidos para este estado.
11957 <item>ACTIVE - Cuando se presiona o se pulsa sobre el <em/widget/,
11958 estará activo, y los atributos asignados por está etiqueta serán
11960 <item>INSENSITIVE - Cuando un <em/widget/ es insensible, y no se puede
11961 activar, tomará estos atributos.
11962 <item>SELECTED - Cuando se seleccione un objeto, tomará estos atributos.
11965 Cuando se utilizan las directivas «fg» y «bg» para poner los colores de
11966 los <em/widgets/, se utilizará el formato siguiente:
11969 fg[<STATE>] = { Red, Green, Blue }
11972 Donde <tt/STATE/ es uno de los estados anteriores (PRELIGHT, ACTIVE,
11973 etc...), y el <tt/Red/, <tt/Green/ y <tt/Blue/ (Rojo, Verde y Azul)
11974 son valores en el rango 0 - 1.0, { 1.0, 1.0, 1.0 } es blanco. Deben
11975 estar en formato flotante, o serán un 0, por lo que "1" no funcionará,
11976 debe ser "1.0". Un "0" está bien ya que es lo mismo si no se
11977 reconoce. Los valores no reconocidos se pondrán a 0.
11979 <tt/bg_pixmap/ es muy similar al de arriba, salvo que los colores se
11980 reemplazan por un nombre de fichero.
11982 <tt/pixmap_path/ es una lista de los caminos (<em/paths/) separados por
11983 «:». Estos caminos se utilizarán para buscar cualquier imagen que
11986 La directiva sobre el tipo de letra es simplemente:
11988 font = "<nombre del tipo de letra>"
11991 Donde lo único difícil es saber la cadena del tipo de letra a
11992 elegir. Utilizar <tt/xfontsel/ o un programa similar debería ayudar.
11994 El <tt/widget_class/ establece el estilo de una clase de
11995 <em/widgets/. Estas clases se muestran en el resumen de <em/widgets/
11996 dentro de la jerarquía de clases.
11998 La directiva <tt/widget/ hace que un conjunto específico de
11999 <em/widgets/ tenga un estido determinado, sobreescribiendo cualquier
12000 estilo anterior que tuviese esa clase de <em/widgets/. Estos
12001 <em/widgets/ se registran dentro de la aplicación utilizando una
12002 llamada a <tt/gtk_widget_set_name()/. Esto le permitirá especificar
12003 los atributos de un <em/widget/ uno a uno, en vez de establecer los
12004 atributos de toda una clase <em/widget/. Deberá documentar cualquiera
12005 de estos <em/widgets/ especiales para que los usuarios puedan
12008 Cuando la palabra clave <tt/parent/ se utiliza como un atributo, el
12009 <em/widget/ tomará los atributos de su padre en la aplicación.
12011 Puede asignar los atributos de un estilo previamente definido a uno
12015 style "main_button" = "button"
12017 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
12018 bg[PRELIGHT] = { 0.75, 0, 0 }
12022 Este ejemplo toma el estilo «button», y crea un nuevo estilo
12023 «main_button» cambiando simplemente el tipo de letra y cambiando el
12024 color de fondo cuando el <em/widget/ esté en estado <tt/PRELIGHT/.
12026 Por supuesto, muchos de estos atributos no se aplican a todos los
12027 <em/widgets/. Realmente es una cuestión de sentido común. Se utilizará
12028 cualquier atributo que se pueda aplicar.
12030 <!-- ----------------------------------------------------------------- -->
12031 <sect1>Fichero <tt/rc/ de ejemplo
12034 <!-- Esto hay que traducirlo -->
12036 # pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
12038 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
12040 # style <name> [= <name>]
12045 # widget <widget_set> style <style_name>
12046 # widget_class <widget_class_set> style <style_name>
12049 # Here is a list of all the possible states. Note that some do not apply to
12052 # NORMAL - The normal state of a widget, without the mouse over top of
12053 # it, and not being pressed etc.
12055 # PRELIGHT - When the mouse is over top of the widget, colors defined
12056 # using this state will be in effect.
12058 # ACTIVE - When the widget is pressed or clicked it will be active, and
12059 # the attributes assigned by this tag will be in effect.
12061 # INSENSITIVE - When a widget is set insensitive, and cannot be
12062 # activated, it will take these attributes.
12064 # SELECTED - When an object is selected, it takes these attributes.
12066 # Given these states, we can set the attributes of the widgets in each of
12067 # these states using the following directives.
12069 # fg - Sets the foreground color of a widget.
12070 # fg - Sets the background color of a widget.
12071 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
12072 # font - Sets the font to be used with the given widget.
12075 # This sets a style called "button". The name is not really important, as
12076 # it is assigned to the actual widgets at the bottom of the file.
12080 #This sets the padding around the window to the pixmap specified.
12081 #bg_pixmap[<STATE>] = "<pixmap filename>"
12082 bg_pixmap[NORMAL] = "warning.xpm"
12087 #Sets the foreground color (font color) to red when in the "NORMAL"
12090 fg[NORMAL] = { 1.0, 0, 0 }
12092 #Sets the background pixmap of this widget to that of its parent.
12093 bg_pixmap[NORMAL] = "<parent>"
12098 # This shows all the possible states for a button. The only one that
12099 # doesn't apply is the SELECTED state.
12101 fg[PRELIGHT] = { 0, 1.0, 1.0 }
12102 bg[PRELIGHT] = { 0, 0, 1.0 }
12103 bg[ACTIVE] = { 1.0, 0, 0 }
12104 fg[ACTIVE] = { 0, 1.0, 0 }
12105 bg[NORMAL] = { 1.0, 1.0, 0 }
12106 fg[NORMAL] = { .99, 0, .99 }
12107 bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
12108 fg[INSENSITIVE] = { 1.0, 0, 1.0 }
12111 # In this example, we inherit the attributes of the "button" style and then
12112 # override the font and background color when prelit to create a new
12113 # "main_button" style.
12115 style "main_button" = "button"
12117 font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
12118 bg[PRELIGHT] = { 0.75, 0, 0 }
12121 style "toggle_button" = "button"
12123 fg[NORMAL] = { 1.0, 0, 0 }
12124 fg[ACTIVE] = { 1.0, 0, 0 }
12126 # This sets the background pixmap of the toggle_button to that of its
12127 # parent widget (as defined in the application).
12128 bg_pixmap[NORMAL] = "<parent>"
12133 bg_pixmap[NORMAL] = "marble.xpm"
12134 fg[NORMAL] = { 1.0, 1.0, 1.0 }
12139 font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
12142 # pixmap_path "~/.pixmaps"
12144 # These set the widget types to use the styles defined above.
12145 # The widget types are listed in the class hierarchy, but could probably be
12146 # just listed in this document for the users reference.
12148 widget_class "GtkWindow" style "window"
12149 widget_class "GtkDialog" style "window"
12150 widget_class "GtkFileSelection" style "window"
12151 widget_class "*Gtk*Scale" style "scale"
12152 widget_class "*GtkCheckButton*" style "toggle_button"
12153 widget_class "*GtkRadioButton*" style "toggle_button"
12154 widget_class "*GtkButton*" style "button"
12155 widget_class "*Ruler" style "ruler"
12156 widget_class "*GtkText" style "text"
12158 # This sets all the buttons that are children of the "main window" to
12159 # the main_button style. These must be documented to be taken advantage of.
12160 widget "main window.*GtkButton*" style "main_button"
12163 <!-- ***************************************************************** -->
12164 <sect>Escribiendo sus propios <em/widgets/
12165 <!-- ***************************************************************** -->
12167 <!-- ----------------------------------------------------------------- -->
12168 <sect1> Visión general
12170 Aunque la distribución de GTK viene con muchos tipos de <em/widgets/
12171 que debería cubrir todas la mayoría de las necesidades básicas, puede
12172 que haya llegado el momento en que necesite crear su propio
12173 <em/widget/. Debido a que GTK utiliza mucho la herencia de
12174 <em/widgets/, y si ya hay un <em/widget/ que se acerque lo suficiente
12175 a lo que quiere, tal vez pueda hacer un nuevo <em/widget/ con tan solo
12176 unas cuantas líneas de código. Pero antes de empezar a trabajar en un
12177 nuevo <em/widget/, asegúrese primero de que no hay nadie que ya haya
12178 hecho otro parecido. Así evitará la duplicación de esfuerzo y
12179 mantendrá el número de <em/widgets/ GTK en su valor mínimo, lo que
12180 ayudará a que el código y la interfaz de las diferentes aplicaciones
12181 sea consistente. Por otra parte, cuando haya acabado su <em/widget/,
12182 anúncielo al mundo entreo para que todo el mundo se pueda
12183 beneficiar. Probablemente el mejor lugar para hacerlo sea la
12186 Las fuentes completas de los <em/widgets/ de ejemplo están disponibles
12187 en el mismo lugar en el que consiguió este tutorial, o en:
12189 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
12190 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
12193 <!-- ----------------------------------------------------------------- -->
12194 <sect1> La anatomía de un <em/widget/
12196 Para crear un nuevo <em/widget/, es importante conocer como funcionan
12197 los objetos de GTK. Esta sección es sólo un breve resumen. Ver la
12198 documentación a la que se hace referencia para obtener más detalles.
12200 Los widgets GTK están implementados siguiendo una orientación a
12201 objetos. Sin embargo, están implementados en C estándar. De esta forma
12202 se mejora enormemente la portabilidad y la estabilidad con respecto a
12203 la actual generación de compiladores C++; sin embargo, con todo esto
12204 no queremos decir que el creador de <em/widgets/ tenga que prestar
12205 atención a ninguno de los detalles de implementación. La información
12206 que es común a todos los <em/widgets/ de una clase de <em/widgets/
12207 (p.e., a todos los <em/widgets/ botón) se almacena en la
12208 <em>estructura de clase</em>. Sólo hay una copia de ésta en la que se
12209 almacena información sobre las señales de la clase (que actuan como
12210 funciones virtuales en C). Para permitir la herencia, el primer campo
12211 en la estructura de la clase debe ser una copia de la estructura de la
12212 clase del padre. La declaración de la estructura de la clase de
12213 GtkButton debe ser algo así:
12216 struct _GtkButtonClass
12218 GtkContainerClass parent_class;
12220 void (* pressed) (GtkButton *button);
12221 void (* released) (GtkButton *button);
12222 void (* clicked) (GtkButton *button);
12223 void (* enter) (GtkButton *button);
12224 void (* leave) (GtkButton *button);
12228 Cuando un botón se trata como un contenedor (por ejemplo, cuando se le
12229 cambia el tamaño), su estructura de clase puede convertirse a
12230 GtkContainerClass, y los campos relevantes se utilizarán para manejar
12233 También hay una estructura que se crea para cada <em/widget/. Esta
12234 estructura tiene campos para almacenar la información que es diferente
12235 para cada copia del <em/widget/. Nosotros llamaremos a esta estructura
12236 la <em>estructura objeto</em>. Para la clase botón, es así:
12241 GtkContainer container;
12245 guint in_button : 1;
12246 guint button_down : 1;
12250 Observe que, como en la estructura de clase, el primer campo es la
12251 estructura objeto de la clase padre, por lo que esta estructura puede
12252 convertirse en la estructura de la clase del objeto padre cuando haga
12255 <!-- ----------------------------------------------------------------- -->
12256 <sect1> Creando un <em/widget/ compuesto
12258 <!-- ----------------------------------------------------------------- -->
12259 <sect2> Introducción
12261 Un tipo de widget que puede interesarnos es uno que sea un mero
12262 agregado de otros <em/widgets/ GTK. Este tipo de <em/widget/ no hace
12263 nada que no pueda hacerse sin la necesidad de crear un nuevo
12264 <em/widget/, pero proporciona una forma conveniente de empaquetar los
12265 elementos del interfaz de usuario para su reutilización. Los
12266 <em/widgets/ <tt/FileSelection/ y <tt/ColorSelection/ incluidos en la
12267 distribución estándar son ejemplos de este tipo de <em/widgets/.
12269 El <em/widget/ ejemplo que hemos creado en esta sección es el
12270 <em/widget/ Tictactoe, una matriz de 3x3 de botones de selección que
12271 lanza una señal cuando están deseleccionados tres botones en una misma
12272 fila, columna, o diagonal.
12274 <!-- ----------------------------------------------------------------- -->
12275 <sect2> Escogiendo una clase padre
12277 Normalmente la clase padre para un <em/widget/ compuesto es la clase
12278 contenedor que tenga todos los elementos del <em/widget/
12279 compuesto. Por ejemplo, la clase padre del <em/widget/
12280 <tt/FileSelection/ es la clase <tt/Dialog/. Ya que nuestros botones se
12281 ordenarán en una tabla, parece natural hacer que nuestra clase padre
12282 sea la clase <tt/GtkTable/. Desafortunadamente, esto no
12283 funcionaría. La creación de un <em/widget/ se divide en dos funciones
12284 - una función <tt/NOMBREWIDGET_new()/ que utilizará el usuario, y una
12285 función <tt/NOMBREWIDGET_init()/ que hará el trabajo básico de
12286 inicializar el <em/widget/ que es independiente de los argumentos que
12287 se le pasen a la función <tt/_new()/. Los <em/widgets/ derivados sólo
12288 llaman a la función <tt/_init/ de su <em/widget/ padre. Pero esta
12289 división del trabajo no funciona bien con las tablas, que necesitan
12290 saber en el momento de su creación el número de filas y de columnas
12291 que deben tener. A menos que queramos duplicar la mayor parte de lo
12292 hecho en <tt/gtk_table_new()/ en nuestro <em/widget/ Tictactoe,
12293 haremos mejor si evitamos derivar de GtkTable. Por esta razón,
12294 derivaremos de <tt/GtkVBox/, y meteremos nuestra tabla dentro de la
12297 <!-- ----------------------------------------------------------------- -->
12298 <sect2> El fichero de cabecera
12300 Cada clase <em/widget/ tiene un fichero de cabecera que declara el
12301 objeto y las estructuras de clase para ese <em/widget/, así como las
12302 funciones públicas. Un par de características que merecen dejarse
12303 aparte. Para evitar la duplicación de definiciones, meteremos el
12304 fichero de cabecera al completo entre:
12307 #ifndef __TICTACTOE_H__
12308 #define __TICTACTOE_H__
12312 #endif /* __TICTACTOE_H__ */
12315 Y para que los programas en C++ incluyan sin problemas el fichero de
12316 cabecera, pondremos:
12321 #endif /* __cplusplus */
12327 #endif /* __cplusplus */
12330 Con las funciones y las estructuras, declararemos tres macros estándar
12331 en nuestro fichero de cabecera, <tt/TICTACTOE(obj)/,
12332 <tt/TICTACTOE_CLASS(class)/, y <tt/IS_TICTACTOE(obj)/, que,
12333 convierten, respectivamente, un puntero en un puntero al objeto o a la
12334 estructura de la clase, y comprueba si un objeto es un <em/widget/
12337 Aquí está el fichero de cabecera al completo:
12342 #ifndef __TICTACTOE_H__
12343 #define __TICTACTOE_H__
12345 #include <gdk/gdk.h>
12346 #include <gtk/gtkvbox.h>
12350 #endif /* __cplusplus */
12352 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
12353 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
12354 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
12357 typedef struct _Tictactoe Tictactoe;
12358 typedef struct _TictactoeClass TictactoeClass;
12364 GtkWidget *botones[3][3];
12367 struct _TictactoeClass
12369 GtkVBoxClass parent_class;
12371 void (* tictactoe) (Tictactoe *ttt);
12374 guint tictactoe_get_type (void);
12375 GtkWidget* tictactoe_new (void);
12376 void tictactoe_clear (Tictactoe *ttt);
12380 #endif /* __cplusplus */
12382 #endif /* __TICTACTOE_H__ */
12386 <!-- ----------------------------------------------------------------- -->
12387 <sect2> La función <tt/_get_type()/.
12389 Ahora continuaremos con la implementación de nuestro <em/widget/. Una
12390 función del núcleo de todo <em/widget/ es
12391 <tt/NOMBREWIDGET_get_type()/. Cuando se llame a esta función por
12392 vez primera, le informará a GTK sobre la clase del <em/widget/, y
12393 devolverá un ID que identificará unívocamente la clase <em/widget/. En
12394 las llamadas siguientes, lo único que hará será devolver el ID.
12398 tictactoe_get_type ()
12400 static guint ttt_type = 0;
12404 GtkTypeInfo ttt_info =
12407 sizeof (Tictactoe),
12408 sizeof (TictactoeClass),
12409 (GtkClassInitFunc) tictactoe_class_init,
12410 (GtkObjectInitFunc) tictactoe_init,
12411 (GtkArgSetFunc) NULL,
12412 (GtkArgGetFunc) NULL
12415 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
12422 La estructura GtkTypeInfo tiene la definición siguiente:
12425 struct _GtkTypeInfo
12430 GtkClassInitFunc class_init_func;
12431 GtkObjectInitFunc object_init_func;
12432 GtkArgSetFunc arg_set_func;
12433 GtkArgGetFunc arg_get_func;
12437 Los utilidad de cada campo de esta estructura se explica por su propio
12438 nombre. Ignoraremos por ahora los campos <tt/arg_set_func/
12439 y <tt/arg_get_func/: son importantes, pero todavía es raro
12440 utilizarlos, su papel es permitir que las opciones de los <em/wdigets/
12441 puedan establecerse correctamente mediante lenguajes
12442 interpretados. Una vez que GTK tiene una copia de esta estructura
12443 correctamente rellenada, sabrá como crear objetos de un tipo
12444 particular de <em/widget/.
12446 <!-- ----------------------------------------------------------------- -->
12447 <sect2> La función <tt/_class_init()/
12449 La función <tt/NOMBREWIDGET_class_init()/ inicializa los campos de la
12450 estructura clase del <em/widget/, y establece las señales de la
12451 clase. Para nuestro <em/widget/ Tictactoe será una cosa así:
12460 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
12463 tictactoe_class_init (TictactoeClass *class)
12465 GtkObjectClass *object_class;
12467 object_class = (GtkObjectClass*) class;
12469 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
12471 object_class->type,
12472 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
12473 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
12476 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
12478 class->tictactoe = NULL;
12482 Nuestro <em/widget/ sólo tiene una señal, la señal <tt/tictactoe/ que
12483 se invoca cuando una fila, columna, o diagonal se rellena
12484 completamente. No todos los <em/widgets/ compuestos necesitan señales,
12485 por lo que si está leyendo esto por primera vez, puede que sea mejor
12486 que pase a la sección siguiente, ya que las cosas van a complicarse un
12492 gint gtk_signal_new( const gchar *name,
12493 GtkSignalRunType run_type,
12494 GtkType object_type,
12495 gint function_offset,
12496 GtkSignalMarshaller marshaller,
12497 GtkType return_val,
12502 crea una nueva señal. Los parámetros son:
12505 <item> <tt/name/: El nombre de la señal.
12506 <item> <tt/run_type/: Si el manejador por defecto se ejecuta antes o
12507 despues del manejador de usuario. Normalmente debe ser
12508 <tt/GTK_RUN_FIRST/, o <tt/GTK_RUN_LAST/, aunque hay otras
12510 <item> <tt/object_type/: El ID del objeto al que se le aplica esta
12511 señal. (También se aplicará a los descendientes de los objetos)
12512 <item> <tt/function_offset/: El desplazamiento en la estructura de la
12513 clase de un puntero al manejador por defecto.
12514 <item> <tt/marshaller/: Una función que se utiliza para invocar al
12515 manejador de señal. Para los manejadores de señal que no tengan más
12516 argumentos que el objeto que emitió la señal podemos utilizar la
12517 función marshaller por defecto <tt/gtk_signal_default_marshaller/.
12518 <item> <tt/return_val/: El tipo del valor devuelto.
12519 <item> <tt/nparams/: El número de parámetros del manejador de señal
12520 (distintos de los dos por defecto que hemos mencionado arriba).
12521 <item> <tt/.../: Los tipos de los parámetros.
12524 Cuando se especifican los tipos, se utilizará la enumeración
12550 /* it'd be great if the next two could be removed eventually */
12552 GTK_TYPE_C_CALLBACK,
12556 } GtkFundamentalType;
12559 <tt/gtk_signal_new()/ devuelve un identificador entero único para la
12560 señal, que almacenamos en el vector <tt/tictactoe_signals/, que
12561 indexaremos utilizando una enumeración. (Convencionalmente, los
12562 elementos de la enumeración son el nombre de la señal, en mayúsculas,
12563 pero aquí tendríamos un conflicto con la macro <tt/TICTACTOE()/, por
12564 lo que lo llamaremos <tt/TICTACTOE_SIGNAL/.
12566 Después de crear nuestras señales, necesitamos llamar a GTK para
12567 asociarlas con la clase Tictactoe. Hacemos esto llamando a
12568 <tt/gtk_object_class_add_signals()/. Entonces haremos que el puntero
12569 que apunta al manejador por defecto para la señal `tictactoe' sea NULL,
12570 indicando que no hay ninguna acción por defecto.
12572 <!-- ----------------------------------------------------------------- -->
12573 <sect2> La función <tt/_init()/.
12575 Cada clase <em/widget/ también necesita una función para inicializar
12576 la estructura del objeto. Normalmente, esta función tiene el limitado
12577 rol de poner los distintos campos de la estructura a su valor por
12578 defecto. Sin embargo para los <em/widgets/ de composición, esta
12579 función también crea los distintos <em/widgets/ componentes.
12583 tictactoe_init (Tictactoe *ttt)
12588 table = gtk_table_new (3, 3, TRUE);
12589 gtk_container_add (GTK_CONTAINER(ttt), table);
12590 gtk_widget_show (table);
12595 ttt->buttons[i][j] = gtk_toggle_button_new ();
12596 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
12598 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
12599 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
12600 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
12601 gtk_widget_show (ttt->buttons[i][j]);
12606 <!-- ----------------------------------------------------------------- -->
12607 <sect2> Y el resto...
12609 Hay una función más que cada <em/widget/ (excepto los <em/widget/ muy
12610 básicos como GtkBin que no pueden crear objetos) tiene que
12611 tener - la función que el usuario llama para crear un objeto de ese
12612 tipo. Normalmente se llama <tt/NOMBREWIDGET_new()/. En algunos
12613 <em/widgets/, que no es el caso del <em/widget/ Tictactoe, esta
12614 función toma argumentos, y hace alguna inicialización en función de
12615 estos. Las otras dos funciones son específicas al <em/widget/
12618 <tt/tictactoe_clear()/ es una función pública que reinicia todos los
12619 botones en el <em/widget/ a la posición alta. Observe la utilización
12620 de <tt/gtk_signal_handler_block_by_data()/ para hacer que no se
12621 ejecute nuestro manejador de señal innecesariamente por cambios en los
12624 <tt/tictactoe_toggle()/ es el manejador de señal que se invoca cuando
12625 el usuario pulsa un botón. Hace una comprobación para ver si hay
12626 alguna combinación ganadora, y si la hay, emite la señal
12633 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
12637 tictactoe_clear (Tictactoe *ttt)
12644 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12645 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
12647 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
12652 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
12656 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12657 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12658 { 0, 1, 2 }, { 0, 1, 2 } };
12659 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
12660 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
12661 { 0, 1, 2 }, { 2, 1, 0 } };
12663 int success, found;
12665 for (k=0; k<8; k++)
12672 success = success &&
12673 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
12675 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
12678 if (success && found)
12680 gtk_signal_emit (GTK_OBJECT (ttt),
12681 tictactoe_signals[TICTACTOE_SIGNAL]);
12688 Y finalmente, un programa ejemplo que utiliza nuestro <em/widget/
12692 #include <gtk/gtk.h>
12693 #include "tictactoe.h"
12695 /* Invocado cuando se completa una fila, columna o diagonal */
12697 win (GtkWidget *widget, gpointer data)
12699 g_print ("Yay!\n");
12700 tictactoe_clear (TICTACTOE (widget));
12704 main (int argc, char *argv[])
12706 GtkWidget *ventana;
12709 gtk_init (&argc, &argv);
12711 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
12713 gtk_window_set_title (GTK_WINDOW (ventana), "Aspect Frame");
12715 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
12716 GTK_SIGNAL_FUNC (gtk_exit), NULL);
12718 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
12720 /* Create a new Tictactoe widget */
12721 ttt = tictactoe_new ();
12722 gtk_container_add (GTK_CONTAINER (ventana), ttt);
12723 gtk_widget_show (ttt);
12725 /* And attach to its "tictactoe" signal */
12726 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
12727 GTK_SIGNAL_FUNC (win), NULL);
12729 gtk_widget_show (ventana);
12738 <!-- ----------------------------------------------------------------- -->
12739 <sect1> Creando un <em/widget/ desde cero.
12741 <!-- ----------------------------------------------------------------- -->
12742 <sect2> Introducción
12744 En esta sección, averiguaremos como se dibujan los <em/widgets/ a sí
12745 mismos en pantalla y como interactuan con los eventos. Como ejemplo,
12746 crearemos un marcador analógico con un puntero que el usuario
12747 podrá arrastrar para hacer que el marcador tenga un valor dado.
12749 <!-- ----------------------------------------------------------------- -->
12750 <sect2> Mostrando un <em/widget/ en la pantalla
12752 Hay varios pasos que están involucrados en el dibujado en pantalla.
12753 Después de que el <em/widget/ se cree con una llamada a
12754 <tt/NOMBREWIDGET_new()/, se necesitarán muchas más funciones:
12757 <item> <tt/NOMBREWIDGET_realize()/ es la responsable de crear una
12758 ventana X para el <em/widget/, si tiene alguna.
12759 <item> <tt/NOMBREWIDGET_map()/ se invoca después de las llamadas del
12761 <tt/gtk_widget_show()/. Es la responsable de asegurarse de que el
12762 <em/widget/ está dibujado (<em/mapeado/) en la pantalla. Para una
12763 clase contenedor, también deberá ocuparse de llamar a las funciones
12764 <tt/map()/ de cada <em/widget/ hijo.
12765 <item> <tt/NOMBREWIDGET_draw()/ se invoca cuando se llama a
12766 <tt/gtk_widget_draw()/ desde el <em/widget/ de uno de sus
12767 antepasados. Hace las llamadas necesarias a las funciones de dibujo
12768 para dibujar el <em/widget/ en la pantalla. Para los <em/widgets/
12769 contenedores, esta función debe llamar a las <tt/gtk_widget_draw/ de
12770 sus <em/widgets/ hijos.
12771 <item> <tt/NOMBREWIDGET_expose()/ es un manejador de los eventos
12772 <tt/expose/ del <em/widget/. Hace las llamadas necesarias a las
12773 funciones de dibujo para dibujar la parte expuesta en la
12774 pantalla. Para los <em/widgets/ contenedores, esta función debe
12775 generar los eventos <tt/expose/ de sus <em/widgets/ hijos que no
12776 tengan su propia ventana. (Si tuviesen su propia ventana, X generaría
12777 los eventos <tt/expose/ necesarios)
12780 Las últimas dos funciones son bastante similares - ambas son
12781 responsables de dibujar el <em/widget/ en pantalla. De hecho en muchos
12782 <em/widgets/ realmente no importa la diferencia que hay entre ambas
12783 funciones. La función <em/draw()/ que hay por defecto en
12784 la clase <em/widget/ simplemente genera un evento <tt/expose/
12785 artificial de la zona a redibujar. Sin embargo, algunos tipos de
12786 <em/widgets/ puede ahorrarse trabajo distinguiendo entre las dos
12787 funciones. Por ejemplo, si un <em/widget/ tiene varias ventanas X,
12788 entonces, como los eventos <tt/expose/ identifican a la ventana
12789 expuesta, podrán redibujar sólo la ventana afectada, lo que no es
12790 posible con llamadas a <tt/draw()/.
12792 Los <em/widgets/ contenedores, aunque no utilicen la diferecia
12793 existente entre las dos funciones por sí mismos, no pueden utilizar
12794 simplemente las funciones <tt/draw()/ que hay por defecto ya que sus
12795 <em/widgets/ hijos puede que tengan que utilizar la diferencia. Sin
12796 embargo, sería un derroche duplicar el código de dibujado entre las
12797 dos funciones. Lo normal es que cada <em/widget/ tenga una función
12798 llamada <tt/NOMBREWIDGET_paint()/ que haga el trabajo de dibujar el
12799 <em/widget/, ésta función será a la que se llame por las funciones
12800 <tt/draw()/ y <tt/expose()/.
12802 En nuestro ejemplo, como el <em/widget/ Dial no es un <em/widget/
12803 contenedor, y sólo tiene una ventana, podemos tomar el camino más
12804 corto, utilizar la función <tt/draw()/ por defecto y sólo
12805 implementar la función <tt/expose()/.
12807 <!-- ----------------------------------------------------------------- -->
12808 <sect2> Los orígenes del <em/widget/ Dial
12810 Así como todos los animales terrestes son variaciones del primer
12811 anfíbio que salió del barro, los <em/widgets/ Gtk tienden a nacer
12812 como variaciones de algún otro <em/widget/ escrito previamente. Por
12813 tanto, aunque esta sección se titule `Creando un <em/widget/ de la
12814 nada', el <em/widget/ Dial empieza realmente con el código fuente
12815 del <em/widget/ Range. He tomado éste como punto de arranque porque
12816 sería bonito que nuestro dial tuviese la misma interfaz que los
12817 <em/widgets/ Scale, que son sólo una especialización del <em/widget/
12818 Range. Por tanto, aunque el código fuente se presente más adelante en
12819 su forma final, no implica que fuese escrito de esta forma <em>deus ex
12820 machina</em>. Si todavía no está familiarizado, desde el punto de
12821 vista del escritor de aplicaciones, con la forma de funcionar de los
12822 <em/widgets/ Scale, sería una buena idea echarles un vistazo antes de
12825 <!-- ----------------------------------------------------------------- -->
12826 <sect2> Los comienzos
12828 Nuestro <em/widget/ tiene un aspecto algo parecido al del <em/widget/
12829 Tictactoe. Primero, tenemos un fichero de cabecera:
12832 /* GTK - The GIMP Toolkit
12833 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
12835 * This library is free software; you can redistribute it and/or
12836 * modify it under the terms of the GNU Library General Public
12837 * License as published by the Free Software Foundation; either
12838 * version 2 of the License, or (at your option) any later version.
12840 * This library is distributed in the hope that it will be useful,
12841 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12842 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12843 * Library General Public License for more details.
12845 * You should have received a copy of the GNU Library General Public
12846 * License along with this library; if not, write to the Free
12847 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
12850 #ifndef __GTK_DIAL_H__
12851 #define __GTK_DIAL_H__
12853 #include <gdk/gdk.h>
12854 #include <gtk/gtkadjustment.h>
12855 #include <gtk/gtkwidget.h>
12860 #endif /* __cplusplus */
12863 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
12864 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
12865 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
12868 typedef struct _GtkDial GtkDial;
12869 typedef struct _GtkDialClass GtkDialClass;
12875 /* política de actualización
12876 * (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
12879 /* Botón actualmente presionado o 0 si no hay ninguno */
12882 /* Dimensión de los componendes del dial */
12884 gint pointer_width;
12886 /* ID del temporizador de actualización, o 0 si no hay ninguno */
12889 /* ángulo actual */
12892 /* Viejos valores almacenados del adjustment, para que así no
12893 * tengamos que saber cuando cambia algo */
12898 /* El objeto adjustment que almacena los datos para este dial */
12899 GtkAdjustment *adjustment;
12902 struct _GtkDialClass
12904 GtkWidgetClass parent_class;
12908 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
12909 guint gtk_dial_get_type (void);
12910 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
12911 void gtk_dial_set_update_policy (GtkDial *dial,
12912 GtkUpdateType policy);
12914 void gtk_dial_set_adjustment (GtkDial *dial,
12915 GtkAdjustment *adjustment);
12918 #endif /* __cplusplus */
12921 #endif /* __GTK_DIAL_H__ */
12924 Como vamos a ir con este <em/widget/ un poco más lejos que con el
12925 último que creamos, ahora tenemos unos cuantos campos más en la
12926 estructura de datos, pero el resto de las cosas son muy parecidas.
12928 Ahora, después de incluir los ficheros de cabecera, y declarar unas
12929 cuantas constantes, tenemos algunas funciones que proporcionan
12930 información sobre el <em/widget/ y lo inicializan:
12935 #include <gtk/gtkmain.h>
12936 #include <gtk/gtksignal.h>
12938 #include "gtkdial.h"
12940 #define SCROLL_DELAY_LENGTH 300
12941 #define DIAL_DEFAULT_SIZE 100
12943 /* Declaraciones de funciones */
12945 [ omitido para salvar espacio ]
12947 /* datos locales */
12949 static GtkWidgetClass *parent_class = NULL;
12952 gtk_dial_get_type ()
12954 static guint dial_type = 0;
12958 GtkTypeInfo dial_info =
12962 sizeof (GtkDialClass),
12963 (GtkClassInitFunc) gtk_dial_class_init,
12964 (GtkObjectInitFunc) gtk_dial_init,
12965 (GtkArgSetFunc) NULL,
12966 (GtkArgGetFunc) NULL,
12969 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
12976 gtk_dial_class_init (GtkDialClass *class)
12978 GtkObjectClass *object_class;
12979 GtkWidgetClass *widget_class;
12981 object_class = (GtkObjectClass*) class;
12982 widget_class = (GtkWidgetClass*) class;
12984 parent_class = gtk_type_class (gtk_widget_get_type ());
12986 object_class->destroy = gtk_dial_destroy;
12988 widget_class->realize = gtk_dial_realize;
12989 widget_class->expose_event = gtk_dial_expose;
12990 widget_class->size_request = gtk_dial_size_request;
12991 widget_class->size_allocate = gtk_dial_size_allocate;
12992 widget_class->button_press_event = gtk_dial_button_press;
12993 widget_class->button_release_event = gtk_dial_button_release;
12994 widget_class->motion_notify_event = gtk_dial_motion_notify;
12998 gtk_dial_init (GtkDial *dial)
13001 dial->policy = GTK_UPDATE_CONTINUOUS;
13004 dial->pointer_width = 0;
13006 dial->old_value = 0.0;
13007 dial->old_lower = 0.0;
13008 dial->old_upper = 0.0;
13009 dial->adjustment = NULL;
13013 gtk_dial_new (GtkAdjustment *adjustment)
13017 dial = gtk_type_new (gtk_dial_get_type ());
13020 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
13022 gtk_dial_set_adjustment (dial, adjustment);
13024 return GTK_WIDGET (dial);
13028 gtk_dial_destroy (GtkObject *object)
13032 g_return_if_fail (object != NULL);
13033 g_return_if_fail (GTK_IS_DIAL (object));
13035 dial = GTK_DIAL (object);
13037 if (dial->adjustment)
13038 gtk_object_unref (GTK_OBJECT (dial->adjustment));
13040 if (GTK_OBJECT_CLASS (parent_class)->destroy)
13041 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
13045 Observe que ésta función <tt/init()/ hace menos cosas de las que hacía
13046 la función <tt/init()/ que utilizamos con el <em/widget/ Tictactoe, ya
13047 que éste no es un <em/widget/ compuesto, y la función <tt/new()/ hace
13048 más cosas, ya que ahora admite un argumento. Observe también que
13049 cuando almacenamos un puntero en un objeto Adjustment, incrementamos
13050 su contador interno, (y lo decrementamos cuando ya no lo utilizamos)
13051 por lo que GTK puede saber cuando se puede destruir sin que se
13052 produzcan problemas.
13055 Aquí tenemos unas cuantas funciones para manipular las opciones del
13060 gtk_dial_get_adjustment (GtkDial *dial)
13062 g_return_val_if_fail (dial != NULL, NULL);
13063 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
13065 return dial->adjustment;
13069 gtk_dial_set_update_policy (GtkDial *dial,
13070 GtkUpdateType policy)
13072 g_return_if_fail (dial != NULL);
13073 g_return_if_fail (GTK_IS_DIAL (dial));
13075 dial->policy = policy;
13079 gtk_dial_set_adjustment (GtkDial *dial,
13080 GtkAdjustment *adjustment)
13082 g_return_if_fail (dial != NULL);
13083 g_return_if_fail (GTK_IS_DIAL (dial));
13085 if (dial->adjustment)
13087 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
13088 gtk_object_unref (GTK_OBJECT (dial->adjustment));
13091 dial->adjustment = adjustment;
13092 gtk_object_ref (GTK_OBJECT (dial->adjustment));
13094 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
13095 (GtkSignalFunc) gtk_dial_adjustment_changed,
13097 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
13098 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
13101 dial->old_value = adjustment->value;
13102 dial->old_lower = adjustment->lower;
13103 dial->old_upper = adjustment->upper;
13105 gtk_dial_update (dial);
13109 <sect2> <tt/gtk_dial_realize()/
13112 Ahora vienen algunas funciones nuevas. Primero, tenemos una función
13113 que hace el trabajo de crear la ventana X. A la función se le pasará
13114 una máscara <tt/gdk_window_new()/ que especifica que campos de la
13115 estructura <tt/GdkWindowAttr/ tienen datos (los campos restantes
13116 tendrán los valores por defecto). También es bueno fijarse en la forma
13117 en que se crea la máscara de eventos. Llamamos a
13118 <tt/gtk_widget_get_events()/ para recuperar la máscara de eventos que
13119 el usuario ha especificado para su <em/widget/ (con
13120 <tt/gtk_widget_set_events()/), y añadir nosotros mismos los eventos
13121 en los que estemos interesados.
13124 Después de crear la ventana, decidiremos su estilo y su fondo, y
13125 pondremos un puntero al <em/widget/ en el campo de datos del usuario
13126 de la <tt/GdkWindow/. Este último paso le permite a GTK despachar los
13127 eventos que hayan para esta ventana hacia el <em/widget/ correcto.
13131 gtk_dial_realize (GtkWidget *widget)
13134 GdkWindowAttr attributes;
13135 gint attributes_mask;
13137 g_return_if_fail (widget != NULL);
13138 g_return_if_fail (GTK_IS_DIAL (widget));
13140 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
13141 dial = GTK_DIAL (widget);
13143 attributes.x = widget->allocation.x;
13144 attributes.y = widget->allocation.y;
13145 attributes.width = widget->allocation.width;
13146 attributes.height = widget->allocation.height;
13147 attributes.wclass = GDK_INPUT_OUTPUT;
13148 attributes.window_type = GDK_WINDOW_CHILD;
13149 attributes.event_mask = gtk_widget_get_events (widget) |
13150 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
13151 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
13152 GDK_POINTER_MOTION_HINT_MASK;
13153 attributes.visual = gtk_widget_get_visual (widget);
13154 attributes.colormap = gtk_widget_get_colormap (widget);
13156 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
13157 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
13159 widget->style = gtk_style_attach (widget->style, widget->window);
13161 gdk_window_set_user_data (widget->window, widget);
13163 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
13167 <sect2> Negociación del tamaño
13170 Antes de que se muestre por primera vez la ventana conteniendo un
13171 <em/widget/, y cuando quiera que la capa de la ventana cambie, GTK le
13172 preguntara a cada <em/widget/ hijo por su tamaño deseado. Esta
13173 petición se controla mediante la función
13174 <tt/gtk_dial_size_request()/. Como nuestro <em/widget/ no es un
13175 <em/widget/ contenedor, y no tiene ninguna limitación en su tamaño,
13176 nos contentaremos con devolver un valor por defecto.
13180 gtk_dial_size_request (GtkWidget *widget,
13181 GtkRequisition *requisition)
13183 requisition->width = DIAL_DEFAULT_SIZE;
13184 requisition->height = DIAL_DEFAULT_SIZE;
13189 Después de que todos los <em/widgets/ hayan pedido su tamaño ideal,
13190 se calculará la ventana y cada <em/widget/ hijo será informado de su
13191 tamaño actual. Normalmente, éste será al menos tan grande como el
13192 pedido, pero si por ejemplo, el usuario ha redimensionado la ventana,
13193 entonces puede que el tamaño que se le de al <em/widget/ sea menor
13194 que el que pidió. La notificación del tamaño se maneja mediante la
13195 función <tt/gtk_dial_size_allocate()/. Fíjese que esta función calcula
13196 los tamaños de los diferentes elementos que componen la ventana para
13197 su uso futuro, así como todo el trabajo sucio que poner los
13198 <em/widgets/ de la ventana X en la nueva posición y con el nuevo
13203 gtk_dial_size_allocate (GtkWidget *widget,
13204 GtkAllocation *allocation)
13208 g_return_if_fail (widget != NULL);
13209 g_return_if_fail (GTK_IS_DIAL (widget));
13210 g_return_if_fail (allocation != NULL);
13212 widget->allocation = *allocation;
13213 if (GTK_WIDGET_REALIZED (widget))
13215 dial = GTK_DIAL (widget);
13217 gdk_window_move_resize (widget->window,
13218 allocation->x, allocation->y,
13219 allocation->width, allocation->height);
13221 dial->radius = MAX(allocation->width,allocation->height) * 0.45;
13222 dial->pointer_width = dial->radius / 5;
13227 <!-- ----------------------------------------------------------------- -->
13228 <sect2> <tt/gtk_dial_expose()/
13231 Como se mencionó arriba, todo el dibujado de este <em/widget/ se hace
13232 en el manejador de los eventos <tt/expose/. No hay mucho destacable
13233 aquí, excepto la utilización de la función <tt/gtk_draw_polygon/ para
13234 dibujar el puntero con un degradado tridimensional de acuerdo con los
13235 colores almacenados en el estilo del <em/widget/.
13239 gtk_dial_expose (GtkWidget *widget,
13240 GdkEventExpose *event)
13243 GdkPoint points[3];
13250 g_return_val_if_fail (widget != NULL, FALSE);
13251 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13252 g_return_val_if_fail (event != NULL, FALSE);
13254 if (event->count > 0)
13257 dial = GTK_DIAL (widget);
13259 gdk_window_clear_area (widget->window,
13261 widget->allocation.width,
13262 widget->allocation.height);
13264 xc = widget->allocation.width/2;
13265 yc = widget->allocation.height/2;
13267 /* Dibujar las rayitas */
13269 for (i=0; i<25; i++)
13271 theta = (i*M_PI/18. - M_PI/6.);
13275 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
13277 gdk_draw_line (widget->window,
13278 widget->style->fg_gc[widget->state],
13279 xc + c*(dial->radius - tick_length),
13280 yc - s*(dial->radius - tick_length),
13281 xc + c*dial->radius,
13282 yc - s*dial->radius);
13285 /* Dibujar el puntero */
13287 s = sin(dial->angle);
13288 c = cos(dial->angle);
13291 points[0].x = xc + s*dial->pointer_width/2;
13292 points[0].y = yc + c*dial->pointer_width/2;
13293 points[1].x = xc + c*dial->radius;
13294 points[1].y = yc - s*dial->radius;
13295 points[2].x = xc - s*dial->pointer_width/2;
13296 points[2].y = yc - c*dial->pointer_width/2;
13298 gtk_draw_polygon (widget->style,
13309 <!-- ----------------------------------------------------------------- -->
13310 <sect2> Manejo de eventos
13313 El resto del código del <em/widget/ controla varios tipos de eventos,
13314 y no es muy diferente del que podemos encontrar en muchas aplicaciones
13315 GTK. Pueden ocurrir dos tipos de eventos - el usuario puede pulsar en
13316 el <em/widget/ con el ratón y arrastrar para mover el puntero, o el
13317 valor del objeto Adjustement puede cambiar debido a alguna
13318 circunstancia externa.
13321 Cuando el usuario pulsa en el <em/widget/, haremos una comprobación
13322 para ver si la pulsación se hizo lo suficientemente cerca del
13323 puntero, y si así fue, almacenamos el botón que pulsó el usuario en
13324 en el campo <tt/button/ de la estructura del <em/widget/, y grabamos
13325 todos los eventos del ratón con una llamada a <tt/gtk_grab_add()/. El
13326 movimiento del ratón hará que se recalcule el valor del control
13327 (mediante la función <tt/gtk_dial_update_mouse/). Dependiendo de la
13328 política que sigamos, o bien se generarán instantáneamente los eventos
13329 <tt/value_changed/ (<tt/GTK_UPDATE_CONTINUOUS/), o bien después de una
13330 espera del temporizador establecido mediante <tt/gtk_timeout_add()/
13331 (<tt/GTK_UPDATE_DELAYED/), o bien sólo cuando se levante el botón
13332 (<tt/GTK_UPDATE_DISCONTINUOUS/).
13336 gtk_dial_button_press (GtkWidget *widget,
13337 GdkEventButton *event)
13343 double d_perpendicular;
13345 g_return_val_if_fail (widget != NULL, FALSE);
13346 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13347 g_return_val_if_fail (event != NULL, FALSE);
13349 dial = GTK_DIAL (widget);
13351 /* Determinar si la pulsación del botón fue dentro de la región del
13352 puntero - esto lo hacemos calculando la distancia x e y del punto
13353 donde se pulsó el botón ratón de la línea que se ha pasado mediante el
13356 dx = event->x - widget->allocation.width / 2;
13357 dy = widget->allocation.height / 2 - event->y;
13359 s = sin(dial->angle);
13360 c = cos(dial->angle);
13362 d_parallel = s*dy + c*dx;
13363 d_perpendicular = fabs(s*dx - c*dy);
13365 if (!dial->button &&
13366 (d_perpendicular < dial->pointer_width/2) &&
13367 (d_parallel > - dial->pointer_width))
13369 gtk_grab_add (widget);
13371 dial->button = event->button;
13373 gtk_dial_update_mouse (dial, event->x, event->y);
13380 gtk_dial_button_release (GtkWidget *widget,
13381 GdkEventButton *event)
13385 g_return_val_if_fail (widget != NULL, FALSE);
13386 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13387 g_return_val_if_fail (event != NULL, FALSE);
13389 dial = GTK_DIAL (widget);
13391 if (dial->button == event->button)
13393 gtk_grab_remove (widget);
13397 if (dial->policy == GTK_UPDATE_DELAYED)
13398 gtk_timeout_remove (dial->timer);
13400 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
13401 (dial->old_value != dial->adjustment->value))
13402 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13409 gtk_dial_motion_notify (GtkWidget *widget,
13410 GdkEventMotion *event)
13413 GdkModifierType mods;
13416 g_return_val_if_fail (widget != NULL, FALSE);
13417 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
13418 g_return_val_if_fail (event != NULL, FALSE);
13420 dial = GTK_DIAL (widget);
13422 if (dial->button != 0)
13427 if (event->is_hint || (event->window != widget->window))
13428 gdk_window_get_pointer (widget->window, &x, &y, &mods);
13430 switch (dial->button)
13433 mask = GDK_BUTTON1_MASK;
13436 mask = GDK_BUTTON2_MASK;
13439 mask = GDK_BUTTON3_MASK;
13447 gtk_dial_update_mouse (dial, x,y);
13454 gtk_dial_timer (GtkDial *dial)
13456 g_return_val_if_fail (dial != NULL, FALSE);
13457 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
13459 if (dial->policy == GTK_UPDATE_DELAYED)
13460 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13466 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
13471 g_return_if_fail (dial != NULL);
13472 g_return_if_fail (GTK_IS_DIAL (dial));
13474 xc = GTK_WIDGET(dial)->allocation.width / 2;
13475 yc = GTK_WIDGET(dial)->allocation.height / 2;
13477 old_value = dial->adjustment->value;
13478 dial->angle = atan2(yc-y, x-xc);
13480 if (dial->angle < -M_PI/2.)
13481 dial->angle += 2*M_PI;
13483 if (dial->angle < -M_PI/6)
13484 dial->angle = -M_PI/6;
13486 if (dial->angle > 7.*M_PI/6.)
13487 dial->angle = 7.*M_PI/6.;
13489 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
13490 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
13492 if (dial->adjustment->value != old_value)
13494 if (dial->policy == GTK_UPDATE_CONTINUOUS)
13496 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13500 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13502 if (dial->policy == GTK_UPDATE_DELAYED)
13505 gtk_timeout_remove (dial->timer);
13507 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
13508 (GtkFunction) gtk_dial_timer,
13517 Cambios en el Adjustment por motivos externos significa que se le
13518 comunicarán a nuestro <em/widget/ mediante las señales <tt/changed/ y
13519 <tt/value_changed/. Los manejadores de estas funciones llaman a
13520 <tt/gtk_dial_update()/ para comprobar los argumentos, calcular el
13521 nuevo ángulo del puntero, y redibujar el <em/widget/ (llamando a
13522 <tt/gtk_widget_draw()/).
13526 gtk_dial_update (GtkDial *dial)
13530 g_return_if_fail (dial != NULL);
13531 g_return_if_fail (GTK_IS_DIAL (dial));
13533 new_value = dial->adjustment->value;
13535 if (new_value < dial->adjustment->lower)
13536 new_value = dial->adjustment->lower;
13538 if (new_value > dial->adjustment->upper)
13539 new_value = dial->adjustment->upper;
13541 if (new_value != dial->adjustment->value)
13543 dial->adjustment->value = new_value;
13544 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
13547 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
13548 (dial->adjustment->upper - dial->adjustment->lower);
13550 gtk_widget_draw (GTK_WIDGET(dial), NULL);
13554 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
13559 g_return_if_fail (adjustment != NULL);
13560 g_return_if_fail (data != NULL);
13562 dial = GTK_DIAL (data);
13564 if ((dial->old_value != adjustment->value) ||
13565 (dial->old_lower != adjustment->lower) ||
13566 (dial->old_upper != adjustment->upper))
13568 gtk_dial_update (dial);
13570 dial->old_value = adjustment->value;
13571 dial->old_lower = adjustment->lower;
13572 dial->old_upper = adjustment->upper;
13577 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
13582 g_return_if_fail (adjustment != NULL);
13583 g_return_if_fail (data != NULL);
13585 dial = GTK_DIAL (data);
13587 if (dial->old_value != adjustment->value)
13589 gtk_dial_update (dial);
13591 dial->old_value = adjustment->value;
13596 <!-- ----------------------------------------------------------------- -->
13597 <sect2> Posibles mejoras
13600 El <em/widget/ Dial tal y como lo hemos descrito tiene unas 670
13601 líneas de código. Aunque pueda parecer un poco exagerado, todavía
13602 no hemos escrito demasiado código, ya que la mayoría de las líneas
13603 son de ficheros de cabecera y de adornos. Todavía se le pueden hacer
13604 algunas mejoras a este <em/widget/:
13607 <item> Si prueba el <em/widget/, verá que el puntero cambia a
13608 pantallazos cuando se le arrastra. Esto es debido a que todo el
13609 <em/widget/ se borra cada vez que se mueve el puntero, antes de
13610 redibujarse. Normalmente, la mejor forma de tratar este problema es
13611 dibujar en un <em/pixmap/ que no represente lo que se ve directamente
13612 en pantalla, y copiar el resultado final en la pantalla en sólo un
13613 paso. (El <em/widget/ ProgressBar funciona de esta forma.)
13615 <item> El usuario debería ser capaz de utilizar las flechas de arriba
13616 y abajo para aumentar y decrementar el valor.
13618 <item> Sería bonito si el <em/widget/ tuviese botones para
13619 incrementar y decrementar el valor a saltos más o menos
13620 grandes. Es posible utilizar <em/widgets/ botón, aunque también
13621 queremos que los botones pudiesen realizar la operación de incrementar
13622 o decrementar varias veces, mientras se mantenga el botón pulsado, tal
13623 y como lo hacen las flechas en una barra de desplazamiento. La mayoría
13624 del código para implementar todo esto lo podemos encontrar en el
13625 <em/widget/ GtkRange.
13627 <item> El <em/widget/ Dial puede utilizarse en un <em/widget/
13628 contenedor con un simple <em/widget/ hijo colocado en la parte
13629 inferior entre los botones antes mencionados. El usuario puede añadir
13630 (según prefiera) una etiqueta o un <em/widget/ entry para mostrar el
13631 valor actual del marcador.
13635 <!-- ----------------------------------------------------------------- -->
13636 <sect1> Aprendiendo más
13639 Sólo se han descrito una pequeña parte de los muchos detalles
13640 involucrados en la creación de <em/widgets/, la mejor fuente de
13641 ejemplos es el código mismo de GTK. Hágase algunas preguntas acerca
13642 del <em/widget/ que desea crear: ¿es un <em/widget/ contenedor?
13643 ¿Debe tener su propia ventana? ¿Es una modificación de un
13644 <em/widget/ existente? En ese momento busque un <em/widget/ similar, y
13645 comience a hacer los cambios.
13648 <!-- ***************************************************************** -->
13649 <sect>Scribble, un sencillo programa de dibujo de ejemplo
13650 <!-- ***************************************************************** -->
13652 <!-- ----------------------------------------------------------------- -->
13656 En esta sección, vamos a crear un sencillo programa de dibujo. En el
13657 proceso, vamos a examinar como se manejan los eventos de ratón, como
13658 dibujar en una ventana, y como mejorar el dibujado utilizando un
13659 <em/pixmap/ intermedio. Después de crear el programa de dibujo, lo
13660 ampliaremos añadiendole la posibilidad de utilizar dispositivos
13661 XInput, como tabletas digitalizadoras. GTK proporciona las rutinas que
13662 nos darán la posibilidad de obtener información extra, como la presión
13663 y la inclinación, de todo tipo de dispositivos de una forma sencilla.
13665 <!-- ----------------------------------------------------------------- -->
13666 <sect1> Manejo de eventos
13669 Las señales GTK sobre las que ya hemos discutido son para las
13670 acciones de alto nivel, como cuando se selecciona un elemento de un
13671 menú. Sin embargo a veces es útil tratar con los acontecimientos a
13672 bajo nivel, como cuando se mueve el ratón, o cuando se está
13673 presionando una tecla. También hay señales GTK relacionadas con
13674 estos <em/eventos/ de bajo nivel. Los manejadores de estas señales
13675 tienen un parámetro extra que es un puntero a una estructura
13676 conteniendo información sobre el evento. Por ejemplo, a los manejadores
13677 de los eventos de movimiento se les pasa una estructura
13678 <tt/GdkEventMotion/ que es (en parte) así:
13681 struct _GdkEventMotion
13684 GdkWindow *ventana;
13694 <tt/type/ adquirirá su valor adecuado dependiendo del tipo de evento,
13695 en nuestro caso <tt/GDK_MOTION_NOTIFY/, <tt/ventana/ es la ventana en
13696 la que ocurre el evento. <tt/x/ e <tt/y/ dan las coordenadas del
13697 evento, y <tt/state/ especifica cual es la modificación que ha habido
13698 cuando ocurrió el evento (esto es, especifica que teclas han cambiado
13699 su estado y que botones del ratón se han presionado.) Es la
13700 operación OR (O) de algunos de los siguientes valores:
13719 Como con las otras señales, para especificar que es lo que pasa cuando
13720 ocurre un evento, llamaremos a <tt>gtk_signal_connect()</tt>. Pero
13721 también necesitamos decirle a GTK sobre que eventos queremos ser
13722 informados. Para ello, llamaremos a la función:
13725 void gtk_widget_set_events (GtkWidget *widget,
13729 El segundo campo especifica los eventos en los que estamos
13730 interesados. Es el OR (O) de las constantes que especifican los
13731 diferentes tipos de eventos. Por las referencias futuras que podamos
13732 hacer, presentamos aquí los tipos de eventos que hay disponibles:
13736 GDK_POINTER_MOTION_MASK
13737 GDK_POINTER_MOTION_HINT_MASK
13738 GDK_BUTTON_MOTION_MASK
13739 GDK_BUTTON1_MOTION_MASK
13740 GDK_BUTTON2_MOTION_MASK
13741 GDK_BUTTON3_MOTION_MASK
13742 GDK_BUTTON_PRESS_MASK
13743 GDK_BUTTON_RELEASE_MASK
13745 GDK_KEY_RELEASE_MASK
13746 GDK_ENTER_NOTIFY_MASK
13747 GDK_LEAVE_NOTIFY_MASK
13748 GDK_FOCUS_CHANGE_MASK
13750 GDK_PROPERTY_CHANGE_MASK
13751 GDK_PROXIMITY_IN_MASK
13752 GDK_PROXIMITY_OUT_MASK
13755 Hay unos cuantas sutilezas que debemos respetar cuando llamamos a
13756 <tt/gtk_widget_set_events()/. Primero, debemos llamar a esta función
13757 antes de que se cree la ventana X para el <em/widget/ GTK. En
13758 términos prácticos, significa que debemos llamarla inmediatamente
13759 después de crear el <em/widget/. Segundo, el <em/widget/ debe tener
13760 una ventana X asociado. Por motivos de eficiencia, hay muchos
13761 <em/widgets/ que no tienen su propia ventana, sino que dibujan en la
13762 de su padre. Estos <em/widgets/ son:
13784 Para capturar eventos para estos <em/widgets/, necesita utilizar un
13785 <em/widget/ EventBox. Vea la sección <ref
13786 id="sec_The_EventBox_Widget" name="El widget EventBox"> para más
13790 Para nuestro programa de dibujo, queremos saber cuando se presiona el
13791 botón del ratón y cuando se mueve, por lo que debemos especificar
13792 los eventos <tt/GDK_POINTER_MOTION_MASK/ y
13793 <tt/GDK_BUTTON_PRESS_MASK/. También queremos saber cuando necesitamos
13794 redibujar nuestra ventana, por lo que especificaremos el evento
13795 <tt/GDK_EXPOSURE_MASK/. Aunque queremos estar informados mediante un
13796 evento <tt/Configure/ cuando cambie el tamaño de nuestra ventana, no
13797 tenemos que especificar la correspondiente <tt/GDK_STRUCTURE_MASK/,
13798 porque ya está activada por defecto para todas las ventanas.
13801 Tenemos un problema con lo que acabamos de hacer, y tiene que ver con
13802 la utilización de <tt/GDK_POINTER_MOTION_MASK/. Si especificamos este
13803 evento, el servidor añadirá un evento de movimiento a la cola de
13804 eventos cada vez que el usuario mueva el ratón. Imagine que nos
13805 cuesta 0'1 segundo tratar el evento de movimiento, pero que el
13806 servidor X añade a la cola un nuevo evento de moviento cada 0'05
13807 segundos. Pronto nos iremos quedando retrasados con respecto al resto
13808 de los eventos. Si el usuario dibuja durante 5 segundos, ¡nos llevará
13809 otros 5 segundos el cazarle después de que hay levantado el botón
13810 del ratón! Lo que queremos es sólo un evento de movimiento por cada
13811 evento que procesemos. La manera de hacerlo es especificando
13812 <tt/GDK_POINTER_MOTION_HINT_MASK/.
13815 Cuando especificamos <tt/GDK_POINTER_MOTION_HINT_MASK/, el servidor
13816 nos envia un evento de movimiento la primera ver que el puntero se
13817 mueve depués de entrar en nuestra ventana, o después de que se
13818 apriete o se suelte un botón (y se reciba el evento
13819 correspondiente). Los eventos de movimiento restantes se eliminarán a
13820 no ser que preguntemos especificamente por la posición del puntero
13821 utilizando la función:
13824 GdkWindow* gdk_window_get_pointer (GdkWindow *ventana,
13827 GdkModifierType *mask);
13830 (Hay otra función, <tt>gtk_widget_get_pointer()</tt> que tiene una
13831 interfaz más sencillo, pero esta simplificación le resta utilidad, ya
13832 que sólo devuelve la posición del ratón, y no si alguno de sus botones
13836 El código para establecer los eventos para nuestra ventana es el
13840 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
13841 (GtkSignalFunc) expose_event, NULL);
13842 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
13843 (GtkSignalFunc) configure_event, NULL);
13844 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
13845 (GtkSignalFunc) motion_notify_event, NULL);
13846 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
13847 (GtkSignalFunc) button_press_event, NULL);
13849 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
13850 | GDK_LEAVE_NOTIFY_MASK
13851 | GDK_BUTTON_PRESS_MASK
13852 | GDK_POINTER_MOTION_MASK
13853 | GDK_POINTER_MOTION_HINT_MASK);
13856 Vamos a dejar los manejadores de los eventos <tt/expose_event/ y
13857 <tt/configure_event/ para después. Los manejadores de
13858 <tt/motion_notify_event/ y de <tt/button_press_event/ son bastante
13863 button_press_event (GtkWidget *widget, GdkEventButton *event)
13865 if (event->button == 1 && pixmap != NULL)
13866 draw_brush (widget, event->x, event->y);
13872 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13875 GdkModifierType state;
13877 if (event->is_hint)
13878 gdk_window_get_pointer (event->window, &x, &y, &state);
13883 state = event->state;
13886 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
13887 draw_brush (widget, x, y);
13893 <!-- ----------------------------------------------------------------- -->
13894 <sect1> El <em/widget/ DrawingArea, y dibujando
13897 Vamos a pasar al proceso de dibujar en la pantalla. El <em/widget/ que
13898 utilizaremos será el DrawingArea. Un <em/widget/ DrawingArea es
13899 esencialmente una ventana X y nada más. Es un lienzo en blanco en
13900 el que podemos dibujar lo que queramos. Crearemos un área de dibujo
13901 utilizando la llamada:
13904 GtkWidget* gtk_drawing_area_new (void);
13907 Se puede especificar un tamaño por defecto para el <em/widget/
13911 void gtk_drawing_area_size (GtkDrawingArea *darea,
13916 Se puede cambiar el tamaño por defecto, como para todos los
13917 <em/widgets/, llamando a <tt/gtk_widget_set_usize()/, y esto, además,
13918 puede cambiarse si el usuario cambia manualmente el tamaño de la
13919 ventana que contiene el área de dibujo.
13922 Debemos hacer notar que cuando creamos un <em/widget/ DrawingArea,
13923 seremos <em/completamente/ responsables de dibujar su contenido. Si
13924 nuestra ventana se tapa y se vuelve a poner al descubierto,
13925 obtendremos un evento de exposición y deberemos redibujar lo que se
13929 Tener que recordar todo lo que se dibujó en la pantalla para que
13930 podamos redibujarla convenientemente es, por decirlo de alguna manera
13931 suave, una locura. Además puede quedar mal si hay que borrar partes
13932 de la pantalla y hay que redibujarlas paso a paso. La solución a este
13933 problema es utilizar un <em>pixmap</em> intermedio. En lugar de
13934 dibujar directamente en la pantalla, dibujaremos en una imagen que
13935 estará almacenada en la memoria del servidor, pero que no se mostrará,
13936 y cuando cambie la imagen o se muestren nuevas partes de
13937 la misma, copiaremos las porciones relevantes en la pantalla.
13940 Para crear un <em/pixmap/ intermedio, llamaremos a la función:
13943 GdkPixmap* gdk_pixmap_new (GdkWindow *ventana,
13949 El parámetro <tt/widget/ especifica una ventana GDK de las que este
13950 <em/pixmap/ tomará algunas propiedades. <tt/width/ y <tt/height/
13951 especifican el tamaño del <em/pixmap/. <tt/depth/ especifica la
13952 <em/profundidad del color/, que es el número de bits por pixel de la
13953 nueva ventana. Si la profundidad que se especifica es <tt/-1/, se
13954 utilizará la misma profundidad de color que tenga la <tt/ventana/.
13957 Creamos nuestro <em/pixmap/ en nuestro manejador del evento
13958 <tt/configure_event/. Este evento se genera cada vez que cambia el
13959 tamaño de la ventana, incluyendo cuando ésta se crea.
13962 /* Backing pixmap for drawing area */
13963 static GdkPixmap *pixmap = NULL;
13965 /* Create a new backing pixmap of the appropriate size */
13967 configure_event (GtkWidget *widget, GdkEventConfigure *event)
13970 gdk_pixmap_unref(pixmap);
13972 pixmap = gdk_pixmap_new(widget->window,
13973 widget->allocation.width,
13974 widget->allocation.height,
13976 gdk_draw_rectangle (pixmap,
13977 widget->style->white_gc,
13980 widget->allocation.width,
13981 widget->allocation.height);
13987 La llamada a <tt/gdk_draw_rectangle()/ rellena todo el <em/pixmap/ de
13988 blanco. Hablaremos más de todo esto en un momento.
13991 Nuestro manejador del evento de exposición simplemente copia la
13992 porción relevante del <em/pixmap/ en la pantalla (determinaremos la
13993 zona a redibujar utilizando el campo <tt/event->area/ del evento de
13997 /* Redraw the screen from the backing pixmap */
13999 expose_event (GtkWidget *widget, GdkEventExpose *event)
14001 gdk_draw_pixmap(widget->window,
14002 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
14004 event->area.x, event->area.y,
14005 event->area.x, event->area.y,
14006 event->area.width, event->area.height);
14012 Ahora ya sabemos como mantener la pantalla actualizada con el
14013 contenido de nuestro <em/pixmap/, pero ¿cómo podemos dibujar algo
14014 interesante en nuestro <em/pixmap/? Hay un gran número de llamadas en
14015 la biblioteca GDK para dibujar en los <em/dibujables/. Un dibujable es
14016 simplemente algo sobre lo que se puede dibujar. Puede ser una ventana,
14017 un <em/pixmap/, un <em/bitmap/ (una imagen en blanco y negro), etc. Ya
14018 hemos visto arriba dos de estas llamadas,
14019 <tt>gdk_draw_rectangle()</tt> y <tt>gdk_draw_pixmap()</tt>. La lista
14020 completa de funciones para dibujar es:
14024 gdk_draw_rectangle ()
14026 gdk_draw_polygon ()
14033 gdk_draw_segments ()
14036 Ver la documentación de estas funciones o el fichero de cabecera
14037 <tt><gdk/gdk.h></tt> para obtener más detalles sobre estas
14038 funciones. Todas comparten los dos primeros argumentos. El primero es
14039 el dibujable en el que se dibujará, y el segundo argumento es un
14040 <em/contexto gráfico/ (GC).
14043 Un contexto gráfico reúne la información sobre cosas como el color
14044 de fondo y del color de lo que se dibuja, el ancho de la línea,
14045 etc... GDK tiene un conjunto completo de funciones para crear y
14046 modificar los contextos gráficos. Cada <em/widget/ tiene un GC
14047 asociado. (Que puede modificarse en un fichero gtkrc, ver la sección
14048 «Ficheros rc de GTK».) Estos, junto con otras cosas, almacenan
14049 GC's. Algunos ejemplos de como acceder a estos GC's son:
14052 widget->style->white_gc
14053 widget->style->black_gc
14054 widget->style->fg_gc[GTK_STATE_NORMAL]
14055 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
14058 Los campos <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, y
14059 <tt>light_gc</tt> se indexan con un parámetro del tipo
14060 <tt/GtkStateType/ que puede tomar uno de los valores:
14065 GTK_STATE_PRELIGHT,
14066 GTK_STATE_SELECTED,
14067 GTK_STATE_INSENSITIVE
14070 Por ejemplo, para el <tt/GTK_STATE_SELECTED/, el color que se utiliza
14071 para pintar por defecto es el blanco y el color del fondo por defecto,
14075 Nuestra función <tt/draw_brush()/, que es la que dibuja en la
14076 pantalla, será la siguiente:
14079 /* Draw a rectangle on the screen */
14081 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
14083 GdkRectangle update_rect;
14085 update_rect.x = x - 5;
14086 update_rect.y = y - 5;
14087 update_rect.width = 10;
14088 update_rect.height = 10;
14089 gdk_draw_rectangle (pixmap,
14090 widget->style->black_gc,
14092 update_rect.x, update_rect.y,
14093 update_rect.width, update_rect.height);
14094 gtk_widget_draw (widget, &update_rect);
14098 Después de que dibujemos el rectángulo representando la brocha en el
14099 <em/pixmap/ llamaremos a la función:
14102 void gtk_widget_draw (GtkWidget *widget,
14103 GdkRectangle *area);
14106 que le informa a X de que la zona dada por el parámetro <tt/area/
14107 necesita actualizarse. X generará un evento de exposición
14108 (combinando posiblemente distintas zonas pasadas mediante distintas
14109 llamadas a <tt/gtk_widget_draw()/) que hará que nuestro manejador de
14110 eventos de exposición copie las porciones relevantes en la pantalla.
14113 Ya hemos cubierto el programa de dibujo completo, excepto unos cuantos
14114 detalles mundanos como crear la ventana principal. El código completo
14115 está disponible en el mismo lugar en el que consiguió este tutorial,
14118 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
14119 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
14122 <!-- ----------------------------------------------------------------- -->
14123 <sect1> Añadiendo la capacidad de utilizar XInput
14126 Ahora es posible comprar dispositos de entrada bastante baratos, como
14127 tabletas digitalizadoras, que permiten dibujar de forma artística
14128 mucho más fácilmente de cómo lo haríamos con un ratón. La forma
14129 más sencilla de utilizar estos dispositivos es simplemente
14130 reemplazando a los ratones, pero así perdemos muchas de las ventajas
14131 de este tipo de dispositivos, como por ejemplo:
14134 <item> Sensibilidad a la presión
14135 <item> Información sobre la inclinación
14136 <item> Colocación subpixel
14137 <item> Multiples entradas (por ejemplo, un lápiz con una punta y una
14141 Para información sobre la extensión XInput, ver el <htmlurl
14142 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14143 name="XInput-HOWTO">.
14146 Si examinamos la definición completa de, por ejemplo, la estructura
14147 <tt/GdkEventMotion/, veremos que tiene campos para almacenar la
14148 información de los dispositivos extendidos.
14151 struct _GdkEventMotion
14154 GdkWindow *ventana;
14163 GdkInputSource source;
14168 <tt/pressure/ da la presión como un número de coma flotante entre 0
14169 y 1. <tt/xtilt/ e <tt/ytilt/ pueden tomar valores entre -1 y 1,
14170 correspondiendo al grado de inclinación en cada dirección. <tt/source/
14171 y <tt/deviceid/ especifican el dispositivo para el que ocurre el
14172 evento de dos maneras diferentes. <tt/source/ da alguna información
14173 simple sobre el tipo de dispositivo. Puede tomar los valores de la
14174 enumeración siguiente:
14183 <tt/deviceid/ especifica un número único ID para el dispositivo. Puede
14184 utilizarse para obtener más información sobre el dispositivo
14185 utilizando la función <tt/gdk_input_list_devices()/ (ver abajo). El
14186 valor especial <tt/GDK_CORE_POINTER/ se utiliza para el núcleo del
14187 dispositivo apuntador. (Normalmente el ratón.)
14189 <sect2> Activando la información del dispositivo extendido
14192 Para informar a GTK de nuestro interés en la información sobre los
14193 dispositivos extendidos, sólo tenemos que añadirle una línea a
14197 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
14200 Dando el valor <tt/GDK_EXTENSION_EVENTS_CURSOR/ decimos que estamos
14201 interesados en los eventos de extensión, pero sólo si no tenemos que
14202 dibujar nuestro propio cursor. Ver la sección <ref
14203 id="sec_Further_Sophistications" name="Sofisticaciones adicionales">
14204 más abajo para obtener más información sobre el dibujado del
14205 cursor. También podríamos dar los valores
14206 <tt/GDK_EXTENSION_EVENTS_ALL/ si queremos dibujar nuestro propio
14207 cursor, o <tt/GDK_EXTENSION_EVENTS_NONE/ para volver al estado
14211 Todavía no hemos llegado al final de la historia. Por defecto, no hay
14212 ningún dispositivo extra activado. Necesitamos un mecanismo que
14213 permita a los usuarios activar y configurar sus dispositivos
14214 extra. GTK proporciona el <em/widget/ InputDialog para automatizar el
14215 proceso. El siguiente procedimiento utiliza el <em/widget/
14216 InputDialog. Crea el cuadro de diálogo si no ha sido ya creado, y lo
14217 pone en primer plano en caso contrario.
14221 input_dialog_destroy (GtkWidget *w, gpointer data)
14223 *((GtkWidget **)data) = NULL;
14227 create_input_dialog ()
14229 static GtkWidget *inputd = NULL;
14233 inputd = gtk_input_dialog_new();
14235 gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
14236 (GtkSignalFunc)input_dialog_destroy, &inputd);
14237 gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
14239 (GtkSignalFunc)gtk_widget_hide,
14240 GTK_OBJECT(inputd));
14241 gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
14243 gtk_widget_show (inputd);
14247 if (!GTK_WIDGET_MAPPED(inputd))
14248 gtk_widget_show(inputd);
14250 gdk_window_raise(inputd->window);
14255 (Tome nota de la manera en que hemos manejado el cuadro de
14256 diálogo. Conectando la señal <tt/destroy/, nos aseguramos de que no
14257 tendremos un puntero al cuadro de diálogo después de que haya sido
14258 destruido, lo que nos podría llevar a un segfault.)
14261 El InputDialog tiene dos botones «Cerrar» y «Guardar», que por
14262 defecto no tienen ninguna acción asignada. En la función anterior
14263 hemos hecho que «Cerrar» oculte el cuadro de diálogo, ocultando el
14264 botón «Guardar», ya que no implementaremos en este programa la
14265 acción de guardar las opciones de XInput.
14267 <sect2> Utilizando la información de los dispositivos extras
14270 Una vez hemos activado el dispositivo, podemos utilizar la
14271 información que hay respecto a los dispositivos extendidos en los
14272 campos extras de las estructuras de los eventos. De hecho, es bueno
14273 utilizar esa información ya que esos campos tienen unos valores por
14274 defecto razonables aún cuando no se activen los eventos extendidos.
14277 Un cambio que tenemos que hacer es llamar a
14278 <tt/gdk_input_window_get_pointer()/ en vez de a
14279 <tt/gdk_window_get_pointer/. Esto es necesario porque
14280 <tt/gdk_window_get_pointer/ no devuelve la información de los
14281 dispositivos extra.
14284 void gdk_input_window_get_pointer (GdkWindow *ventana,
14291 GdkModifierType *mask);
14294 Cuando llamamos a esta función, necesitamos especificar tanto el ID
14295 del dispositivo como la ventana. Normalmente, obtendremos el ID del
14296 dispositivo del campo <tt/deviceid/ de una estructura de evento. De
14297 nuevo, esta función devolverá valores razonables cuando no estén
14298 activados los eventos extendidos. (En ese caso, <tt/event->deviceid/
14299 tendrá el valor <tt/GDK_CORE_POINTER/).
14301 Por tanto la estructura básica de nuestros manejadores de los
14302 eventos de movimiento y de pulsación del botón del ratón no
14303 cambiarán mucho - sólo tenemos que añadir código para manejar la
14308 button_press_event (GtkWidget *widget, GdkEventButton *event)
14310 print_button_press (event->deviceid);
14312 if (event->button == 1 && pixmap != NULL)
14313 draw_brush (widget, event->source, event->x, event->y, event->pressure);
14319 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
14323 GdkModifierType state;
14325 if (event->is_hint)
14326 gdk_input_window_get_pointer (event->window, event->deviceid,
14327 &x, &y, &pressure, NULL, NULL, &state);
14332 pressure = event->pressure;
14333 state = event->state;
14336 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
14337 draw_brush (widget, event->source, x, y, pressure);
14343 También tenemos que hacer algo con la nueva información. Nuestra
14344 nueva función <tt/draw_brush()/ dibuja con un color diferente
14345 dependiendo de <tt/event->source/ y cambia el tamaño de la brocha
14346 dependiendo de la presión.
14349 /* Draw a rectangle on the screen, size depending on pressure,
14350 and color on the type of device */
14352 draw_brush (GtkWidget *widget, GdkInputSource source,
14353 gdouble x, gdouble y, gdouble pressure)
14356 GdkRectangle update_rect;
14360 case GDK_SOURCE_MOUSE:
14361 gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
14363 case GDK_SOURCE_PEN:
14364 gc = widget->style->black_gc;
14366 case GDK_SOURCE_ERASER:
14367 gc = widget->style->white_gc;
14370 gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
14373 update_rect.x = x - 10 * pressure;
14374 update_rect.y = y - 10 * pressure;
14375 update_rect.width = 20 * pressure;
14376 update_rect.height = 20 * pressure;
14377 gdk_draw_rectangle (pixmap, gc, TRUE,
14378 update_rect.x, update_rect.y,
14379 update_rect.width, update_rect.height);
14380 gtk_widget_draw (widget, &update_rect);
14384 <sect2> Obteniendo más información de un dispositivo
14387 Como ejemplo de como podemos obtener más información de un
14388 dispositivo, nuestro programa imprimirá el nombre del dispositivo que
14389 genera cada pulsación de botón. Para encontrar el nombre de un
14390 dispositivo, llamaremos a la función:
14393 GList *gdk_input_list_devices (void);
14396 que devuelve una GList (una lista enlazada de la biblioteca glib)
14397 de estructuras <tt/GdkDeviceInfo/. La estructura <tt/GdkDeviceInfo/ se
14401 struct _GdkDeviceInfo
14405 GdkInputSource source;
14411 GdkDeviceKey *keys;
14415 Muchos de estos campos son información de configuración que puede
14416 ignorar, a menos que quiera permitir la opción de grabar la
14417 configuración de XInput. El campo que nos interesa ahora es <tt/name/
14418 que es simplemente el nombre que X le asigna al dispositivo. El otro
14419 campo que no tiene información sobre la configuración es
14420 <tt/has_cursor/. Si <tt/has_cursor/ es falso, tendremos que dibujar
14421 nuestro propio cursor. Pero como hemos especificado
14422 <tt/GDK_EXTENSION_EVENTS_CURSOR/, no tendremos que preocuparnos por
14426 Nuestra función <tt/print_button_press()/ simplemente recorre la
14427 lista devuelta hasta que encuentra una coincidencia, y entonces
14428 imprime el nombre del dispositivo.
14432 print_button_press (guint32 deviceid)
14436 /* gdk_input_list_devices returns an internal list, so we shouldn't
14437 free it afterwards */
14438 tmp_list = gdk_input_list_devices();
14442 GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
14444 if (info->deviceid == deviceid)
14446 printf("Button press on device '%s'\n", info->name);
14450 tmp_list = tmp_list->next;
14455 Con esto hemos completado los cambios para `XInputizar' nuestro
14456 programa. Como ocurría con la primera versión, el código completo se
14457 encuentra disponible en el mismo sitio donde obtuvo este tutorial, o
14460 <htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
14461 name="http://www.gtk.org/~otaylor/gtk/tutorial/">
14464 <sect2> Sofisticaciones adicionales <label id="sec_Further_Sophistications">
14467 Aunque ahora nuestro programa admite XInput bastante bien, todavía
14468 falla en algunas características que deberían estar disponibles en una
14469 aplicación bien hecha. Primero, el usuario no debería tener que
14470 configurar su dispositivo cada vez que ejecute el programa, por lo que
14471 debería estar disponible la opción de guardar la configuración del
14472 dispositivo. Esto se hace recorriendo el resultado de
14473 <tt/gdk_input_list_devices()/ y escribiendo la configuración en un
14477 Para cargar la configuración del dispositivo cuando se vuelva a
14478 ejecutar el programa, puede utilizar las funciones que proporciona GDK
14479 para cambiar la configuración de los dispositivos:
14482 gdk_input_set_extension_events()
14483 gdk_input_set_source()
14484 gdk_input_set_mode()
14485 gdk_input_set_axes()
14486 gdk_input_set_key()
14489 (La lista devuelta por <tt/gdk_input_list_devices()/ no debería
14490 modificarse directamente.) Podemos encontrar un ejemplo de como debe
14491 utilizarse en el programa de dibujo <tt/gsumi/. (Disponible en
14492 <htmlurl url="http://www.msc.cornell.edu/~otaylor/gsumi/"
14493 name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Estaría bien
14494 tener un procedimiento estándar para poder hacer todo esto en
14495 cualquier aplicaciones. Probablemente se llegue a esto en una capa
14496 superior a GTK, quizás en la biblioteca GNOME.
14499 El programa tiene otra carencia importante que ya hemos mencionado más
14500 arriba, y es la falta del cursor. Ninguna plataforma distinta de
14501 XFree86 permite utilizar simultaneamente un dispositivo como puntero
14502 núcleo y como dispositivo directamente utilizable por una
14503 aplicación. Ver el <url
14504 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
14505 name="XInput-HOWTO"> para más información sobre esto. Con esto
14506 queremos decir que si quiere tener la máxima audiencia necesita
14507 dibujar su propio cursor.
14510 Una aplicación que dibuja su propio cursor necesita hacer dos cosas:
14511 determinar si el dispositivo actual necesita que se dibuje un cursor o
14512 no, y determinar si el dispositivo está «próximo». (Si el
14513 dispositivo es una tableta digitalizadora, queda muy bonito que el
14514 cursor desaparezca cuando el lápiz se separa de la tableta. Cuando el
14515 lápiz está tocando la tableta, se dice que el dispositivo está
14516 «próximo»). Lo primero se hace buscando la lista de dispositivos,
14517 tal y como hicimos para encontrar el nombre del dispositivo. Lo
14518 segundo se consigue seleccionando los eventos
14519 <em/proximity_out/. Podemos encontrar un ejemplo de como dibujar
14520 nuestro propio cursor en el programa `testinput' que viene con la
14521 distribución de GTK.
14523 <!-- ***************************************************************** -->
14524 <sect>Trucos para escribir aplicaciones GTK
14525 <!-- ***************************************************************** -->
14528 Esta sección es sólo un compendio de sabiduria, de guías generales
14529 de estilo y de consejos para crear buenas aplicaciones GTK. Y es
14530 totalmente inútil por ahora ya que esta frase es sólo un tópico :)
14532 ¡Utilice GNU autoconf y automake! Son sus amigos :) Pretendo poner
14533 aquí una rápida introducción a ambos.
14535 <!-- ***************************************************************** -->
14536 <sect>Contribuyendo <label id="sec_Contributing">
14537 <!-- ***************************************************************** -->
14540 Este documento, como muchos otros grandes paquetes de programas que
14541 hay por ahí, fue creado de forma libre por voluntarios. Si comprende
14542 algo de GTK que todavía no se ha documentado, por favor piense en
14543 contribuir a este documento.
14546 Si decide contribuir, por favor mande un correo-e con su texto a Tony
14547 Gale, <tt><htmlurl url="mailto:gale@gtk.org"
14548 name="gale@gtk.org"></tt>. Recuerde que todas las partes que componen
14549 este documento son libre, y cualquier añadido que haga debe ser
14550 libre. Esto es, la gente debe de poder utilizar cualquier trozo de sus
14551 ejemplos en sus programas, podrán distribuir copias de su documento
14552 como deseen, etc...
14556 <!-- ***************************************************************** -->
14558 <!-- ***************************************************************** -->
14560 Quiero agradecer a las siguientes personas por sus contribuciones a
14564 <item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
14565 name="chamele0n@geocities.com"></tt> por el tutorial sobre los menús.
14567 <item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
14568 name="raph@acm.org"></tt> por el «hola mundo» a la GTK, el
14569 empaquetado de <em/widgets/, y su sabiduría general. Ha donado
14570 generosamente un hogar para este tutorial.
14572 <item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
14573 name="petm@xcf.berkeley.edu"></tt> por el más simple de los programas
14574 GTK... y por la posibilidad de hacerlo :)
14576 <item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
14577 name="werner.koch@guug.de"></tt> por convertir el texto original a
14578 SGML, y por la jerarquia de clases de <em/widgets/.
14580 <item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
14581 name="crichton@expert.cc.purdue.edu"></tt> por el código del menú
14582 factory, y el tutorial sobre el empaquetamiento de las tablas.
14584 <item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
14585 name="owt1@cornell.edu"></tt> por la sección sobre el <em/widget/
14586 EventBox (y el parche para el distro). También es el responsable
14587 del código de las selecciones y el tutorial, así como de la
14588 sección de escribiendo su propio <em/widget/ GTK, y la aplicación de
14589 ejemplo. ¡Muchas gracias por toda tu ayuda, Owen!
14591 <item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
14592 name="mvboom42@calvin.edu"></tt> por su fantástico trabajo sobre los
14593 <em/widgets/ Notebook, Progress Bar, Dialog, y selección de ficheros.
14594 ¡Muchas gracias Mark!
14595 Has sido de una gran ayuda.
14597 <item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
14598 name="timj@gtk.org"></tt> por su gran trabajo en el <em/widget/ List.
14601 <item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
14602 name="rajat@ix.netcom.com"</tt> por el excelente trabajo con el
14605 <item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
14606 name="johnsonm@redhat.com"></tt> por la información y el código de
14607 los menús ("popup").
14609 <item>David Huggins-Daines <tt><htmlurl url="mailto:bn711@freenet.carleton.ca"
14610 name="bn711@freenet.carleton.ca"></tt> por las secciones sobre los
14611 <em/widgets/ Range y Tree.
14613 <item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
14614 name="mars@lysator.liu.se"></tt> por la sección GtkCList
14617 Y a todos los que han comentado y ayudado a refinar este documento.
14621 <!-- ***************************************************************** -->
14622 <sect> Copyright del Tutorial y notas sobre los permisos
14623 <!-- ***************************************************************** -->
14626 Esta traducción está bajo la misma licencia bajo la que está
14627 el documento original. A continuación se presenta la traducción
14628 de la licencia y la licencia en versión original. En caso de haber
14629 alguna discrepancia entre la traducción y la licencia original, se
14630 aplicará esta última.
14632 El Tutorial GTK tiene Copyright (C) 1997 Ian Main.
14634 Copyright (C) 1998 Tony Gale.
14636 Se da permiso para hacer y distribuir copias idénticas de este manual
14637 siempre que se incluya el copyright en todas las copias.
14639 Se da permiso para copiar y distribuir versiones modificadas de este
14640 documento bajo las mismas condiciones que para las copias idénticas,
14641 siempre que el copyright se incluya exactamente tal y como se
14642 encuentra en el original, y que el trabajo completo derivado de este
14643 documento se distribuya bajo los términos de un permiso idéntico a
14646 Se da permiso para copiar y distribuir traducciones de este documento
14647 en otro lenguaje, bajo las condiciones arriba mencionadas para las
14648 versiones modificadas.
14650 Si se propone incluir este documento en un trabajo que vaya a ser
14651 impreso, por favor contacte con el encargado del mantenimiento, y
14652 haremos un esfuerzo para asegurarnos de que dispone de la información
14653 lo más actualizada posible.
14655 No hay ninguna garantia de que este documento se mantenga activo lo
14656 suficiente como para conseguir cumplir con su propósito. Se
14657 proporciona como un documento libre. Como tal, los autores y
14658 encargados del mantenimiento de la información que se da en el
14659 documento no pueden dar ninguna garantia de que la misma esté al día.
14661 -----------------------------
14663 The GTK Tutorial is Copyright (C) 1997 Ian Main.
14665 Copyright (C) 1998 Tony Gale.
14667 Permission is granted to make and distribute verbatim copies of this
14668 manual provided the copyright notice and this permission notice are
14669 preserved on all copies.
14670 <P>Permission is granted to copy and distribute modified versions of
14671 this document under the conditions for verbatim copying, provided that
14672 this copyright notice is included exactly as in the original,
14673 and that the entire resulting derived work is distributed under
14674 the terms of a permission notice identical to this one.
14675 <P>Permission is granted to copy and distribute translations of this
14676 document into another language, under the above conditions for modified
14678 <P>If you are intending to incorporate this document into a published
14679 work, please contact the maintainer, and we will make an effort
14680 to ensure that you have the most up to date information available.
14681 <P>There is no guarantee that this document lives up to its intended
14682 purpose. This is simply provided as a free resource. As such,
14683 the authors and maintainers of the information provided within can
14684 not make any guarantee that the information is even accurate.
14686 <sect1>Acerca de la traducción
14689 Esta traduccion tiene copyright (C) 1999 de Joaquín Cuenca Abela
14690 <tt><htmlurl url="mailto:e98cuenc@criens.u-psud.fr"
14691 name="<e98cuenc@criens.u-psud.fr>"></tt>
14692 y de Eduardo Anglada Varela
14693 <tt><htmlurl url="mailto:eduardo.anglada@adi.uam.es"
14694 name="<eduardo.anglada@adi.uam.es>"></tt>.
14696 duda, sugerencia o corrección no dude en consultarnos.
14698 Gracias a Manuel de Vega Barreiro <tt><htmlurl
14699 url="mailto:barreiro@arrakis.es"
14700 name="<barreiro@arrakis.es>"></tt> por haber hospedado las
14701 versiones beta y la versión actual de este tutorial en su página
14702 web Linux Landia <tt><url
14703 url="http://www.croftj.net/~barreiro/spain/gnome/"
14704 name="www.croftj.net/~barreiro/spain/gnome/"></tt>.
14708 <!-- ***************************************************************** -->
14710 <!-- ***************************************************************** -->
14712 <!-- ***************************************************************** -->
14713 <sect> Señales GTK <label id="sec_GTK_Signals">
14714 <!-- ***************************************************************** -->
14716 GTK+, al ser un conjunto de <em/widgets/ orientado al objeto, tiene
14717 una jerarquía de herencias. Este mecanismo de herencia se aplica a las
14718 señales. Por eso, debe utilizar el árbol de jerarquías de los
14719 <em/widgets/ cuando utilice las señales que aparecen en esta sección.
14721 <!-- ----------------------------------------------------------------- -->
14723 <!-- ----------------------------------------------------------------- -->
14726 void GtkObject::destroy (GtkObject *,
14730 <!-- ----------------------------------------------------------------- -->
14732 <!-- ----------------------------------------------------------------- -->
14736 void GtkWidget::show (GtkWidget *,
14738 void GtkWidget::hide (GtkWidget *,
14740 void GtkWidget::map (GtkWidget *,
14742 void GtkWidget::unmap (GtkWidget *,
14744 void GtkWidget::realize (GtkWidget *,
14746 void GtkWidget::unrealize (GtkWidget *,
14748 void GtkWidget::draw (GtkWidget *,
14751 void GtkWidget::draw-focus (GtkWidget *,
14753 void GtkWidget::draw-default (GtkWidget *,
14755 void GtkWidget::size-request (GtkWidget *,
14758 void GtkWidget::size-allocate (GtkWidget *,
14761 void GtkWidget::state-changed (GtkWidget *,
14764 void GtkWidget::parent-set (GtkWidget *,
14767 void GtkWidget::style-set (GtkWidget *,
14770 void GtkWidget::add-accelerator (GtkWidget *,
14777 void GtkWidget::remove-accelerator (GtkWidget *,
14782 gboolean GtkWidget::event (GtkWidget *,
14785 gboolean GtkWidget::button-press-event (GtkWidget *,
14788 gboolean GtkWidget::button-release-event (GtkWidget *,
14791 gboolean GtkWidget::motion-notify-event (GtkWidget *,
14794 gboolean GtkWidget::delete-event (GtkWidget *,
14797 gboolean GtkWidget::destroy-event (GtkWidget *,
14800 gboolean GtkWidget::expose-event (GtkWidget *,
14803 gboolean GtkWidget::key-press-event (GtkWidget *,
14806 gboolean GtkWidget::key-release-event (GtkWidget *,
14809 gboolean GtkWidget::enter-notify-event (GtkWidget *,
14812 gboolean GtkWidget::leave-notify-event (GtkWidget *,
14815 gboolean GtkWidget::configure-event (GtkWidget *,
14818 gboolean GtkWidget::focus-in-event (GtkWidget *,
14821 gboolean GtkWidget::focus-out-event (GtkWidget *,
14824 gboolean GtkWidget::map-event (GtkWidget *,
14827 gboolean GtkWidget::unmap-event (GtkWidget *,
14830 gboolean GtkWidget::property-notify-event (GtkWidget *,
14833 gboolean GtkWidget::selection-clear-event (GtkWidget *,
14836 gboolean GtkWidget::selection-request-event (GtkWidget *,
14839 gboolean GtkWidget::selection-notify-event (GtkWidget *,
14842 void GtkWidget::selection-get (GtkWidget *,
14843 GtkSelectionData *,
14846 void GtkWidget::selection-received (GtkWidget *,
14847 GtkSelectionData *,
14850 gboolean GtkWidget::proximity-in-event (GtkWidget *,
14853 gboolean GtkWidget::proximity-out-event (GtkWidget *,
14856 void GtkWidget::drag-begin (GtkWidget *,
14859 void GtkWidget::drag-end (GtkWidget *,
14862 void GtkWidget::drag-data-delete (GtkWidget *,
14865 void GtkWidget::drag-leave (GtkWidget *,
14869 gboolean GtkWidget::drag-motion (GtkWidget *,
14875 gboolean GtkWidget::drag-drop (GtkWidget *,
14881 void GtkWidget::drag-data-get (GtkWidget *,
14883 GtkSelectionData *,
14887 void GtkWidget::drag-data-received (GtkWidget *,
14891 GtkSelectionData *,
14895 gboolean GtkWidget::client-event (GtkWidget *,
14898 gboolean GtkWidget::no-expose-event (GtkWidget *,
14901 gboolean GtkWidget::visibility-notify-event (GtkWidget *,
14904 void GtkWidget::debug-msg (GtkWidget *,
14909 <!-- ----------------------------------------------------------------- -->
14911 <!-- ----------------------------------------------------------------- -->
14914 void GtkData::disconnect (GtkData *,
14918 <!-- ----------------------------------------------------------------- -->
14919 <sect1>GtkContainer
14920 <!-- ----------------------------------------------------------------- -->
14923 void GtkContainer::add (GtkContainer *,
14926 void GtkContainer::remove (GtkContainer *,
14929 void GtkContainer::check-resize (GtkContainer *,
14931 GtkDirectionType GtkContainer::focus (GtkContainer *,
14934 void GtkContainer::set-focus-child (GtkContainer *,
14939 <!-- ----------------------------------------------------------------- -->
14941 <!-- ----------------------------------------------------------------- -->
14944 void GtkCalendar::month-changed (GtkCalendar *,
14946 void GtkCalendar::day-selected (GtkCalendar *,
14948 void GtkCalendar::day-selected-double-click (GtkCalendar *,
14950 void GtkCalendar::prev-month (GtkCalendar *,
14952 void GtkCalendar::next-month (GtkCalendar *,
14954 void GtkCalendar::prev-year (GtkCalendar *,
14956 void GtkCalendar::next-year (GtkCalendar *,
14960 <!-- ----------------------------------------------------------------- -->
14962 <!-- ----------------------------------------------------------------- -->
14965 void GtkEditable::changed (GtkEditable *,
14967 void GtkEditable::insert-text (GtkEditable *,
14972 void GtkEditable::delete-text (GtkEditable *,
14976 void GtkEditable::activate (GtkEditable *,
14978 void GtkEditable::set-editable (GtkEditable *,
14981 void GtkEditable::move-cursor (GtkEditable *,
14985 void GtkEditable::move-word (GtkEditable *,
14988 void GtkEditable::move-page (GtkEditable *,
14992 void GtkEditable::move-to-row (GtkEditable *,
14995 void GtkEditable::move-to-column (GtkEditable *,
14998 void GtkEditable::kill-char (GtkEditable *,
15001 void GtkEditable::kill-word (GtkEditable *,
15004 void GtkEditable::kill-line (GtkEditable *,
15007 void GtkEditable::cut-clipboard (GtkEditable *,
15009 void GtkEditable::copy-clipboard (GtkEditable *,
15011 void GtkEditable::paste-clipboard (GtkEditable *,
15015 <!-- ----------------------------------------------------------------- -->
15016 <sect1>GtkTipsQuery
15017 <!-- ----------------------------------------------------------------- -->
15020 void GtkTipsQuery::start-query (GtkTipsQuery *,
15022 void GtkTipsQuery::stop-query (GtkTipsQuery *,
15024 void GtkTipsQuery::widget-entered (GtkTipsQuery *,
15029 gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
15037 <!-- ----------------------------------------------------------------- -->
15039 <!-- ----------------------------------------------------------------- -->
15042 void GtkCList::select-row (GtkCList *,
15047 void GtkCList::unselect-row (GtkCList *,
15052 void GtkCList::row-move (GtkCList *,
15056 void GtkCList::click-column (GtkCList *,
15059 void GtkCList::resize-column (GtkCList *,
15063 void GtkCList::toggle-focus-row (GtkCList *,
15065 void GtkCList::select-all (GtkCList *,
15067 void GtkCList::unselect-all (GtkCList *,
15069 void GtkCList::undo-selection (GtkCList *,
15071 void GtkCList::start-selection (GtkCList *,
15073 void GtkCList::end-selection (GtkCList *,
15075 void GtkCList::toggle-add-mode (GtkCList *,
15077 void GtkCList::extend-selection (GtkCList *,
15082 void GtkCList::scroll-vertical (GtkCList *,
15086 void GtkCList::scroll-horizontal (GtkCList *,
15090 void GtkCList::abort-column-resize (GtkCList *,
15094 <!-- ----------------------------------------------------------------- -->
15096 <!-- ----------------------------------------------------------------- -->
15099 void GtkNotebook::switch-page (GtkNotebook *,
15106 <!-- ----------------------------------------------------------------- -->
15108 <!-- ----------------------------------------------------------------- -->
15111 void GtkList::selection-changed (GtkList *,
15113 void GtkList::select-child (GtkList *,
15116 void GtkList::unselect-child (GtkList *,
15121 <!-- ----------------------------------------------------------------- -->
15122 <sect1>GtkMenuShell
15123 <!-- ----------------------------------------------------------------- -->
15126 void GtkMenuShell::deactivate (GtkMenuShell *,
15128 void GtkMenuShell::selection-done (GtkMenuShell *,
15130 void GtkMenuShell::move-current (GtkMenuShell *,
15131 GtkMenuDirectionType,
15133 void GtkMenuShell::activate-current (GtkMenuShell *,
15136 void GtkMenuShell::cancel (GtkMenuShell *,
15140 <!-- ----------------------------------------------------------------- -->
15142 <!-- ----------------------------------------------------------------- -->
15145 void GtkToolbar::orientation-changed (GtkToolbar *,
15148 void GtkToolbar::style-changed (GtkToolbar *,
15153 <!-- ----------------------------------------------------------------- -->
15155 <!-- ----------------------------------------------------------------- -->
15158 void GtkTree::selection-changed (GtkTree *,
15160 void GtkTree::select-child (GtkTree *,
15163 void GtkTree::unselect-child (GtkTree *,
15168 <!-- ----------------------------------------------------------------- -->
15170 <!-- ----------------------------------------------------------------- -->
15173 void GtkButton::pressed (GtkButton *,
15175 void GtkButton::released (GtkButton *,
15177 void GtkButton::clicked (GtkButton *,
15179 void GtkButton::enter (GtkButton *,
15181 void GtkButton::leave (GtkButton *,
15185 <!-- ----------------------------------------------------------------- -->
15187 <!-- ----------------------------------------------------------------- -->
15190 void GtkItem::select (GtkItem *,
15192 void GtkItem::deselect (GtkItem *,
15194 void GtkItem::toggle (GtkItem *,
15198 <!-- ----------------------------------------------------------------- -->
15200 <!-- ----------------------------------------------------------------- -->
15203 void GtkWindow::set-focus (GtkWindow *,
15208 <!-- ----------------------------------------------------------------- -->
15209 <sect1>GtkHandleBox
15210 <!-- ----------------------------------------------------------------- -->
15213 void GtkHandleBox::child-attached (GtkHandleBox *,
15216 void GtkHandleBox::child-detached (GtkHandleBox *,
15221 <!-- ----------------------------------------------------------------- -->
15222 <sect1>GtkToggleButton
15223 <!-- ----------------------------------------------------------------- -->
15226 void GtkToggleButton::toggled (GtkToggleButton *,
15231 <!-- ----------------------------------------------------------------- -->
15233 <!-- ----------------------------------------------------------------- -->
15236 void GtkMenuItem::activate (GtkMenuItem *,
15238 void GtkMenuItem::activate-item (GtkMenuItem *,
15242 <!-- ----------------------------------------------------------------- -->
15244 <!-- ----------------------------------------------------------------- -->
15247 void GtkListItem::toggle-focus-row (GtkListItem *,
15249 void GtkListItem::select-all (GtkListItem *,
15251 void GtkListItem::unselect-all (GtkListItem *,
15253 void GtkListItem::undo-selection (GtkListItem *,
15255 void GtkListItem::start-selection (GtkListItem *,
15257 void GtkListItem::end-selection (GtkListItem *,
15259 void GtkListItem::toggle-add-mode (GtkListItem *,
15261 void GtkListItem::extend-selection (GtkListItem *,
15266 void GtkListItem::scroll-vertical (GtkListItem *,
15270 void GtkListItem::scroll-horizontal (GtkListItem *,
15276 <!-- ----------------------------------------------------------------- -->
15278 <!-- ----------------------------------------------------------------- -->
15281 void GtkTreeItem::collapse (GtkTreeItem *,
15283 void GtkTreeItem::expand (GtkTreeItem *,
15287 <!-- ----------------------------------------------------------------- -->
15288 <sect1>GtkCheckMenuItem
15289 <!-- ----------------------------------------------------------------- -->
15292 void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
15296 <!-- ----------------------------------------------------------------- -->
15297 <sect1>GtkInputDialog
15298 <!-- ----------------------------------------------------------------- -->
15301 void GtkInputDialog::enable-device (GtkInputDialog *,
15304 void GtkInputDialog::disable-device (GtkInputDialog *,
15309 <!-- ----------------------------------------------------------------- -->
15310 <sect1>GtkColorSelection
15311 <!-- ----------------------------------------------------------------- -->
15314 void GtkColorSelection::color-changed (GtkColorSelection *,
15318 <!-- ----------------------------------------------------------------- -->
15319 <sect1>GtkStatusBar
15320 <!-- ----------------------------------------------------------------- -->
15323 void GtkStatusbar::text-pushed (GtkStatusbar *,
15327 void GtkStatusbar::text-popped (GtkStatusbar *,
15333 <!-- ----------------------------------------------------------------- -->
15335 <!-- ----------------------------------------------------------------- -->
15338 void GtkCTree::tree-select-row (GtkCTree *,
15342 void GtkCTree::tree-unselect-row (GtkCTree *,
15346 void GtkCTree::tree-expand (GtkCTree *,
15349 void GtkCTree::tree-collapse (GtkCTree *,
15352 void GtkCTree::tree-move (GtkCTree *,
15357 void GtkCTree::change-focus-row-expansion (GtkCTree *,
15358 GtkCTreeExpansionType,
15362 <!-- ----------------------------------------------------------------- -->
15364 <!-- ----------------------------------------------------------------- -->
15367 void GtkCurve::curve-type-changed (GtkCurve *,
15371 <!-- ----------------------------------------------------------------- -->
15372 <sect1>GtkAdjustment
15373 <!-- ----------------------------------------------------------------- -->
15376 void GtkAdjustment::changed (GtkAdjustment *,
15378 void GtkAdjustment::value-changed (GtkAdjustment *,
15382 <!-- ***************************************************************** -->
15383 <sect> Tipos de eventos GDK<label id="sec_GDK_Event_Types">
15384 <!-- ***************************************************************** -->
15386 Los siguientes tipos de datos se pasan en los manejadores de los
15387 eventos por GTK+. Para cada tipo de dato que se muestra, se muestran
15388 las señales que utilizan ese tipo de dato.
15393 <item>drag_end_event
15396 <item> GdkEventType
15401 <item>destroy_event
15404 <item>no_expose_event
15407 <item> GdkEventExpose
15412 <item> GdkEventNoExpose
15414 <item> GdkEventVisibility
15416 <item> GdkEventMotion
15418 <item>motion_notify_event
15421 <item> GdkEventButton
15423 <item>button_press_event
15424 <item>button_release_event
15429 <item>key_press_event
15430 <item>key_release_event
15433 <item> GdkEventCrossing
15435 <item>enter_notify_event
15436 <item>leave_notify_event
15439 <item> GdkEventFocus
15441 <item>focus_in_event
15442 <item>focus_out_event
15445 <item> GdkEventConfigure
15447 <item>configure_event
15450 <item> GdkEventProperty
15452 <item>property_notify_event
15455 <item> GdkEventSelection
15457 <item>selection_clear_event
15458 <item>selection_request_event
15459 <item>selection_notify_event
15462 <item> GdkEventProximity
15464 <item>proximity_in_event
15465 <item>proximity_out_event
15468 <item> GdkEventDragBegin
15470 <item>drag_begin_event
15473 <item> GdkEventDragRequest
15475 <item>drag_request_event
15478 <item> GdkEventDropEnter
15480 <item>drop_enter_event
15483 <item> GdkEventDropLeave
15485 <item>drop_leave_event
15488 <item> GdkEventDropDataAvailable
15490 <item>drop_data_available_event
15493 <item> GdkEventClient
15498 <item> GdkEventOther
15504 El tipo de dato <tt/GdkEventType/ es un tipo de dato especial que se
15505 utiliza por todos los otros tipos de datos como un indicador del tipo
15506 de dato que se le está pasando al manejador de señal. Como verá
15507 más adelante, cada una de estructuras de los datos de los eventos
15508 tienen un miembro de este tipo. Se define como la siguiente
15518 GDK_MOTION_NOTIFY = 3,
15519 GDK_BUTTON_PRESS = 4,
15520 GDK_2BUTTON_PRESS = 5,
15521 GDK_3BUTTON_PRESS = 6,
15522 GDK_BUTTON_RELEASE = 7,
15524 GDK_KEY_RELEASE = 9,
15525 GDK_ENTER_NOTIFY = 10,
15526 GDK_LEAVE_NOTIFY = 11,
15527 GDK_FOCUS_CHANGE = 12,
15528 GDK_CONFIGURE = 13,
15531 GDK_PROPERTY_NOTIFY = 16,
15532 GDK_SELECTION_CLEAR = 17,
15533 GDK_SELECTION_REQUEST = 18,
15534 GDK_SELECTION_NOTIFY = 19,
15535 GDK_PROXIMITY_IN = 20,
15536 GDK_PROXIMITY_OUT = 21,
15537 GDK_DRAG_BEGIN = 22,
15538 GDK_DRAG_REQUEST = 23,
15539 GDK_DROP_ENTER = 24,
15540 GDK_DROP_LEAVE = 25,
15541 GDK_DROP_DATA_AVAIL = 26,
15542 GDK_CLIENT_EVENT = 27,
15543 GDK_VISIBILITY_NOTIFY = 28,
15544 GDK_NO_EXPOSE = 29,
15545 GDK_OTHER_EVENT = 9999 /* Anacrónico, utilice en su lugar los
15550 El otro tipo de evento que es diferente del resto es el mismo
15551 <tt/GdkEvent/. Ésta es una unión de todos los otros tipos de
15552 datos, que permite que se convierta en un tipo de dato de evento
15553 específico con un manejador de señal.
15555 <!-- Just a big list for now, needs expanding upon - TRG -->
15556 Por tanto, los tipos de los datos de los eventos se definen como
15560 struct _GdkEventAny
15567 struct _GdkEventExpose
15573 gint count; /* Si count no es, entonces es el número de eventos que
15577 struct _GdkEventNoExpose
15582 /* XXX: ¿Hay alguien que necesite los campos major_code y minor_code
15586 struct _GdkEventVisibility
15591 GdkVisibilityState state;
15594 struct _GdkEventMotion
15607 GdkInputSource source;
15609 gdouble x_root, y_root;
15612 struct _GdkEventButton
15625 GdkInputSource source;
15627 gdouble x_root, y_root;
15630 struct _GdkEventKey
15642 struct _GdkEventCrossing
15647 GdkWindow *subwindow;
15648 GdkNotifyType detail;
15651 struct _GdkEventFocus
15659 struct _GdkEventConfigure
15669 struct _GdkEventProperty
15679 struct _GdkEventSelection
15691 /* Este tipo de evento se utiliza muy raramente. Solamente es
15692 * importante para los programas que utilizan XInput y que dibujar su
15695 struct _GdkEventProximity
15701 GdkInputSource source;
15705 struct _GdkEventDragRequest
15713 guint protocol_version:4;
15715 guint willaccept:1;
15716 guint delete_data:1; /* No borrar si se ha mandado un enlace,
15717 sólo si se ha mandado el dato */
15723 guint8 isdrop; /* Este evento gdk puede ser generado por un par de
15724 eventos X - esto le permite a las aplicaciones
15725 saber si ha ocurrido realmente el soltado (drop),
15726 o si sólo hemos cambiado el valor de algunos datos
15729 GdkPoint drop_coords;
15734 struct _GdkEventDragBegin
15741 guint protocol_version:4;
15748 struct _GdkEventDropEnter
15756 guint protocol_version:4;
15758 guint extended_typelist:1;
15765 struct _GdkEventDropLeave
15773 guint protocol_version:4;
15780 struct _GdkEventDropDataAvailable
15788 guint protocol_version:4;
15794 gchar *data_type; /* tipo MIME */
15795 gulong data_numbytes;
15801 struct _GdkEventClient
15806 GdkAtom message_type;
15807 gushort data_format;
15815 struct _GdkEventOther
15824 <!-- ***************************************************************** -->
15825 <sect> Código ejemplo
15826 <!-- ***************************************************************** -->
15828 A continuación tenemos el código ejemplo que se ha utilizado en el
15829 texto anterior y que no se ha incluido al completo en otro lugar.
15831 <!-- ----------------------------------------------------------------- -->
15833 <!-- ----------------------------------------------------------------- -->
15837 /* principio del ejemplo tictactoe tictactoe.h */
15839 /* GTK - The GIMP Toolkit
15840 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15842 * This library is free software; you can redistribute it and/or
15843 * modify it under the terms of the GNU Library General Public
15844 * License as published by the Free Software Foundation; either
15845 * version 2 of the License, or (at your option) any later version.
15847 * This library is distributed in the hope that it will be useful,
15848 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15849 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15850 * Library General Public License for more details.
15852 * You should have received a copy of the GNU Library General Public
15853 * License along with this library; if not, write to the
15854 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15855 * Boston, MA 02111-1307, USA.
15857 #ifndef __TICTACTOE_H__
15858 #define __TICTACTOE_H__
15861 #include <gdk/gdk.h>
15862 #include <gtk/gtkvbox.h>
15867 #endif /* __cplusplus */
15869 #define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
15870 #define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
15871 #define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
15874 typedef struct _Tictactoe Tictactoe;
15875 typedef struct _TictactoeClass TictactoeClass;
15881 GtkWidget *botones[3][3];
15884 struct _TictactoeClass
15886 GtkVBoxClass parent_class;
15888 void (* tictactoe) (Tictactoe *ttt);
15891 guint tictactoe_get_type (void);
15892 GtkWidget* tictactoe_new (void);
15893 void tictactoe_clear (Tictactoe *ttt);
15897 #endif /* __cplusplus */
15899 #endif /* __TICTACTOE_H__ */
15901 /* fin del ejemplo */
15904 <!-- ----------------------------------------------------------------- -->
15908 /* principio del ejemplo tictactoe tictactoe.c */
15910 /* GTK - The GIMP Toolkit
15911 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15913 * This library is free software; you can redistribute it and/or
15914 * modify it under the terms of the GNU Library General Public
15915 * License as published by the Free Software Foundation; either
15916 * version 2 of the License, or (at your option) any later version.
15918 * This library is distributed in the hope that it will be useful,
15919 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15920 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15921 * Library General Public License for more details.
15923 * You should have received a copy of the GNU Library General Public
15924 * License along with this library; if not, write to the
15925 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15926 * Boston, MA 02111-1307, USA.
15928 #include "gtk/gtksignal.h"
15929 #include "gtk/gtktable.h"
15930 #include "gtk/gtktogglebutton.h"
15931 #include "tictactoe.h"
15938 static void tictactoe_class_init (TictactoeClass *klass);
15939 static void tictactoe_init (Tictactoe *ttt);
15940 static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
15942 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
15945 tictactoe_get_type ()
15947 static guint ttt_type = 0;
15951 GtkTypeInfo ttt_info =
15954 sizeof (Tictactoe),
15955 sizeof (TictactoeClass),
15956 (GtkClassInitFunc) tictactoe_class_init,
15957 (GtkObjectInitFunc) tictactoe_init,
15958 (GtkArgSetFunc) NULL,
15959 (GtkArgGetFunc) NULL
15962 ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
15969 tictactoe_class_init (TictactoeClass *class)
15971 GtkObjectClass *object_class;
15973 object_class = (GtkObjectClass*) class;
15975 tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
15977 object_class->type,
15978 GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
15979 gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
15982 gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
15984 class->tictactoe = NULL;
15988 tictactoe_init (Tictactoe *ttt)
15993 table = gtk_table_new (3, 3, TRUE);
15994 gtk_container_add (GTK_CONTAINER(ttt), table);
15995 gtk_widget_show (table);
16000 ttt->buttons[i][j] = gtk_toggle_button_new ();
16001 gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
16003 gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
16004 GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
16005 gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
16006 gtk_widget_show (ttt->buttons[i][j]);
16013 return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
16017 tictactoe_clear (Tictactoe *ttt)
16024 gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
16025 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
16027 gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
16032 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
16036 static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
16037 { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
16038 { 0, 1, 2 }, { 0, 1, 2 } };
16039 static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
16040 { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
16041 { 0, 1, 2 }, { 2, 1, 0 } };
16043 int success, found;
16045 for (k=0; k<8; k++)
16052 success = success &&
16053 GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
16055 ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
16058 if (success && found)
16060 gtk_signal_emit (GTK_OBJECT (ttt),
16061 tictactoe_signals[TICTACTOE_SIGNAL]);
16067 /* fin del ejemplo */
16070 <!-- ----------------------------------------------------------------- -->
16074 /* principio del ejemplo tictactoe ttt_test.c */
16076 #include <gtk/gtk.h>
16077 #include "tictactoe.h"
16080 win (GtkWidget *widget, gpointer data)
16082 g_print ("Yay!\n");
16083 tictactoe_clear (TICTACTOE (widget));
16087 main (int argc, char *argv[])
16089 GtkWidget *ventana;
16092 gtk_init (&argc, &argv);
16094 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16096 gtk_window_set_title (GTK_WINDOW (ventana), "Aspect Frame");
16098 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
16099 GTK_SIGNAL_FUNC (gtk_exit), NULL);
16101 gtk_container_border_width (GTK_CONTAINER (ventana), 10);
16103 ttt = tictactoe_new ();
16105 gtk_container_add (GTK_CONTAINER (ventana), ttt);
16106 gtk_widget_show (ttt);
16108 gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
16109 GTK_SIGNAL_FUNC (win), NULL);
16111 gtk_widget_show (ventana);
16118 /* fin del ejemplo */
16121 <!-- ----------------------------------------------------------------- -->
16124 <!-- ----------------------------------------------------------------- -->
16128 /* principio del ejmplo gtkdial gtkdial.h */
16130 /* GTK - The GIMP Toolkit
16131 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16133 * This library is free software; you can redistribute it and/or
16134 * modify it under the terms of the GNU Library General Public
16135 * License as published by the Free Software Foundation; either
16136 * version 2 of the License, or (at your option) any later version.
16138 * This library is distributed in the hope that it will be useful,
16139 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16140 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16141 * Library General Public License for more details.
16143 * You should have received a copy of the GNU Library General Public
16144 * License along with this library; if not, write to the
16145 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16146 * Boston, MA 02111-1307, USA.
16148 #ifndef __GTK_DIAL_H__
16149 #define __GTK_DIAL_H__
16152 #include <gdk/gdk.h>
16153 #include <gtk/gtkadjustment.h>
16154 #include <gtk/gtkwidget.h>
16159 #endif /* __cplusplus */
16162 #define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
16163 #define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
16164 #define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
16167 typedef struct _GtkDial GtkDial;
16168 typedef struct _GtkDialClass GtkDialClass;
16174 /* política de actualización
16175 * (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
16178 /* Botón actualmente presionado o 0 si no hay ninguno */
16181 /* Dimensión de los componendes del dial */
16183 gint pointer_width;
16185 /* ID del temporizador de actualización, o 0 si no hay ninguno */
16188 /* ángulo actual */
16191 /* Viejos valores almacenados del adjustment, para que así no
16192 * tengamos que saber cuando cambia algo */
16197 /* El objeto adjustment que almacena los datos para este dial */
16198 GtkAdjustment *adjustment;
16201 struct _GtkDialClass
16203 GtkWidgetClass parent_class;
16207 GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
16208 guint gtk_dial_get_type (void);
16209 GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
16210 void gtk_dial_set_update_policy (GtkDial *dial,
16211 GtkUpdateType policy);
16213 void gtk_dial_set_adjustment (GtkDial *dial,
16214 GtkAdjustment *adjustment);
16217 #endif /* __cplusplus */
16220 #endif /* __GTK_DIAL_H__ */
16221 /* fin del ejemplo */
16224 <!-- ----------------------------------------------------------------- -->
16228 /* principio del ejemplo gtkdial gtkdial.c */
16230 /* GTK - The GIMP Toolkit
16231 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16233 * This library is free software; you can redistribute it and/or
16234 * modify it under the terms of the GNU Library General Public
16235 * License as published by the Free Software Foundation; either
16236 * version 2 of the License, or (at your option) any later version.
16238 * This library is distributed in the hope that it will be useful,
16239 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16240 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16241 * Library General Public License for more details.
16243 * You should have received a copy of the GNU Library General Public
16244 * License along with this library; if not, write to the
16245 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16246 * Boston, MA 02111-1307, USA.
16250 #include <gtk/gtkmain.h>
16251 #include <gtk/gtksignal.h>
16253 #include "gtkdial.h"
16255 #define SCROLL_DELAY_LENGTH 300
16256 #define DIAL_DEFAULT_SIZE 100
16258 /* declaraciones de funciones */
16260 static void gtk_dial_class_init (GtkDialClass *klass);
16261 static void gtk_dial_init (GtkDial *dial);
16262 static void gtk_dial_destroy (GtkObject *object);
16263 static void gtk_dial_realize (GtkWidget *widget);
16264 static void gtk_dial_size_request (GtkWidget *widget,
16265 GtkRequisition *requisition);
16266 static void gtk_dial_size_allocate (GtkWidget *widget,
16267 GtkAllocation *allocation);
16268 static gint gtk_dial_expose (GtkWidget *widget,
16269 GdkEventExpose *event);
16270 static gint gtk_dial_button_press (GtkWidget *widget,
16271 GdkEventButton *event);
16272 static gint gtk_dial_button_release (GtkWidget *widget,
16273 GdkEventButton *event);
16274 static gint gtk_dial_motion_notify (GtkWidget *widget,
16275 GdkEventMotion *event);
16276 static gint gtk_dial_timer (GtkDial *dial);
16278 static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
16279 static void gtk_dial_update (GtkDial *dial);
16280 static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16282 static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16285 /* datos locales */
16287 static GtkWidgetClass *parent_class = NULL;
16290 gtk_dial_get_type ()
16292 static guint dial_type = 0;
16296 GtkTypeInfo dial_info =
16300 sizeof (GtkDialClass),
16301 (GtkClassInitFunc) gtk_dial_class_init,
16302 (GtkObjectInitFunc) gtk_dial_init,
16303 (GtkArgSetFunc) NULL,
16304 (GtkArgGetFunc) NULL,
16307 dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
16314 gtk_dial_class_init (GtkDialClass *class)
16316 GtkObjectClass *object_class;
16317 GtkWidgetClass *widget_class;
16319 object_class = (GtkObjectClass*) class;
16320 widget_class = (GtkWidgetClass*) class;
16322 parent_class = gtk_type_class (gtk_widget_get_type ());
16324 object_class->destroy = gtk_dial_destroy;
16326 widget_class->realize = gtk_dial_realize;
16327 widget_class->expose_event = gtk_dial_expose;
16328 widget_class->size_request = gtk_dial_size_request;
16329 widget_class->size_allocate = gtk_dial_size_allocate;
16330 widget_class->button_press_event = gtk_dial_button_press;
16331 widget_class->button_release_event = gtk_dial_button_release;
16332 widget_class->motion_notify_event = gtk_dial_motion_notify;
16336 gtk_dial_init (GtkDial *dial)
16339 dial->policy = GTK_UPDATE_CONTINUOUS;
16342 dial->pointer_width = 0;
16344 dial->old_value = 0.0;
16345 dial->old_lower = 0.0;
16346 dial->old_upper = 0.0;
16347 dial->adjustment = NULL;
16351 gtk_dial_new (GtkAdjustment *adjustment)
16355 dial = gtk_type_new (gtk_dial_get_type ());
16358 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
16360 gtk_dial_set_adjustment (dial, adjustment);
16362 return GTK_WIDGET (dial);
16366 gtk_dial_destroy (GtkObject *object)
16370 g_return_if_fail (object != NULL);
16371 g_return_if_fail (GTK_IS_DIAL (object));
16373 dial = GTK_DIAL (object);
16375 if (dial->adjustment)
16376 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16378 if (GTK_OBJECT_CLASS (parent_class)->destroy)
16379 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
16383 gtk_dial_get_adjustment (GtkDial *dial)
16385 g_return_val_if_fail (dial != NULL, NULL);
16386 g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
16388 return dial->adjustment;
16392 gtk_dial_set_update_policy (GtkDial *dial,
16393 GtkUpdateType policy)
16395 g_return_if_fail (dial != NULL);
16396 g_return_if_fail (GTK_IS_DIAL (dial));
16398 dial->policy = policy;
16402 gtk_dial_set_adjustment (GtkDial *dial,
16403 GtkAdjustment *adjustment)
16405 g_return_if_fail (dial != NULL);
16406 g_return_if_fail (GTK_IS_DIAL (dial));
16408 if (dial->adjustment)
16410 gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
16411 gtk_object_unref (GTK_OBJECT (dial->adjustment));
16414 dial->adjustment = adjustment;
16415 gtk_object_ref (GTK_OBJECT (dial->adjustment));
16417 gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
16418 (GtkSignalFunc) gtk_dial_adjustment_changed,
16420 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
16421 (GtkSignalFunc) gtk_dial_adjustment_value_changed,
16424 dial->old_value = adjustment->value;
16425 dial->old_lower = adjustment->lower;
16426 dial->old_upper = adjustment->upper;
16428 gtk_dial_update (dial);
16432 gtk_dial_realize (GtkWidget *widget)
16435 GdkWindowAttr attributes;
16436 gint attributes_mask;
16438 g_return_if_fail (widget != NULL);
16439 g_return_if_fail (GTK_IS_DIAL (widget));
16441 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
16442 dial = GTK_DIAL (widget);
16444 attributes.x = widget->allocation.x;
16445 attributes.y = widget->allocation.y;
16446 attributes.width = widget->allocation.width;
16447 attributes.height = widget->allocation.height;
16448 attributes.wclass = GDK_INPUT_OUTPUT;
16449 attributes.window_type = GDK_WINDOW_CHILD;
16450 attributes.event_mask = gtk_widget_get_events (widget) |
16451 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
16452 GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
16453 GDK_POINTER_MOTION_HINT_MASK;
16454 attributes.visual = gtk_widget_get_visual (widget);
16455 attributes.colormap = gtk_widget_get_colormap (widget);
16457 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
16458 widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
16460 widget->style = gtk_style_attach (widget->style, widget->window);
16462 gdk_window_set_user_data (widget->window, widget);
16464 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
16468 gtk_dial_size_request (GtkWidget *widget,
16469 GtkRequisition *requisition)
16471 requisition->width = DIAL_DEFAULT_SIZE;
16472 requisition->height = DIAL_DEFAULT_SIZE;
16476 gtk_dial_size_allocate (GtkWidget *widget,
16477 GtkAllocation *allocation)
16481 g_return_if_fail (widget != NULL);
16482 g_return_if_fail (GTK_IS_DIAL (widget));
16483 g_return_if_fail (allocation != NULL);
16485 widget->allocation = *allocation;
16486 dial = GTK_DIAL (widget);
16488 if (GTK_WIDGET_REALIZED (widget))
16491 gdk_window_move_resize (widget->window,
16492 allocation->x, allocation->y,
16493 allocation->width, allocation->height);
16496 dial->radius = MIN(allocation->width,allocation->height) * 0.45;
16497 dial->pointer_width = dial->radius / 5;
16501 gtk_dial_expose (GtkWidget *widget,
16502 GdkEventExpose *event)
16505 GdkPoint points[3];
16512 g_return_val_if_fail (widget != NULL, FALSE);
16513 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16514 g_return_val_if_fail (event != NULL, FALSE);
16516 if (event->count > 0)
16519 dial = GTK_DIAL (widget);
16521 gdk_window_clear_area (widget->window,
16523 widget->allocation.width,
16524 widget->allocation.height);
16526 xc = widget->allocation.width/2;
16527 yc = widget->allocation.height/2;
16529 /* Dibuja las rayitas */
16531 for (i=0; i<25; i++)
16533 theta = (i*M_PI/18. - M_PI/6.);
16537 tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
16539 gdk_draw_line (widget->window,
16540 widget->style->fg_gc[widget->state],
16541 xc + c*(dial->radius - tick_length),
16542 yc - s*(dial->radius - tick_length),
16543 xc + c*dial->radius,
16544 yc - s*dial->radius);
16547 /* Dibuja el puntero */
16549 s = sin(dial->angle);
16550 c = cos(dial->angle);
16553 points[0].x = xc + s*dial->pointer_width/2;
16554 points[0].y = yc + c*dial->pointer_width/2;
16555 points[1].x = xc + c*dial->radius;
16556 points[1].y = yc - s*dial->radius;
16557 points[2].x = xc - s*dial->pointer_width/2;
16558 points[2].y = yc - c*dial->pointer_width/2;
16560 gtk_draw_polygon (widget->style,
16571 gtk_dial_button_press (GtkWidget *widget,
16572 GdkEventButton *event)
16578 double d_perpendicular;
16580 g_return_val_if_fail (widget != NULL, FALSE);
16581 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16582 g_return_val_if_fail (event != NULL, FALSE);
16584 dial = GTK_DIAL (widget);
16587 /* Determinar si la pulsación del botón fue dentro de la región del
16588 puntero - esto lo hacemos calculando la distancia x e y del punto
16589 donde se pulsó el botón ratón de la línea que se ha pasado mediante el
16592 dx = event->x - widget->allocation.width / 2;
16593 dy = widget->allocation.height / 2 - event->y;
16595 s = sin(dial->angle);
16596 c = cos(dial->angle);
16598 d_parallel = s*dy + c*dx;
16599 d_perpendicular = fabs(s*dx - c*dy);
16601 if (!dial->button &&
16602 (d_perpendicular < dial->pointer_width/2) &&
16603 (d_parallel > - dial->pointer_width))
16605 gtk_grab_add (widget);
16607 dial->button = event->button;
16609 gtk_dial_update_mouse (dial, event->x, event->y);
16616 gtk_dial_button_release (GtkWidget *widget,
16617 GdkEventButton *event)
16621 g_return_val_if_fail (widget != NULL, FALSE);
16622 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16623 g_return_val_if_fail (event != NULL, FALSE);
16625 dial = GTK_DIAL (widget);
16627 if (dial->button == event->button)
16629 gtk_grab_remove (widget);
16633 if (dial->policy == GTK_UPDATE_DELAYED)
16634 gtk_timeout_remove (dial->timer);
16636 if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
16637 (dial->old_value != dial->adjustment->value))
16638 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16645 gtk_dial_motion_notify (GtkWidget *widget,
16646 GdkEventMotion *event)
16649 GdkModifierType mods;
16652 g_return_val_if_fail (widget != NULL, FALSE);
16653 g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
16654 g_return_val_if_fail (event != NULL, FALSE);
16656 dial = GTK_DIAL (widget);
16658 if (dial->button != 0)
16663 if (event->is_hint || (event->window != widget->window))
16664 gdk_window_get_pointer (widget->window, &x, &y, &mods);
16666 switch (dial->button)
16669 mask = GDK_BUTTON1_MASK;
16672 mask = GDK_BUTTON2_MASK;
16675 mask = GDK_BUTTON3_MASK;
16682 if (mods & mask)
16683 gtk_dial_update_mouse (dial, x,y);
16690 gtk_dial_timer (GtkDial *dial)
16692 g_return_val_if_fail (dial != NULL, FALSE);
16693 g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
16695 if (dial->policy == GTK_UPDATE_DELAYED)
16696 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16702 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
16707 g_return_if_fail (dial != NULL);
16708 g_return_if_fail (GTK_IS_DIAL (dial));
16710 xc = GTK_WIDGET(dial)->allocation.width / 2;
16711 yc = GTK_WIDGET(dial)->allocation.height / 2;
16713 old_value = dial->adjustment->value;
16714 dial->angle = atan2(yc-y, x-xc);
16716 if (dial->angle < -M_PI/2.)
16717 dial->angle += 2*M_PI;
16719 if (dial->angle < -M_PI/6)
16720 dial->angle = -M_PI/6;
16722 if (dial->angle > 7.*M_PI/6.)
16723 dial->angle = 7.*M_PI/6.;
16725 dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
16726 (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
16728 if (dial->adjustment->value != old_value)
16730 if (dial->policy == GTK_UPDATE_CONTINUOUS)
16732 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16736 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16738 if (dial->policy == GTK_UPDATE_DELAYED)
16741 gtk_timeout_remove (dial->timer);
16743 dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
16744 (GtkFunction) gtk_dial_timer,
16752 gtk_dial_update (GtkDial *dial)
16756 g_return_if_fail (dial != NULL);
16757 g_return_if_fail (GTK_IS_DIAL (dial));
16759 new_value = dial->adjustment->value;
16761 if (new_value < dial->adjustment->lower)
16762 new_value = dial->adjustment->lower;
16764 if (new_value > dial->adjustment->upper)
16765 new_value = dial->adjustment->upper;
16767 if (new_value != dial->adjustment->value)
16769 dial->adjustment->value = new_value;
16770 gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
16773 dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
16774 (dial->adjustment->upper - dial->adjustment->lower);
16776 gtk_widget_draw (GTK_WIDGET(dial), NULL);
16780 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
16785 g_return_if_fail (adjustment != NULL);
16786 g_return_if_fail (data != NULL);
16788 dial = GTK_DIAL (data);
16790 if ((dial->old_value != adjustment->value) ||
16791 (dial->old_lower != adjustment->lower) ||
16792 (dial->old_upper != adjustment->upper))
16794 gtk_dial_update (dial);
16796 dial->old_value = adjustment->value;
16797 dial->old_lower = adjustment->lower;
16798 dial->old_upper = adjustment->upper;
16803 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
16808 g_return_if_fail (adjustment != NULL);
16809 g_return_if_fail (data != NULL);
16811 dial = GTK_DIAL (data);
16813 if (dial->old_value != adjustment->value)
16815 gtk_dial_update (dial);
16817 dial->old_value = adjustment->value;
16820 /* fin del ejemplo */
16823 <!-- ----------------------------------------------------------------- -->
16827 /* principio del ejemplo scribble-simple scribble-simple.c */
16829 /* GTK - The GIMP Toolkit
16830 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
16832 * This library is free software; you can redistribute it and/or
16833 * modify it under the terms of the GNU Library General Public
16834 * License as published by the Free Software Foundation; either
16835 * version 2 of the License, or (at your option) any later version.
16837 * This library is distributed in the hope that it will be useful,
16838 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16839 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16840 * Library General Public License for more details.
16842 * You should have received a copy of the GNU Library General Public
16843 * License along with this library; if not, write to the
16844 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16845 * Boston, MA 02111-1307, USA.
16848 #include <gtk/gtk.h>
16850 /* Creamos un backing pixmap para la zona donde dibujamos */
16851 static GdkPixmap *pixmap = NULL;
16853 /* Creamos un nuevo backing pixmap del tamaño apropiado */
16855 configure_event (GtkWidget *widget, GdkEventConfigure *event)
16858 gdk_pixmap_unref(pixmap);
16860 pixmap = gdk_pixmap_new(widget->window,
16861 widget->allocation.width,
16862 widget->allocation.height,
16864 gdk_draw_rectangle (pixmap,
16865 widget->style->white_gc,
16868 widget->allocation.width,
16869 widget->allocation.height);
16874 /* Redibujamos la pantalla con el backing pixmap */
16876 expose_event (GtkWidget *widget, GdkEventExpose *event)
16878 gdk_draw_pixmap(widget->window,
16879 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
16881 event->area.x, event->area.y,
16882 event->area.x, event->area.y,
16883 event->area.width, event->area.height);
16888 /* Dibujamos un rectángulo en la pantalla */
16890 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
16892 GdkRectangle update_rect;
16894 update_rect.x = x - 5;
16895 update_rect.y = y - 5;
16896 update_rect.width = 10;
16897 update_rect.height = 10;
16898 gdk_draw_rectangle (pixmap,
16899 widget->style->black_gc,
16901 update_rect.x, update_rect.y,
16902 update_rect.width, update_rect.height);
16903 gtk_widget_draw (widget, &update_rect);
16907 button_press_event (GtkWidget *widget, GdkEventButton *event)
16909 if (event->button == 1 && pixmap != NULL)
16910 draw_brush (widget, event->x, event->y);
16916 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
16919 GdkModifierType state;
16921 if (event->is_hint)
16922 gdk_window_get_pointer (event->window, &x, &y, &state);
16927 state = event->state;
16930 if (state & GDK_BUTTON1_MASK && pixmap != NULL)
16931 draw_brush (widget, x, y);
16943 main (int argc, char *argv[])
16945 GtkWidget *ventana;
16946 GtkWidget *drawing_area;
16951 gtk_init (&argc, &argv);
16953 ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16954 gtk_widget_set_name (ventana, "Test Input");
16956 vbox = gtk_vbox_new (FALSE, 0);
16957 gtk_container_add (GTK_CONTAINER (ventana), vbox);
16958 gtk_widget_show (vbox);
16960 gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
16961 GTK_SIGNAL_FUNC (quit), NULL);
16963 /* Crear la zona de dibujado */
16965 drawing_area = gtk_drawing_area_new ();
16966 gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
16967 gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16969 gtk_widget_show (drawing_area);
16971 /* Las señales utilizadas para manejar el backing pixmap */
16973 gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
16974 (GtkSignalFunc) expose_event, NULL);
16975 gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
16976 (GtkSignalFunc) configure_event, NULL);
16978 /* Señales evento */
16980 gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
16981 (GtkSignalFunc) motion_notify_event, NULL);
16982 gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
16983 (GtkSignalFunc) button_press_event, NULL);
16985 gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16986 | GDK_LEAVE_NOTIFY_MASK
16987 | GDK_BUTTON_PRESS_MASK
16988 | GDK_POINTER_MOTION_MASK
16989 | GDK_POINTER_MOTION_HINT_MASK);
16991 /* .. Y un botón para salir */
16992 boton = gtk_button_new_with_label ("Quit");
16993 gtk_box_pack_start (GTK_BOX (vbox), boton, FALSE, FALSE, 0);
16995 gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
16996 GTK_SIGNAL_FUNC (gtk_widget_destroy),
16997 GTK_OBJECT (ventana));
16998 gtk_widget_show (boton);
17000 gtk_widget_show (ventana);
17006 /* fin del ejemplo */
17009 <!-- ***************************************************************** -->
17010 <sect> El <em>widget</em> lista
17011 <!-- ***************************************************************** -->
17013 ATENCIÓN: El <em>widget</em> GtkList ha sido reemplazado por el
17014 <em>widget</em> GtkCList.
17016 El <em>widget</em> GtkList está diseñado para actuar como un
17017 contenedor vertical de <em>widgets</em> que deben ser del tipo
17020 Un <em>widget</em> GtkList tiene su propia ventana para recibir
17021 eventos y su propio color de fondo, que normalmente es blanco.
17022 Como es un objeto derivado directamente de GtkContainer puede tratarse
17023 utilizando la macro GTK_CONTAINER(List), ver el <em>widget</em>
17024 GtkContainer para obtener más información.
17026 Debería familiarizarse con la utilización de un GList y con sus
17027 funciones relacionadas <tt/g_list_*()/ para ser capaz de explotar el
17028 <em>widget</em> GtkList hasta su límite.
17030 Sólo hay un campo dentro de la definición de la estructura del
17031 <em>widget</em> GtkList que nos es de interés, y es:
17038 guint selection_mode;
17043 El campo <tt/selection/ de un GtkList apunta a una lista enlazada de
17044 todos los elementos que están actualmente seleccionados, o NULL si la
17045 selección está vacia. Por lo tanto para saber quien es la actual
17046 selección debemos leer el campo <tt/GTK_LIST()->selection/, pero no
17047 modificarlo ya que los campos de los que está constituido GtkList
17048 están controlados por las funciones gtk_list_*().
17050 El <tt/selection_mode/ de la GtkList determina las posibilidades de
17051 selección de una GtkList y por tanto los contenidos del campo
17052 <tt/GTK_LIST()->selection/. El <tt/selection_mode/ puede tener uno de
17053 los valores siguientes:
17056 <item> GTK_SELECTION_SINGLE - La selección es o NULL o contiene un
17057 puntero a un GList con un solo elemento seleccionado.
17059 <item> GTK_SELECTION_BROWSE - La selección es NULL si la lista no
17060 contiene <em>widgets</em> o si los que contiene no son sensibles, en
17061 cualquier otro caso contiene un puntero GList a una estructura GList,
17062 y contendrá por tanto un solo elemento.
17064 <item> GTK_SELECTION_MULTIPLE - La selección es NULL si no hay
17065 elementos seleccionados o un puntero GList hacia el primer elemento
17066 seleccionado. ("That in turn") apunta a una estructura GList para
17067 el segundo elemento seleccionado y así.
17069 <item> GTK_SELECTION_EXTENDED - La selección siempre es NULL.
17072 El valor por defecto es GTK_SELECTION_MULTIPLE.
17074 <!-- ----------------------------------------------------------------- -->
17078 void selection_changed( GtkList *list );
17081 Se invocará esta señal cuando cambie el campo <tt/selection/ de un
17082 GtkList. Es decir, cuando un hijo de una GtkList se selecciona o
17086 void select_child( GtkList *list,
17090 Se invoca esta señal cuando un hijo de la GtkList está siendo
17091 seleccionado. Esto ocurre principalmente en llamadas a
17092 <tt/gtk_list_select_item()/, a <tt/gtk_list_select_child()/, cuando se
17093 pulsa algún botón y a veces se lanza indirectamente cuando se añade o
17094 se elimina un hijo del GtkList.
17097 void unselect_child( GtkList *list,
17101 Se invoca esta señal cuando un hijo del GtkList está siendo
17102 deseleccionado. Esto ocurre principalmente cuando ocurre una llamada a
17103 <tt/gtk_list_unselect_item()/, <tt/gtk_list_unselect_item()/,
17104 pulsaciones de botón y a veces se lanza indirectamente cuando se añade
17105 o se elimina algún hijo de la GtkList.
17107 <!-- ----------------------------------------------------------------- -->
17111 guint gtk_list_get_type( void );
17114 Devuelve el identificador de tipo `GtkList'.
17117 GtkWidget *gtk_list_new( void );
17120 Crea un nuevo objeto GtkList. Se devuelve el nuevo <em/widget/ como un
17121 puntero a un objeto GtkWidget. Se devuelve NULL en caso de producirse
17125 void gtk_list_insert_items( GtkList *list,
17130 Introduce elementos en la lista, comenzando en la posición
17131 <tt/posicion/. <tt/items/ es una lista doblemente enlazada donde cada
17132 puntero de datos de cada nodo se supone que apunta a una nueva
17133 GtkListItem (recien creada). Los nodos GList de <tt/items/ son
17134 controlados por la lista.
17137 void gtk_list_append_items( GtkList *list,
17141 Introduce elementos tal y como lo hace <tt/gtk_list_insert_items()/,
17142 pero los mete en el final de la lista. Los nodos GList de <tt/items/
17143 son controlados por la lista.
17146 void gtk_list_prepend_items( GtkList *list,
17150 Introduce elementos tal y como lo hace <tt/gtk_list_insert_items()/,
17151 pero los mete al principio de la lista. Los nodos GList de <tt/items/
17152 son controlados por la lista.
17155 void gtk_list_remove_items( GtkList *list,
17159 Elimina elementos de la lista. <tt/items/ es una lista doblemente
17160 enlazada donde cada puntero de datos de cada nodo se supone que apunta
17161 a un hijo directo de la lista. El ejecutar o no
17162 <tt/g_list_free(items)/ cuando la función termine de ejecutarse es
17163 responsabilidad del que llama a la misma. Está bajo su responsabilidad
17164 la destrucción de los elementos de la lista.
17167 void gtk_list_clear_items( GtkList *list,
17172 Elimina y destruye los elementos de la lista. Esta operación afectará
17173 a todos los <em/widgets/ que se encuentren en la lista y en el rango
17174 especificado por <tt/start/ y <tt/end/.
17177 void gtk_list_select_item( GtkList *list,
17181 Invoca la señal <tt/select_child/ para el elemento especificado
17182 mediante su posición actual en la lista.
17185 void gtk_list_unselect_item( GtkList *list,
17189 Invoca la señal <tt/unselect_child/ para un elemento especificado
17190 mediante su posición actual en la lista.
17193 void gtk_list_select_child( GtkList *list,
17197 Invoca la señal <tt/select_child/ para el hijo especificado.
17200 void gtk_list_unselect_child( GtkList *list,
17204 Invoca la señal <tt/unselect_child/ para el hijo especificado.
17207 gint gtk_list_child_position( GtkList *list,
17211 Devuelve la posición de <tt/hijo/ en la lista. Se devuelve «-1» en
17212 caso de producirse algún error.
17215 void gtk_list_set_selection_mode( GtkList *list,
17216 GtkSelectionMode mode );
17219 Pone el modo de selección, que puede ser <tt/GTK_SELECTION_SINGLE/,
17220 <tt/GTK_SELECTION_BROWSE/, <tt/GTK_SELECTION_MULTIPLE/ o
17221 <tt/GTK_SELECTION_EXTENDED/.
17224 GtkList *GTK_LIST( gpointer obj );
17227 Convierte un puntero general en `GtkList *'. Para más información *Note
17231 GtkListClass *GTK_LIST_CLASS( gpointer class);
17234 Convierte un puntero general en `GtkListClass *'. Para más información
17235 *Note Standard Macros::.
17238 gint GTK_IS_LIST( gpointer obj);
17241 Determina si un puntero general se refiere a un objeto `GtkList'. Para
17242 más información, *Note Standard Macros::.
17244 <!-- ----------------------------------------------------------------- -->
17247 A continuación tenemos un programa ejemplo que muestra los cambios de
17248 la selección de un GtkList, y le deja «arrestar» elementos de la
17249 lista en una prisión, seleccionándolos con el botón derecho del ratón.
17252 /* principio del ejemplo list list.c */
17254 /* incluye los ficheros de cabecera de gtk+
17255 * incluye stdio.h, que necesitamos para la función printf()
17257 #include <gtk/gtk.h>
17260 /* ésta es nuestra cadena de identificación para almacenar datos en la
17261 * lista de elementos
17263 const gchar *list_item_data_key="list_item_data";
17266 /* prototipos para los manejadores de señal que vamos a conectar con
17267 * el widget GtkList
17269 static void sigh_print_selection (GtkWidget *gtklist,
17270 gpointer func_data);
17271 static void sigh_button_event (GtkWidget *gtklist,
17272 GdkEventButton *event,
17276 /* función principal donde se establece el interface con el usuario */
17278 gint main (int argc, gchar *argv[])
17280 GtkWidget *separator;
17281 GtkWidget *ventana;
17283 GtkWidget *scrolled_window;
17285 GtkWidget *gtklist;
17287 GtkWidget *list_item;
17293 /* inicializar gtk+ (y consecuentemente gdk) */
17295 gtk_init(&argc, &argv);
17298 /* crear una ventana donde meter todos los widgets y conectar
17299 * gtk_main_quit() con el evento "destroy" de la ventana para
17300 * poder controlar los eventos de cerrado de ventana del
17301 * administrador de ventanas
17303 ventana=gtk_window_new(GTK_WINDOW_TOPLEVEL);
17304 gtk_window_set_title(GTK_WINDOW(ventana), "GtkList Example");
17305 gtk_signal_connect(GTK_OBJECT(ventana),
17307 GTK_SIGNAL_FUNC(gtk_main_quit),
17311 /* dentro de la ventana necesitamos una caja para alinear los
17312 * widgets verticalmente */
17313 vbox=gtk_vbox_new(FALSE, 5);
17314 gtk_container_border_width(GTK_CONTAINER(vbox), 5);
17315 gtk_container_add(GTK_CONTAINER(ventana), vbox);
17316 gtk_widget_show(vbox);
17318 /* Ésta es la ventana con barras de desplazamiento donde meteremos
17319 * el widget GtkList */
17320 scrolled_window=gtk_scrolled_window_new(NULL, NULL);
17321 gtk_widget_set_usize(scrolled_window, 250, 150);
17322 gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
17323 gtk_widget_show(scrolled_window);
17325 /* crear el widget GtkList
17326 * conectar la función manipuladora de señal
17327 * sigh_print_selection() a la señal "selection_changed" del
17328 * GtkList para imprimir los elementos seleccionados cada vez que
17329 * cambie la selección */
17330 gtklist=gtk_list_new();
17331 gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
17332 gtk_widget_show(gtklist);
17333 gtk_signal_connect(GTK_OBJECT(gtklist),
17334 "selection_changed",
17335 GTK_SIGNAL_FUNC(sigh_print_selection),
17338 /* creamos una "Prisión" donde meteremos una lista de elementos ;)
17340 frame=gtk_frame_new("Prison");
17341 gtk_widget_set_usize(frame, 200, 50);
17342 gtk_container_border_width(GTK_CONTAINER(frame), 5);
17343 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
17344 gtk_container_add(GTK_CONTAINER(vbox), frame);
17345 gtk_widget_show(frame);
17347 /* conectamos el manipulador de señal sigh_button_event() al
17348 * GtkList que manejará la lista de elementos "arrestados"
17350 gtk_signal_connect(GTK_OBJECT(gtklist),
17351 "button_release_event",
17352 GTK_SIGNAL_FUNC(sigh_button_event),
17355 /* crear un separador
17357 separator=gtk_hseparator_new();
17358 gtk_container_add(GTK_CONTAINER(vbox), separator);
17359 gtk_widget_show(separator);
17361 /* crear finalmente un botón y conectar su señal "clicked" con la
17362 * destrucción de la ventana
17364 boton=gtk_button_new_with_label("Close");
17365 gtk_container_add(GTK_CONTAINER(vbox), boton);
17366 gtk_widget_show(boton);
17367 gtk_signal_connect_object(GTK_OBJECT(boton),
17369 GTK_SIGNAL_FUNC(gtk_widget_destroy),
17370 GTK_OBJECT(ventana));
17373 /* ahora creamos 5 elementos de lista, teniendo cada uno su propia
17374 * etiqueta y añadiéndolos a la GtkList mediante
17375 * gtk_container_add() también consultaremos la cadena de texto de
17376 * la etiqueta y la asociaremos con la list_item_data_key para
17377 * cada elemento de la lista
17379 for (i=0; i<5; i++) {
17380 GtkWidget *etiqueta;
17383 sprintf(buffer, "ListItemContainer with Label #%d", i);
17384 etiqueta=gtk_label_new(buffer);
17385 list_item=gtk_list_item_new();
17386 gtk_container_add(GTK_CONTAINER(list_item), etiqueta);
17387 gtk_widget_show(etiqueta);
17388 gtk_container_add(GTK_CONTAINER(gtklist), list_item);
17389 gtk_widget_show(list_item);
17390 gtk_label_get(GTK_LABEL(etiqueta), &string);
17391 gtk_object_set_data(GTK_OBJECT(list_item),
17392 list_item_data_key,
17395 /* aquí, estamos creando otras 5 etiquetas, esta vez utilizaremos
17396 * gtk_list_item_new_with_label() para la creación
17397 * no podemos consultar la cadena de texto de la etiqueta ya que
17398 * no tenemos el puntero de etiquetas y por tanto lo único que
17399 * haremos será asociar el list_item_data_key de cada elemento de
17400 * la lista con la misma cadena de texto. Para añadirlo a la lista
17401 * de elementos los pondremos en lista doblemente enlazada
17402 * (GList), y entonces los añadimos mediante una simple llamada a
17403 * gtk_list_append_items()
17404 * como utilizamos g_list_prepend() para poner los elementos en la
17405 * lista doblemente enlazada, su orden será descendente (en vez de
17406 * ascendente como cuando utilizamos g_list_append())
17409 for (; i<10; i++) {
17410 sprintf(buffer, "List Item with Label %d", i);
17411 list_item=gtk_list_item_new_with_label(buffer);
17412 dlist=g_list_prepend(dlist, list_item);
17413 gtk_widget_show(list_item);
17414 gtk_object_set_data(GTK_OBJECT(list_item),
17415 list_item_data_key,
17416 "ListItem with integrated Label");
17418 gtk_list_append_items(GTK_LIST(gtklist), dlist);
17420 /* finalmente queremos ver la ventana, ¿verdad? ;)
17422 gtk_widget_show(ventana);
17424 /* y nos metemos en el bucle de eventos de gtk
17428 /* llegaremos aquí después de que se llame a gtk_main_quit(), lo
17429 * que ocurre si se destruye la ventana
17434 /* éste es el manejador de señal que se conectó a los eventos de
17435 * pulsar/soltar de los botones de la GtkList
17438 sigh_button_event (GtkWidget *gtklist,
17439 GdkEventButton *event,
17442 /* sólo hacemos algo si el tercer botón (el botón derecho) se
17445 if (event->type==GDK_BUTTON_RELEASE &&
17446 event->button==3) {
17447 GList *dlist, *free_list;
17448 GtkWidget *new_prisoner;
17450 /* sacar la lista de elementos que están actualmente
17451 * seleccionados y que serán nuestro próximos prisioneros ;)
17453 dlist=GTK_LIST(gtklist)->selection;
17455 new_prisoner=GTK_WIDGET(dlist->data);
17459 /* buscar por elementos de la lista ya encarcelados, los
17460 * volveremos a poner en la lista, recordar que hay que
17461 * eliminar la lista doblemente enlazada que devuelve
17462 * gtk_container_children()
17464 dlist=gtk_container_children(GTK_CONTAINER(frame));
17467 GtkWidget *list_item;
17469 list_item=dlist->data;
17471 gtk_widget_reparent(list_item, gtklist);
17475 g_list_free(free_list);
17477 /* si tenemos un nuevo prisionero, lo eliminamos de la GtkList
17478 * y lo ponemos en el marco "Prisión". Primero tenemos que
17481 if (new_prisoner) {
17482 GList static_dlist;
17484 static_dlist.data=new_prisoner;
17485 static_dlist.next=NULL;
17486 static_dlist.prev=NULL;
17488 gtk_list_unselect_child(GTK_LIST(gtklist),
17490 gtk_widget_reparent(new_prisoner, frame);
17495 /* éste es el manipulador de señal que se llama si GtkList emite la
17496 * señal "selection_changed"
17499 sigh_print_selection (GtkWidget *gtklist,
17500 gpointer func_data)
17504 /* sacar la lista doblemente enlazada de los elementos
17505 * seleccionados en GtkList, ¡recuerde que hay que tratarla como
17508 dlist=GTK_LIST(gtklist)->selection;
17510 /* si no hay elementos seleccionados no queda nada por hacer
17511 * excepto informar al usuario
17514 g_print("Selection cleared\n");
17517 /* Bien, conseguimos una selección y la imprimimos
17519 g_print("The selection is a ");
17521 /* obtenemos la lista de elementos de la lista doblemente enlazada
17522 * y entonces consultamos los datos asociados con la
17523 * list_item_data_key que acabamos de imprimir
17526 GtkObject *list_item;
17527 gchar *item_data_string;
17529 list_item=GTK_OBJECT(dlist->data);
17530 item_data_string=gtk_object_get_data(list_item,
17531 list_item_data_key);
17532 g_print("%s ", item_data_string);
17538 /* fin del ejemplo */
17541 <!-- ----------------------------------------------------------------- -->
17542 <sect1> El <em/widget/ GtkListItem
17544 El <em/widget/ GtkListItem está diseñado para comportarse como un
17545 contenedor que tiene un hijo, proporcionando funciones para la
17546 selección/deselección justo como las necesitan los hijos del
17547 <em/widget/ GtkList.
17549 Un GtkListItem tiene su propia ventana para recibir eventos y tiene su
17550 propio color de fondo, que normalmente es blanco.
17552 Como está derivado directamente de un GtkItem, puede tratarse como tal
17553 utilizando la macro GTK_ITEM(ListItem), ver el <em/widget/ GtkItem
17554 para más detalles. Normalmente un GtkListItem sólo tiene una etiqueta
17555 para identificar, por ejemplo, el nombre de un fichero dentro de una
17556 GtkList -- por lo tanto se proporciona la función
17557 <tt/gtk_list_item_new_with_label()/. Se puede conseguir el mismo
17558 efecto creando un GtkLabel, poniendo su alineación a <tt/xalign=0/ e
17559 <tt/yalign=0.5/ y seguido de una adición al contenedor GtkListItem.
17561 Nadie le obliga a meter un GtkLabel en un GtkListItem, puede meter un
17562 GtkVBox o un GtkArrow, etc...
17564 <!-- ----------------------------------------------------------------- -->
17567 Un GtkListItem no crea por sí misma nuevas señales, pero hereda las
17568 señales de un GtkItem. Para más información *Note GtkItem::.
17570 <!-- ----------------------------------------------------------------- -->
17574 guint gtk_list_item_get_type( void );
17577 Devuelve el identificador de tipo `GtkListItem'.
17580 GtkWidget *gtk_list_item_new( void );
17583 Crea un nuevo objeto GtkListItem. Se devuelve el nuevo <em/widget/
17584 como un puntero a un objeto GtkWidget. Se devuelve NULL en caso de
17585 producirse algún error.
17588 GtkWidget *gtk_list_item_new_with_label( gchar *etiqueta );
17591 Crea un nuevo objeto GtkListItem, con una sola GtkLabel como único
17592 hijo. Se devuelve el nuevo <em/widget/ como un puntero a un objeto
17593 GtkWidget. Se devuelve NULL en caso de producirse algún error.
17596 void gtk_list_item_select( GtkListItem *list_item );
17599 Esta función es, básicamente, un recubrimiento de una llamada a
17600 <tt/gtk_item_select (GTK_ITEM (list_item))/, y emitirá la señal
17601 <tt/select/. Para más información *Note GtkItem::.
17604 void gtk_list_item_deselect( GtkListItem *list_item );
17607 Esta función es, básicamente, un recubrimiento de una llamada a
17608 <tt/gtk_item_deselect (GTK_ITEM (list_item))/, y emitirá la señal
17609 <tt/deselect/. Para más información *Note GtkItem::.
17612 GtkListItem *GTK_LIST_ITEM( gpointer obj );
17615 Convierte un puntero general a `GtkListItem *'. Para más información
17616 *Note Standard Macros::.
17619 GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
17622 Convierte un puntero general a `GtkListItemClass *'. Para más
17623 información *Note Standard Macros::.
17626 gint GTK_IS_LIST_ITEM( gpointer obj );
17629 Determina si un puntero general se refiere a un puntero
17630 `GtkListItem'. Para más información *Note Standard Macros::.
17632 <!-- ----------------------------------------------------------------- -->
17635 Para ver un ejemplo de todo esto, mire el de GtkList, que también
17636 cubre la utilización un GtkListItem.