2000-04-23 09:17:36 +00:00
|
|
|
|
<!doctype linuxdoc system>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
Traducci<63>n realizada por:
|
|
|
|
|
Joaqu<71>n Cuenca Abela (e98cuenc@criens.u-psud.fr)
|
|
|
|
|
Eduardo Anglada Varela (eduardo.anglada@adi.uam.es)
|
|
|
|
|
|
|
|
|
|
Versi<73>n beta 2 de la traducci<63>n del GTK+
|
|
|
|
|
Tutorial 1.2. Cualquier sugerencia ser<65> bienvenida.
|
|
|
|
|
Los cambios m<>s significativos de esta versi<73>n son la traducci<63>n
|
|
|
|
|
de las variables de los programas y XXX.
|
|
|
|
|
|
|
|
|
|
Si quiere obtener este documento puede encontrarlo en Linux Landia:
|
|
|
|
|
http://www.croftj.net/~barreiro/spanish/gnome-es/
|
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
|
<article>
|
|
|
|
|
<title>GTK Tutorial v1.2
|
|
|
|
|
<author>Tony Gale <tt><htmlurl url="mailto:gale@gtk.org"
|
|
|
|
|
name="<gale@gtk.org>"></tt>,
|
|
|
|
|
Ian Main <tt><htmlurl url="mailto:imain@gtk.org"
|
|
|
|
|
name="<imain@gtk.org>"></tt>
|
|
|
|
|
<date>21 de Febrero de 1999
|
|
|
|
|
<abstract>
|
|
|
|
|
Este documento es un tutorial sobre como utilizar GTK (el GIMP
|
|
|
|
|
Toolkit) en C
|
|
|
|
|
</abstract>
|
|
|
|
|
|
|
|
|
|
<toc>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Introducci<63>n
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
2008-07-01 22:57:50 +00:00
|
|
|
|
GTK (GIMP Toolkit) es una biblioteca para crear interfaces gr<67>ficas
|
2000-04-23 09:17:36 +00:00
|
|
|
|
de usuario. Su licencia es la LGPL, as<61> que mediante GTK podr<64>
|
|
|
|
|
desarrollar programas con licencias abiertas, gratuitas, libres, y
|
|
|
|
|
hasta licencias comerciales no libres sin mayores problemas.
|
|
|
|
|
|
|
|
|
|
Se llama el GIMP toolkit porque fue escrito para el desarrollo del
|
|
|
|
|
General Image Manipulation Program (GIMP), pero ahora GTK se utiliza
|
|
|
|
|
en un gran n<>mero de proyectos de programaci<63>n, incluyendo el
|
|
|
|
|
proyecto GNU Network Object Model Environment (GNOME). GTK est<73>
|
2008-07-01 22:57:50 +00:00
|
|
|
|
construido encima de GDK (GIMP Drawing Kit) que b<>sicamente es un
|
2000-04-23 09:17:36 +00:00
|
|
|
|
recubrimiento de las funciones de bajo nivel que deben haber para
|
|
|
|
|
acceder al sistema de ventanas sobre el que se programe (Xlib en el
|
|
|
|
|
caso de X windows). Los principales autores de GTK son:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> Peter Mattis <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
|
|
|
|
|
name="petm@xcf.berkeley.edu"></tt>
|
|
|
|
|
<item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
|
|
|
|
|
name="spencer@xcf.berkeley.edu"></tt>
|
|
|
|
|
<item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
|
|
|
|
|
name="jmacd@xcf.berkeley.edu"></tt>
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
GTK es esencialmente una interfaz para la programaci<63>n de
|
|
|
|
|
aplicaciones orientadas al objeto (API). Aunque est<73> completamente
|
|
|
|
|
escrito en C, esta implementado haciendo uso de la idea de clases y de
|
|
|
|
|
funciones respuesta o de <em/callback/ (punteros o funciones).
|
|
|
|
|
|
|
|
|
|
Tenemos un tercer componente llamado glib, que contiene unas cuantas
|
|
|
|
|
funciones para reemplazar algunas llamadas est<73>ndar, as<61> como
|
|
|
|
|
funciones adicionales para manejar listas enlazadas, etc... Se
|
|
|
|
|
reemplazan algunas funciones para aumentar la portabilidad de GTK, ya
|
|
|
|
|
que algunas de las funciones implementadas no est<73>n disponibles o
|
|
|
|
|
no son est<73>ndar en otros unixs, como por ejemplo
|
|
|
|
|
g_strerror(). Algunas otras contienen mejoras a la versi<73>n de libc,
|
|
|
|
|
como g_malloc que mejora las posibilidades de encontrar errores.
|
|
|
|
|
|
|
|
|
|
Este tutorial describe la interfaz C de GTK. Hay recubrimientos GTK
|
|
|
|
|
para muchos otros lenguajes, incluyendo C++, Guile, Perl, Python, TOM,
|
|
|
|
|
Ada95, Objective C, Free Pascal, y Eiffel. Si va a utilizar el
|
|
|
|
|
recubrimiento para alguno de estos lenguajes, mire primero su
|
|
|
|
|
documentaci<EFBFBD>n. En algunos casos la documentaci<63>n puede describir
|
|
|
|
|
alg<EFBFBD>n convenio importante (que deber<65>a conocer de antemano) y
|
|
|
|
|
despu<EFBFBD>s puede volver a este tutorial. Tambi<62>n hay alg<6C>n API
|
|
|
|
|
multiplataforma (como wxWindows y V) que utilizan GTK como una de sus
|
|
|
|
|
plataformas destino; de nuevo, consulte primero la documentaci<63>n
|
|
|
|
|
que viene con estos paquetes.
|
|
|
|
|
|
|
|
|
|
Si est<73> desarrollando su aplicaci<63>n GTK en C++, hay algunas
|
|
|
|
|
cosas que deber<65>a saber. Hay un recubriento a GTK para C++ llamado
|
|
|
|
|
GTK--, que proporciona una interfaz C++ a GTK; probablemente
|
|
|
|
|
deber<EFBFBD>a empezar mirando ah<61>. Si no le gusta esa aproximaci<63>n
|
|
|
|
|
al problema, por los motivos que sean, tiene dos
|
|
|
|
|
alternativas. Primero, puede ce<63>irse al subconjunto C de C++ cuando
|
|
|
|
|
realice alguna llamada a GTK a trav<61>s de su interfaz en C. Segundo,
|
|
|
|
|
puede utilizar GTK y C++ al mismo tiempo declarando todas las
|
|
|
|
|
funciones respuesta como funciones est<73>ticas en clases C++, y de
|
|
|
|
|
nuevo, llamar a GTK utilizando su interfaz C. Si elige esta <20>ltima
|
|
|
|
|
forma de actuar, puede incluir como dato de la funci<63>n respuesta un
|
|
|
|
|
puntero al objeto a manipular (el tambi<62>n llamado valor
|
|
|
|
|
<EFBFBD>this<EFBFBD>). La elecci<63>n de una u otra opci<63>n es cuesti<74>n de
|
|
|
|
|
gustos personales, ya que de las tres maneras conseguir<69> utilizar
|
|
|
|
|
GTK en C++. Ninguna de estas aproximaciones requiere el uso de un
|
|
|
|
|
preprocesador especializado, por lo que sin importar la opci<63>n que
|
|
|
|
|
escoja podr<64> utilizar C++ est<73>ndar en C++.
|
|
|
|
|
|
|
|
|
|
Este tutorial es un intento de documentar GTK tanto como sea posible,
|
|
|
|
|
pero no est<73> completo. Este tutorial asume un buen conocimiento de
|
|
|
|
|
C y de como crear programas bajo este lenguaje. Se ver<65> beneficiado
|
|
|
|
|
si tiene un conocimiento previo de la programaci<63>n en X, pero no
|
|
|
|
|
deber<EFBFBD>a ser necesario. Si est<73> aprendiendo GTK y es el primer
|
|
|
|
|
conjunto de <em/widgets/ que utiliza, por favor env<6E>enos sus
|
|
|
|
|
comentarios sobre este tutorial y los problemas que ha
|
|
|
|
|
encontrado.
|
|
|
|
|
|
|
|
|
|
Este documento es un `trabajo pendiente de finalizar'. Para encontrar
|
|
|
|
|
actualizaciones mire en http://www.gtk.org/ <htmlurl
|
|
|
|
|
url="http://www.gtk.org/" name="http://www.gtk.org/">.
|
|
|
|
|
|
|
|
|
|
Me gustar<61>a escuchar cualquier problema que le surja mientras
|
|
|
|
|
aprende GTK siguiendo este documento, y apreciar<61> cualquier
|
|
|
|
|
informaci<EFBFBD>n sobre como mejorarlo. Por favor, vea la secci<63>n <ref
|
|
|
|
|
id="sec_Contributing" name="Contribuyendo"> para encontrar m<>s
|
|
|
|
|
informaci<EFBFBD>n.
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Comenzando
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Por supuesto lo primero que hay que hacer es descargar las fuentes de
|
|
|
|
|
GTK e instalarlas. La <20>ltima versi<73>n siempre se puede obtener de
|
|
|
|
|
ftp.gtk.org (en el directorio /pub/gtk). En <htmlurl
|
|
|
|
|
url="http://www.gtk.org/" name="http://www.gtk.org/"> hay m<>s
|
|
|
|
|
informaci<EFBFBD>n sobre GTK. Para configurar GTK hay que usar GNU
|
|
|
|
|
autoconf. Una vez descomprimido se pueden obtener las opciones usando
|
|
|
|
|
<tt>./configure --help</tt>.
|
|
|
|
|
|
|
|
|
|
El c<>digo de GTK adem<65>s contiene las fuentes completas de todos
|
|
|
|
|
los ejemplos usados en este manual, as<61> como los makefiles para
|
|
|
|
|
compilarlos.
|
|
|
|
|
|
|
|
|
|
Para comenzar nuestra introducci<63>n a GTK vamos a empezar con el
|
|
|
|
|
programa m<>s sencillo posible. Con <20>l vamos a crear una ventana de
|
|
|
|
|
200x200 <em/pixels/ que s<>lo se puede destruir desde el shell.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo base base.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Puede compilar el programa anterior con gcc tecleando:
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gcc base.c -o base `gtk-config --cflags --libs`
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El significado de la extra<72>a opci<63>n de compilaci<63>n se explica
|
|
|
|
|
m<EFBFBD>s adelante.
|
|
|
|
|
|
|
|
|
|
Todo programa que use GTK debe llamar a <tt>gtk/gtk.h</tt> donde se
|
|
|
|
|
declaran todas las variables, funciones, estructuras, etc. que ser<65>n
|
|
|
|
|
usadas en el programa.
|
|
|
|
|
|
|
|
|
|
La siguiente l<>nea:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Llama a la funci<63>n gtk_init (gint *argc, gchar *** argv) responsable
|
|
|
|
|
de `arrancar' la biblioteca y de establecer algunos par<61>metros (como son
|
|
|
|
|
los colores y los visuales por defecto), llama a gdk_init (gint *argc,
|
|
|
|
|
gchar *** argv) que inicializa la biblioteca para que pueda
|
|
|
|
|
utilizarse, establece los controladores de las se<73>ales y comprueba los
|
|
|
|
|
argumentos pasados a la aplicaci<63>n desde la l<>nea de comandos,
|
|
|
|
|
buscando alguno de los siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> <tt/--gtk-module/
|
|
|
|
|
<item> <tt/--g-fatal-warnings/
|
|
|
|
|
<item> <tt/--gtk-debug/
|
|
|
|
|
<item> <tt/--gtk-no-debug/
|
|
|
|
|
<item> <tt/--gdk-debug/
|
|
|
|
|
<item> <tt/--gdk-no-debug/
|
|
|
|
|
<item> <tt/--display/
|
|
|
|
|
<item> <tt/--sync/
|
|
|
|
|
<item> <tt/--no-xshm/
|
|
|
|
|
<item> <tt/--name/
|
|
|
|
|
<item> <tt/--class/
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
En el caso de que encuentre alguno lo quita de la lista, dejando todo
|
|
|
|
|
aquello que no reconozca para que el programa lo utilice o lo
|
|
|
|
|
ignore. As<41> se consigue crear un conjunto de argumentos que son
|
|
|
|
|
comunes a todas las aplicaciones basadas en GTK.
|
|
|
|
|
|
|
|
|
|
Las dos l<>neas de c<>digo siguientes crean y muestran una ventana.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento GTK_WINDOW_TOPLEVEL especifica que queremos que el gestor
|
|
|
|
|
de ventanas decore y sit<69>e la ventana. En lugar de crear una ventana
|
|
|
|
|
de tama<6D>o 0 x 0 toda ventana sin hijos por defecto es de 200 x 200, con
|
|
|
|
|
lo que se consigue que pueda ser manipulada.
|
|
|
|
|
|
|
|
|
|
La funci<63>n gtk_widget_show() le comunica a GTK que hemos acabado de
|
|
|
|
|
especificar los atributos del <em/widget/, y que por tanto puede
|
|
|
|
|
mostrarlo.
|
|
|
|
|
|
|
|
|
|
La <20>ltima l<>nea comienza el proceso del bucle principal de GTK.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_main ();
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Otra llamada que siempre est<73> presente en cualquier aplicaci<63>n es
|
|
|
|
|
gtk_main(). Cuando el control llega a ella, GTK se queda dormido
|
|
|
|
|
esperando a que suceda alg<6C>n tipo de evento de las X (como puede ser
|
|
|
|
|
pulsar un bot<6F>n), que pase el tiempo necesario para que el usuario
|
|
|
|
|
haga algo, o que se produzcan notificaciones de IO de archivos. En
|
|
|
|
|
nuestro caso concreto todos los eventos ser<65>n ignorados.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Programa <20>Hola Mundo<64> en GTK
|
|
|
|
|
<p>
|
|
|
|
|
El siguiente ejemplo es un programa con un <em/widget/ (un
|
|
|
|
|
bot<EFBFBD>n). Simplemente es la versi<73>n de GTK del cl<63>sico <20>hola mundo<64>.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* comienzo del ejemplo holamundo */
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* <20>sta es una funci<63>n respuesta (callback). Sus argumentos
|
|
|
|
|
son ignorados por en este ejemplo */
|
|
|
|
|
void hello (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
g_print ("Hola mundo\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
/* si se devuelve FALSE al administrador de llamadas
|
|
|
|
|
* "delete_event", GTK emitir<69> la se<73>al de destrucci<63>n
|
|
|
|
|
* "destroy". Esto es <20>til para di<64>logos emergentes del
|
|
|
|
|
* tipo: <20>Seguro que desea salir?
|
|
|
|
|
|
|
|
|
|
g_print ("Ha ocurrido un evento delete\n");
|
|
|
|
|
|
|
|
|
|
/* Cambiando TRUE por FALSE la ventana se destruir<69> con
|
|
|
|
|
* "delete_event"*/
|
|
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* otra respuesta */
|
|
|
|
|
void destroy (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* GtkWidget es el tipo de almacenamiento usado para los
|
|
|
|
|
* widgets */
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
|
|
|
|
|
/* En cualquier aplicaci<63>n hay que realizar la siguiente
|
|
|
|
|
* llamada. Los argumentos son tomados de la l<>nea de comandos
|
|
|
|
|
* y devueltos a la aplicaci<63>n. */
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* creamos una ventana nueva */
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
/* Cuando la ventana recibe la se<73>al "delete_event" (emitida
|
|
|
|
|
* por el gestor de ventanas, normalmente mediante la opci<63>n
|
|
|
|
|
* 'close', o en la barra del t<>tulo) hacemos que llame a la
|
|
|
|
|
* funci<63>n delete_event() tal y como ya hemos visto. Los datos
|
|
|
|
|
* pasados a la funci<63>n de respuesta son NULL, y ser<65>n ignorados. */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (delete_event), NULL);
|
|
|
|
|
|
|
|
|
|
/* Aqu<71> conectamos el evento "destroy" con el administrador de
|
|
|
|
|
* se<73>ales. El evento se produce cuando llamamos a
|
|
|
|
|
* gtk_widget_destroy() desde la ventana o si devolvemos 'FALSE'
|
|
|
|
|
* en la respuesta "delete_event". */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (destroy), NULL);
|
|
|
|
|
|
|
|
|
|
/* establecemos el ancho del borde de la ventana. */
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* creamos un bot<6F>n nuevo con la etiqueta "Hola mundo" */
|
|
|
|
|
boton = gtk_button_new_with_label ("Hola mundo");
|
|
|
|
|
|
|
|
|
|
/* Cuando el bot<6F>n recibe la se<73>al "clicked" llama a la
|
|
|
|
|
* funci<63>n hello() pas<61>ndole NULL como argumento. (La
|
|
|
|
|
* funci<63>n ya ha sido definida arriba). */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (hello), NULL);
|
|
|
|
|
|
|
|
|
|
/* Esto har<61> que la ventana sea destruida llamando a
|
|
|
|
|
* gtk_widget_destroy(ventana) cuando se produzca "clicked". Una
|
|
|
|
|
* vez mas la se<73>al de destrucci<63>n puede provenir del gestor
|
|
|
|
|
* de ventanas o de aqu<71>. */
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
|
|
|
|
GTK_OBJECT (ventana));
|
|
|
|
|
|
|
|
|
|
/* Ahora empaquetamos el bot<6F>n en la ventana (usamos un gtk
|
|
|
|
|
* container ). */
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), boton);
|
|
|
|
|
|
|
|
|
|
/* El <20>ltimo paso es representar el nuevo widget... */
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
/* y la ventana */
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
/* Todas las aplicaciones basadas en GTK deben tener una llamada
|
|
|
|
|
* gtk_main() ya que el control termina justo aqu<71> y debe
|
|
|
|
|
* esperar a que suceda alg<6C>n evento */
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo*/
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Compilando Hello World
|
|
|
|
|
<p>
|
|
|
|
|
Para compilar el ejemplo hay que usar:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gcc -Wall -g helloworld.c -o hello_world `gtk-config --cflags` \
|
|
|
|
|
`gtk-config --libs`
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Usamos el programa <tt>gtk-config</>, que ya viene (y se instala) con
|
|
|
|
|
la biblioteca. Es muy <20>til porque `conoce' que opciones son
|
|
|
|
|
necesarias para compilar programas que usen gtk. <tt>gtk-config
|
|
|
|
|
--cflags</tt> dar<61> una lista con los directorios donde el
|
|
|
|
|
compilador debe buscar ficheros <20>include<64>. A su vez <tt>gtk-config
|
|
|
|
|
--libs</tt> nos permite saber las bibliotecas que el compilador
|
|
|
|
|
intentar<EFBFBD> enlazar y d<>nde buscarlas.
|
|
|
|
|
|
|
|
|
|
Hay que destacar que las comillas simples en la orden de
|
|
|
|
|
compilaci<EFBFBD>n son absolutamente necesarias.
|
|
|
|
|
|
|
|
|
|
Las bibliotecas que se enlazan normalmente son:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
|
|
|
|
|
<item>La biblioteca GTK (-lgtk), la biblioteca de <em/widgets/ que se
|
|
|
|
|
encuentra encima de GDK.
|
|
|
|
|
|
|
|
|
|
<item>La biblioteca GDK (-lgdk), el wrapper de Xlib.
|
|
|
|
|
|
|
|
|
|
<item>La biblioteca glib (-lglib), que contiene diversas funciones. En
|
|
|
|
|
nuestro ejemplo s<>lo hemos usado g_print(). GTK est<73> construida
|
|
|
|
|
encima de glib por lo que simpre se usar<61>. Vea la secci<63>n <ref
|
|
|
|
|
id="sec_glib" name="glib"> para m<>s detalles.
|
|
|
|
|
|
|
|
|
|
<item>La biblioteca Xlib (-lX11) que es usada por GDK.
|
|
|
|
|
|
|
|
|
|
<item> La biblioteca Xext (-lXext) contiene c<>digo para
|
|
|
|
|
<em/pixmaps/ de memoria compartida y otras extensiones.
|
|
|
|
|
|
|
|
|
|
<item>La biblioteca matem<65>tica (-lm). Es usada por GTK para
|
|
|
|
|
diferentes cosas.
|
|
|
|
|
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Teor<6F>a de se<73>ales y respuestas
|
|
|
|
|
<p>
|
|
|
|
|
Antes de profundizar en <tt/holamundo/ vamos a discutir las
|
|
|
|
|
se<EFBFBD>ales y las respuestas. GTK es un toolkit (conjunto de
|
|
|
|
|
herramientas) gestionadas mediante eventos. Esto quiere decir que GTK
|
|
|
|
|
<EFBFBD>duerme<EFBFBD> en gtk_main hasta que se recibe un evento, momento en el
|
|
|
|
|
cual se transfiere el control a la funci<63>n adecuada.
|
|
|
|
|
|
|
|
|
|
El control se transfiere mediante <20>se<73>ales<65>. (Conviene destacar
|
|
|
|
|
que las se<73>ales de GTK no son iguales que las de los sistemas
|
|
|
|
|
UNIX, aunque la terminolog<6F>a es la misma.) Cuando sucede un evento,
|
|
|
|
|
como por ejemplo la pulsaci<63>n de un bot<6F>n, se <20>emitir<69><72> la
|
|
|
|
|
se<EFBFBD>al apropiada por el <em/widget/ pulsado. As<41> es como GTK
|
|
|
|
|
proporciona la mayor parte de su utilidad. Hay un conjunto de
|
|
|
|
|
se<EFBFBD>ales que todos los <em/widgets/ heredan, como por ejemplo
|
|
|
|
|
<EFBFBD>destroy<EFBFBD> y hay se<73>ales que son espec<65>ficas de cada
|
|
|
|
|
<em/widget/, como por ejemplo la se<73>al <20>toggled<65> de un bot<6F>n
|
|
|
|
|
de selecci<63>n (bot<6F>n <em/toggle/).
|
|
|
|
|
|
|
|
|
|
Para que un bot<6F>n haga algo crearemos un controlador que se encarga de
|
|
|
|
|
recoger las se<73>ales y llamar a la funci<63>n apropiada. Esto se hace
|
|
|
|
|
usando una funci<63>n como:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_signal_connect( GtkObject *objeto,
|
|
|
|
|
gchar *nombre,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
gpointer datos_func );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Donde el primer argumento es el <em/widget/ que emite la se<73>al, el
|
|
|
|
|
segundo el nombre de la se<73>al que queremos `cazar', el tercero es
|
|
|
|
|
la funci<63>n a la que queremos que se llame cuando se `cace' la
|
|
|
|
|
se<EFBFBD>al y el cuarto los datos que queremos pasarle a esta funci<63>n.
|
|
|
|
|
|
|
|
|
|
La funci<63>n especificada en el tercer argumento se denomina <20>funci<63>n
|
|
|
|
|
de respuesta<74> y debe tener la forma siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void callback_func( GtkWidget *widget,
|
|
|
|
|
gpointer datos_respuesta );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Donde el primer argumento ser<65> un puntero al <em/widget/ que emiti<74> la
|
|
|
|
|
se<EFBFBD>al, y el segundo un puntero a los datos pasados a la funci<63>n tal y
|
|
|
|
|
como hemos visto en el <20>ltimo argumento a gtk_signal_connect().
|
|
|
|
|
|
|
|
|
|
Conviene destacar que la declaraci<63>n de la funci<63>n de respuesta debe
|
|
|
|
|
servir s<>lo como gu<67>a general, ya que algunas se<73>ales espec<65>ficas
|
|
|
|
|
pueden generar diferentes par<61>metros de llamada. Por ejemplo, la se<73>al
|
|
|
|
|
de GtkCList <20>select_row<6F> proporciona los par<61>metros fila y columna.
|
|
|
|
|
|
|
|
|
|
Otra llamada usada en el ejemplo del hola mundo es:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_signal_connect_object( GtkObject *objeto,
|
|
|
|
|
gchar *nombre,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
GtkObject *slot_object );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect_object() es id<69>ntica a gtk_signal_connect() excepto
|
|
|
|
|
en que la funci<63>n de llamada s<>lo usa un argumento, un puntero a un
|
|
|
|
|
objeto GTK. Por tanto cuando usemos esta funci<63>n para conectar
|
|
|
|
|
se<EFBFBD>ales, la funci<63>n de respuesta debe ser de la forma:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void callback_func( GtkObject *object );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Donde, por regla general, el objeto es un <em/widget/. Sin embargo no
|
|
|
|
|
es normal establecer una respuesta para gtk_signal_connect_object. En
|
|
|
|
|
lugar de ello llamamos a una funci<63>n de GTK que acepte un <em/widget/
|
|
|
|
|
o un objeto como un argumento, tal y como se vio en el ejemplo hola
|
|
|
|
|
mundo.
|
|
|
|
|
|
|
|
|
|
<EFBFBD>Para qu<71> sirve tener dos funciones para conectar se<73>ales? Simplemente
|
|
|
|
|
para permitir que las funciones de respuesta puedan tener un n<>mero
|
|
|
|
|
diferente de argumentos. Muchas funciones de GTK s<>lo aceptan un
|
|
|
|
|
puntero a un GtkWidget como argumento, por lo que tendr<64> que usar
|
|
|
|
|
gtk_signal_connect_object() con estas funciones, mientras que
|
|
|
|
|
probablemente tenga que suministrarle informaci<63>n adicional a sus
|
|
|
|
|
funciones.
|
|
|
|
|
|
|
|
|
|
<!-- XXX Completamente revisado hasta aqu<71> -------------------------- -->
|
|
|
|
|
<sect1>Eventos
|
|
|
|
|
<p>
|
|
|
|
|
Adem<EFBFBD>s del mecanismo de se<73>ales descrito arriba existe otro conjunto
|
|
|
|
|
de <em>eventos</em> que reflejan como las X manejan los eventos. Se
|
|
|
|
|
pueden asignar funciones de respuesta a estos eventos. Los eventos
|
|
|
|
|
son:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> event
|
|
|
|
|
<item> button_press_event
|
|
|
|
|
<item> button_release_event
|
|
|
|
|
<item> motion_notify_event
|
|
|
|
|
<item> delete_event
|
|
|
|
|
<item> destroy_event
|
|
|
|
|
<item> expose_event
|
|
|
|
|
<item> key_press_event
|
|
|
|
|
<item> key_release_event
|
|
|
|
|
<item> enter_notify_event
|
|
|
|
|
<item> leave_notify_event
|
|
|
|
|
<item> configure_event
|
|
|
|
|
<item> focus_in_event
|
|
|
|
|
<item> focus_out_event
|
|
|
|
|
<item> map_event
|
|
|
|
|
<item> unmap_event
|
|
|
|
|
<item> property_notify_event
|
|
|
|
|
<item> selection_clear_event
|
|
|
|
|
<item> selection_request_event
|
|
|
|
|
<item> selection_notify_event
|
|
|
|
|
<item> proximity_in_event
|
|
|
|
|
<item> proximity_out_event
|
|
|
|
|
<item> drag_begin_event
|
|
|
|
|
<item> drag_request_event
|
|
|
|
|
<item> drag_end_event
|
|
|
|
|
<item> drop_enter_event
|
|
|
|
|
<item> drop_leave_event
|
|
|
|
|
<item> drop_data_available_event
|
|
|
|
|
<item> other_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Para conectar una funci<63>n de respuesta a alguno de los eventos
|
|
|
|
|
anteriores debe usar la funci<63>n gtk_signal_connect, tal y como se
|
|
|
|
|
descrivi<EFBFBD> anteriormente, utilizando en el par<61>metro <tt/name/ uno de
|
|
|
|
|
los nombres de los eventos que se acaban de mencionar. La funci<63>n de
|
|
|
|
|
respuesta para los eventos tiene un forma ligeramente diferente de la
|
|
|
|
|
que tiene para las se<73>ales:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void callback_func( GtkWidget *widget,
|
|
|
|
|
GdkEvent *event,
|
|
|
|
|
gpointer callback_data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
GdkEvent es una estructura <tt/union/ cuyo tipo depende de cual de los
|
|
|
|
|
eventos anteriores haya ocurrido. Para que podamos decir que evento se
|
|
|
|
|
ha lanzado cada una de las posibles alternativas posee un par<61>metro
|
|
|
|
|
<tt/type/ que refleja cual es el evento en cuesti<74>n. Los otros
|
|
|
|
|
componentes de la estructura depender<65>n del tipo de evento. Algunos
|
|
|
|
|
valores posibles son:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GDK_NOTHING
|
|
|
|
|
GDK_DELETE
|
|
|
|
|
GDK_DESTROY
|
|
|
|
|
GDK_EXPOSE
|
|
|
|
|
GDK_MOTION_NOTIFY
|
|
|
|
|
GDK_BUTTON_PRESS
|
|
|
|
|
GDK_2BUTTON_PRESS
|
|
|
|
|
GDK_3BUTTON_PRESS
|
|
|
|
|
GDK_BUTTON_RELEASE
|
|
|
|
|
GDK_KEY_PRESS
|
|
|
|
|
GDK_KEY_RELEASE
|
|
|
|
|
GDK_ENTER_NOTIFY
|
|
|
|
|
GDK_LEAVE_NOTIFY
|
|
|
|
|
GDK_FOCUS_CHANGE
|
|
|
|
|
GDK_CONFIGURE
|
|
|
|
|
GDK_MAP
|
|
|
|
|
GDK_UNMAP
|
|
|
|
|
GDK_PROPERTY_NOTIFY
|
|
|
|
|
GDK_SELECTION_CLEAR
|
|
|
|
|
GDK_SELECTION_REQUEST
|
|
|
|
|
GDK_SELECTION_NOTIFY
|
|
|
|
|
GDK_PROXIMITY_IN
|
|
|
|
|
GDK_PROXIMITY_OUT
|
|
|
|
|
GDK_DRAG_BEGIN
|
|
|
|
|
GDK_DRAG_REQUEST
|
|
|
|
|
GDK_DROP_ENTER
|
|
|
|
|
GDK_DROP_LEAVE
|
|
|
|
|
GDK_DROP_DATA_AVAIL
|
|
|
|
|
GDK_CLIENT_EVENT
|
|
|
|
|
GDK_VISIBILITY_NOTIFY
|
|
|
|
|
GDK_NO_EXPOSE
|
|
|
|
|
GDK_OTHER_EVENT /* En desuso, usar filtros en lugar de ella */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Por lo tanto para conectar una funci<63>n de respuesta a uno de estos
|
|
|
|
|
eventos debemos usar algo como:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_connect( GTK_OBJECT(boton), "button_press_event",
|
|
|
|
|
GTK_SIGNAL_FUNC(button_press_callback),
|
|
|
|
|
NULL);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Por supuesto se asume que <tt/boton/ es un <em/widget/
|
|
|
|
|
GtkButton. Cada vez que el puntero del rat<61>n se encuentre sobre el
|
|
|
|
|
bot<EFBFBD>n y <20>ste sea presionado, se llamar<61> a la funci<63>n
|
|
|
|
|
<tt/button_press_callback/. Esta funci<63>n puede declararse as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static gint button_press_event (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event,
|
|
|
|
|
gpointer data);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Conviene destacar que se puede declarar el segundo argumento como
|
|
|
|
|
<tt/GdkEventButton/ porque sabemos que este tipo de evento ocurrir<69>
|
|
|
|
|
cuando se llame a la funci<63>n.
|
|
|
|
|
|
|
|
|
|
El valor devuelto por esta funci<63>n es usado para saber si el evento
|
|
|
|
|
debe ser propagado a un nivel m<>s profundo dentro del mecanismo de
|
|
|
|
|
GTK para gestionar los eventos. Si devuelve TRUE el evento ya ha sido
|
|
|
|
|
gestionado y por tanto no tiene que ser tratado por el mecanismo de
|
|
|
|
|
gesti<EFBFBD>n. Por contra si devuelve FALSE se continua con la gesti<74>n
|
|
|
|
|
normal del evento. Para m<>s detalles se recomienda leer la secci<63>n
|
|
|
|
|
donde se aclara como se produce el proceso de propagaci<63>n.
|
|
|
|
|
|
|
|
|
|
Para m<>s detalles acerca de los tipos de informaci<63>n GdkEvent
|
|
|
|
|
consultar el ap<61>ndice <ref id="sec_GDK_Event_Types" name="Tipos de
|
|
|
|
|
eventos GDK">.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Aclaraci<63>n de Hello World
|
|
|
|
|
<p>
|
|
|
|
|
Ahora que conocemos la teor<6F>a vamos a aclarar las ideas estudiando
|
|
|
|
|
en detalle el programa <tt/helloworld/.
|
|
|
|
|
|
|
|
|
|
<EFBFBD>sta es la funci<63>n respuesta a la que se llamar<61> cuando se
|
|
|
|
|
pulse el bot<6F>n. En el ejemplo ignoramos tanto el <em/widget/ como
|
|
|
|
|
la informaci<63>n, pero no es dif<69>cil usarlos. El siguiente ejemplo
|
|
|
|
|
usar<EFBFBD> la informaci<63>n que recibe como argumento para decirnos que
|
|
|
|
|
bot<EFBFBD>n fue presionado.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void hello (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
g_print ("Hello World\n");
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La siguiente respuesta es un poco especial, el <20>delete_event<6E> ocurre
|
|
|
|
|
cuando el gestor de ventanas env<6E>a este evento a la aplicaci<63>n. Aqu<71>
|
|
|
|
|
podemos decidir que hacemos con estos eventos. Los podemos ignorar,
|
|
|
|
|
dar alg<6C>n tipo de respuesta, o simplemente terminar la aplicaci<63>n.
|
|
|
|
|
|
|
|
|
|
El valor devuelto en esta respuesta le permite a GTK saber que tiene
|
|
|
|
|
que hacer. Si devolvemos TRUE, estamos diciendo que no queremos que se
|
|
|
|
|
emita la se<73>al <20>destroy<6F> y por lo tanto queremos que nuestra
|
|
|
|
|
aplicaci<EFBFBD>n siga ejecut<75>ndose. Si devolvemos FALSE, decimos que
|
|
|
|
|
se emita <20>destroy<6F>, lo que har<61> que se ejecute nuestro manejador
|
|
|
|
|
de se<73>al de <20>destroy<6F>.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
g_print ("delete event occured\n");
|
|
|
|
|
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Con el siguiente ejemplo presentamos otra funci<63>n de respuesta que hace
|
|
|
|
|
que el programa salga llamando a gtk_main_quit(). Con esta funci<63>n le
|
|
|
|
|
decimos a GTK que salga de la rutina gtk_main() cuando vuelva a estar
|
|
|
|
|
en ella.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void destroy (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como el lector probablemente ya sabe toda aplicaci<63>n debe tener una
|
|
|
|
|
funci<EFBFBD>n main(), y una aplicaci<63>n GTK no va a ser menos. Todas las
|
|
|
|
|
aplicaciones GTK tambi<62>n tienen una funci<63>n de este tipo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Las l<>neas siguientes declaran un puntero a una estructura del tipo
|
|
|
|
|
GtkWidget, que se utilizar<61>n m<>s adelante para crear una ventana y un
|
|
|
|
|
bot<EFBFBD>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> tenemos otra vez a gtk_init. Como antes arranca el conjunto de
|
|
|
|
|
herramientas y filtra las opciones introducidas en la l<>nea de
|
|
|
|
|
<EFBFBD>rdenes. Cualquier argumento que sea reconocido ser<65> borrado de la
|
|
|
|
|
lista de argumentos, de modo que la aplicaci<63>n recibir<69> el resto.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Ahora vamos a crear una ventana. Simplemente reservamos memoria para
|
|
|
|
|
la estructura GtkWindow *ventana, con lo que ya tenemos una nueva
|
|
|
|
|
ventana, ventana que no se mostrar<61> hasta que llamemos a
|
|
|
|
|
gtk_widget_show (ventana) hacia el final del programa.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> tenemos un ejemplo de como conectar un manejador de se<73>al a un
|
|
|
|
|
objeto, en este caso, la ventana. La se<73>al a cazar ser<65>
|
|
|
|
|
<EFBFBD>destroy<EFBFBD>. Esta se<73>al se emite cuando utilizamos el administrador de
|
|
|
|
|
ventanas para matar la ventana (y devolvemos TRUE en el manejador
|
|
|
|
|
<EFBFBD>delete_event<EFBFBD>), o cuando usamos llamamos a gtk_widget_destroy()
|
|
|
|
|
pas<EFBFBD>ndole el <em/widget/ que representa la ventana como argumento.
|
|
|
|
|
As<EFBFBD> conseguimos manejar los dos casos con una simple llamada a la
|
|
|
|
|
funci<EFBFBD>n destroy () (definida arriba) pas<61>ndole NULL como argumento y
|
|
|
|
|
ella acabar<61> con la aplicaci<63>n por nosotros.
|
|
|
|
|
|
|
|
|
|
GTK_OBJECT y GTK_SIGNAL_FUNC son macros que realizan la comprobaci<63>n y
|
|
|
|
|
transformaci<EFBFBD>n de tipos por nosotros. Tambi<62>n aumentan la legibilidad
|
|
|
|
|
del c<>digo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (destroy), NULL);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La siguiente funci<63>n establece un atributo a un objeto contenedor
|
|
|
|
|
(discutidos luego). En este caso le pone a la ventana un <20>rea
|
|
|
|
|
negra de 10 <em/pixels/ de ancho donde no habr<62>n <em/widgets/. Hay
|
|
|
|
|
funciones similares que ser<65>n tratadas con m<>s detalle en la secci<63>n
|
|
|
|
|
<ref id="sec_setting_widget_attributes" name="Estableciendo los
|
|
|
|
|
atributos de los <em/widgets/">
|
|
|
|
|
|
|
|
|
|
De nuevo, GTK_CONTAINER es una macro que se encarga de la conversi<73>n
|
|
|
|
|
entre tipos
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La siguiente llamada crea un nuevo bot<6F>n. Reserva espacio en la
|
|
|
|
|
memoria para una nueva estructura del tipo GtkWidget, la inicializa
|
|
|
|
|
y hace que el puntero <tt/boton/ apunte a esta estructura. Su etiqueta
|
|
|
|
|
ser<EFBFBD>: "Hola mundo".
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
boton = gtk_button_new_with_label ("Hola mundo");
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Ahora hacemos que el bot<6F>n sea <20>til, para ello enlazamos el bot<6F>n con
|
|
|
|
|
el manejador de se<73>ales para que cuando emita la se<73>al <20>clicked<65>, se
|
|
|
|
|
llame a nuestra funci<63>n hola(). Los datos adicionales ser<65>n
|
|
|
|
|
ignorados, por lo que simplemente le pasaremos NULL a la funci<63>n
|
|
|
|
|
respuesta. Obviamente se emitir<69> la se<73>al <20>clicked<65> cuando pulsemos
|
|
|
|
|
en el bot<6F>n con el rat<61>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (hola), NULL);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
XXX
|
|
|
|
|
Ahora vamos a usar el bot<6F>n para terminar nuestro programa. As<41>
|
|
|
|
|
aclararemos c<>mo es posible que la se<73>al <20>destroy<6F> sea emitida tanto
|
|
|
|
|
por el gestor de ventanas como por nuestro programa. Cuando el bot<6F>n
|
|
|
|
|
es pulsado, al igual que arriba, se llama a la primera funci<63>n
|
|
|
|
|
respuesta hello() y despu<70>s se llamar<61> a esta funci<63>n. Las funciones
|
|
|
|
|
respuesta ser<65>n ejecutadas en el orden en que sean conectadas. Como la
|
|
|
|
|
funci<EFBFBD>n gtk_widget_destroy() s<>lo acepta un GtkWidget como argumento,
|
|
|
|
|
utilizaremos gtk_signal_connect_object() en lugar de
|
|
|
|
|
gtk_signal_connect().
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
|
|
|
|
GTK_OBJECT (ventana));
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La siguiente llamada sirve para empaquetar (m<>s detalles luego). Se
|
|
|
|
|
usa para decirle a GTK que el bot<6F>n debe estar en la ventana d<>nde
|
|
|
|
|
ser<EFBFBD> mostrado. Conviene destacar que un contenedor GTK s<>lo puede
|
|
|
|
|
contener un <em/widget/. Existen otros <em/widgets/ (descritos
|
|
|
|
|
despu<EFBFBD>s) que sirven para contener y establecer la disposici<63>n de
|
|
|
|
|
varios <em/widgets/ de diferentes formas.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), boton);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Ahora ya tenemos todo bien organizado. Como todos los controladores de
|
|
|
|
|
las se<73>ales ya est<73>n en su sitio, y el bot<6F>n est<73> situado en la
|
|
|
|
|
ventana donde queremos que est<73>, s<>lo nos queda pedirle a GTK que
|
|
|
|
|
muestre todos los <em/widgets/ en pantalla. El <em/widget/ ventana ser<65>
|
|
|
|
|
el <20>ltimo en mostrarse queremos que aparezca todo de golpe, en vez de
|
|
|
|
|
ver aparecer la ventana, y despu<70>s ver aparecer el bot<6F>n. De todas
|
|
|
|
|
formas con un ejemplo tan simple nunca se notar<61>a cual es el orden de
|
|
|
|
|
aparici<EFBFBD>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Llamamos a gtk_main() que espera hasta que el servidor X le comunique
|
|
|
|
|
que se ha producido alg<6C>n evento para emitir las se<73>ales apropiadas.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_main ();
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Por <20>ltimo el `return' final que devuelve el control cuando gtk_quit()
|
|
|
|
|
sea invocada.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
return 0;
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Cuando pulsemos el bot<6F>n del rat<61>n el <em/widget/ emite la se<73>al
|
|
|
|
|
correspondiente <20>clicked<65>. Para que podamos usar la informaci<63>n el
|
|
|
|
|
programa activa el gestor de eventos que al recibir la se<73>al llama a
|
|
|
|
|
la funci<63>n que hemos elegido. En nuestro ejemplo cuando pulsamos el
|
|
|
|
|
bot<EFBFBD>n se llama a la funci<63>n hello() con NULL como argumento y adem<65>s
|
|
|
|
|
se invoca al siguiente manipulador de se<73>al. As<41> conseguimos que se
|
|
|
|
|
llame a la funci<63>n gtk_widget_destroy() con el <em/widget/ asociado a
|
|
|
|
|
la ventana como argumento, lo que destruye al <em/widget/. Esto hace
|
|
|
|
|
que la ventana emita la se<73>al <20>destroy<6F>, que es cazada, y que llama
|
|
|
|
|
a nuestra funci<63>n respuesta destroy(), que simplemente sale de GTK.
|
|
|
|
|
|
|
|
|
|
Otra posibilidad es usar el gestor de ventanas para acabar con la
|
|
|
|
|
aplicaci<EFBFBD>n. Esto emitir<69> <20>delete_event<6E> que har<61> que se
|
|
|
|
|
llame a nuestra funci<63>n manejadora correspondiente. Si en la
|
|
|
|
|
funci<EFBFBD>n manejadora <20>delete_event<6E> devolvemos TRUE la ventana se
|
|
|
|
|
quedar<EFBFBD> como si nada hubiese ocurrido, pero si devolvemos FALSE GTK
|
|
|
|
|
emitir<EFBFBD> la se<73>al <20>destroy<6F> que, por supuesto, llamar<61> a la
|
|
|
|
|
funci<EFBFBD>n respuesta <20>destroy<6F>, que saldr<64> de GTK.
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Avanzando
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Tipos de datos
|
|
|
|
|
<p>
|
|
|
|
|
Existen algunos detalles de los ejemplos anteriores que hay que aclarar.
|
|
|
|
|
Los tipos gint, gchar, etc. que puede ver por ah<61> son typedefs a int y
|
|
|
|
|
a char respectivamente. Sirven para que no haya que tener en cuenta el
|
|
|
|
|
tama<EFBFBD>o de cada uno de ellos a la hora de hacer c<>lculos.
|
|
|
|
|
|
|
|
|
|
Un buen ejemplo es <tt/gint32/ que es un entero de 32 bits independientemente
|
|
|
|
|
de la plataforma, bien sea un Alpha de 64 bits o un i386 de 32. Todas las
|
|
|
|
|
definiciones son muy intuitivas y se encuentran definidas en glib/glib.h
|
|
|
|
|
(que se incluye desde gtk.h).
|
|
|
|
|
|
|
|
|
|
Probablemente el lector se haya dado cuenta de que se puede usar GtkWidget
|
|
|
|
|
cuando la funci<63>n llama a un GtkObject. Esto es debido a que GTK
|
|
|
|
|
est<EFBFBD> orienta a objetos y un <em/widget/ es un GtkObject.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>M<>s sobre el manejo de se<73>ales
|
|
|
|
|
<p>
|
|
|
|
|
Si estudiamos en mayor profundidad la declaraci<63>n de
|
|
|
|
|
gtk_signal_connect:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_signal_connect( GtkObject *object,
|
|
|
|
|
gchar *name,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
gpointer func_data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Podemos darnos cuenta de que el valor devuelto es del tipo gint. Este
|
|
|
|
|
valor es una etiqueta que identifica a la funci<63>n de respuesta. Tal
|
|
|
|
|
y como ya vimos podemos tener tantas funciones de respuesta por
|
|
|
|
|
se<EFBFBD>al y objeto como sean necesarias, y cada una de ellas se
|
|
|
|
|
ejecutar<EFBFBD> en el mismo orden en el que fueron enlazadas.
|
|
|
|
|
|
|
|
|
|
Esta etiqueta nos permite eliminar la funci<63>n respuesta de la lista
|
|
|
|
|
usando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_signal_disconnect( GtkObject *object,
|
|
|
|
|
gint id );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Por lo tanto podemos desconectar un manejador de se<73>al pas<61>ndole
|
|
|
|
|
a la funci<63>n anterior el <em/widget/ del que queremos desconectar y
|
|
|
|
|
la etiqueta o id devuelta por una de las funciones signal_connect.
|
|
|
|
|
|
|
|
|
|
Otra funci<63>n que se usa para quitar desconectar todos los
|
|
|
|
|
controladores de un objeto es:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_signal_handlers_destroy( GtkObject *object );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta llamada es bastante auto explicativa. Simplemente quitamos todos los
|
|
|
|
|
controladores de se<73>ales del objeto que pasamos como primer argumento.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Un Hello World mejorado.
|
|
|
|
|
<p>
|
|
|
|
|
Vamos a mejorar el ejemplo para obtener una visi<73>n m<>s amplia
|
|
|
|
|
sobre el manejo de se<73>ales y respuestas. Tambi<62>n introduciremos
|
|
|
|
|
los <em/widgets/ usados para empaquetar.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo helloworld2 */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* Nuestra respuesta mejorada. Los argumentos de la funci<63>n se
|
|
|
|
|
* imprimen en el stdout.*/
|
|
|
|
|
void callback (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
g_print ("Hello again - %s was pressed\n", (char *) data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* otra respuesta*/
|
|
|
|
|
void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
/* GtkWidget es el tipo de almacenamiento usado para los wigtes*/
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *caja1;
|
|
|
|
|
|
|
|
|
|
/* Esta llamada est<73> presente en todas las aplicaciones basadas
|
|
|
|
|
* en GTK. Los argumentos introducidos a la aplicaci<63>n*/
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* creamos una nueva ventana*/
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
/* Esta funci<63>n es nueva, pone como t<>tulo de la ventana
|
|
|
|
|
* "<22>Hola botones!"*/
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "<22>Hola botones!");
|
|
|
|
|
|
|
|
|
|
/* Establecemos el controlador para la llamada delete_event que
|
|
|
|
|
* termina la aplicaci<63>n inmediatamente. */
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (delete_event), NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Establecemos el ancho del borde de la ventana.*/
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* Creamos una caja donde empaquetaremos los widgets. El
|
|
|
|
|
* procedimiento de empaquetamiento se describe en detalle en la
|
|
|
|
|
* secci<63>n correspondiente. La caja no se ve realmente, s<>lo
|
|
|
|
|
* sirve para introducir los widgets. */
|
|
|
|
|
caja1 = gtk_hbox_new(FALSE, 0);
|
|
|
|
|
|
|
|
|
|
/* ponemos la caja en la ventana principal */
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), caja1);
|
|
|
|
|
|
|
|
|
|
/* Creamos un nuevo bot<6F>n con la etiqueta "Bot<6F>n 1". */
|
|
|
|
|
boton = gtk_button_new_with_label ("Bot<6F>n 1");
|
|
|
|
|
|
|
|
|
|
/* Cada vez que el bot<6F>n sea pulsado llamamos a la funci<63>n
|
|
|
|
|
* "callback" con un puntero a "bot<6F>n 1" como argumento. */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (callback), (gpointer) "bot<6F>n 1");
|
|
|
|
|
|
|
|
|
|
/* En lugar de gtk_container_add empaquetamos el bot<6F>n en la
|
|
|
|
|
* caja invisible, que a su vez ha sido empaquetado en la
|
|
|
|
|
* ventana. */
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(caja1), boton, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
/* Siempre se debe realizar este paso. Sirve para decirle a GTK
|
|
|
|
|
* que los preparativos del bot<6F>n ya se han finalizado y que
|
|
|
|
|
* por tanto puede ser mostrado. */
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
/* hacemos lo mismo para crear un segundo bot<6F>n. */
|
|
|
|
|
boton = gtk_button_new_with_label ("Bot<6F>n 2");
|
|
|
|
|
|
|
|
|
|
/* Llamamos a la misma funci<63>n de respuesta pero con diferente
|
|
|
|
|
* argumento: un puntero a "bot<6F>n 2". */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (callback), (gpointer) "bot<6F>n 2");
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(caja1), boton, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
/* El orden en que mostramos los botones no es realmente
|
|
|
|
|
* importante, pero se recomienda mostrar la ventana la <20>ltima
|
|
|
|
|
* para que todo aparezca de golpe. */
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(caja1);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
/* Esperamos en gtk_main a que comience el espect<63>culo.*/
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo*/
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Compile el programa usando los mismos argumentos que en el ejemplo
|
|
|
|
|
anterior. Probablemente ya se habr<62> dado cuenta de que no hay una
|
|
|
|
|
forma sencilla para terminar el programa, se debe usar el gestor de
|
|
|
|
|
ventanas o la l<>nea de comandos para ello. Un buen ejercicio para
|
|
|
|
|
el lector es introducir un tercer bot<6F>n que termine el
|
|
|
|
|
programa. Tambi<62>n puede resultar interesante probar las diferentes
|
|
|
|
|
opciones de gtk_box_pack_start() mientras lee la siguiente
|
|
|
|
|
secci<EFBFBD>n. Intente cambiar el tama<6D>o de la ventana y observe el
|
|
|
|
|
comportamiento.
|
|
|
|
|
|
|
|
|
|
Como <20>ltima nota, existe otra definici<63>n bastante <20>til:
|
|
|
|
|
gtk_widow_new() - GTK_WINDOW_DIALOG. Su comportamiento es un poco
|
|
|
|
|
diferente y debe ser usado para ventanas intermedias (cuadros de
|
|
|
|
|
di<EFBFBD>logo).
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect><em/Widgets/ usados para empaquetar
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
Al crear una aplicaci<63>n normalmente se quiere que haya m<>s de un
|
|
|
|
|
<em/widget/ por ventana. Nuestro primer ejemplo s<>lo usaba un
|
|
|
|
|
<em/widget/ por lo que us<75>bamos la funci<63>n gtk_container_add
|
|
|
|
|
para <20>empaquetar<61> el <em/widget/ en la ventana. Pero cuando cuando
|
|
|
|
|
se quiere poner m<>s de un <em/widget/ en una ventana, <20>C<EFBFBD>mo
|
|
|
|
|
podemos controlar donde aparecer<65> el <em/widget/?. Aqu<71> es donde
|
|
|
|
|
entra el empaquetamiento.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Empaquetamiento usando cajas
|
|
|
|
|
<p>
|
|
|
|
|
Normalmente para empaquetar se usan cajas, tal y como ya hemos
|
|
|
|
|
visto. <20>stas son <em/widgets/ invisibles que pueden contener
|
|
|
|
|
nuestros <em/widgets/ de dos formas diferentes, horizontal o
|
|
|
|
|
verticalmente. Al hacerlo de la primera forma los objetos son
|
|
|
|
|
insertados de izquierda a derecha o al rev<65>s (dependiendo de que
|
|
|
|
|
llamada se use). Lo mismo ocurre en los verticales (de arriba a bajo o
|
|
|
|
|
al rev<65>s). Se pueden usar tantas cajas como se quieran para
|
|
|
|
|
conseguir cualquier tipo de efecto.
|
|
|
|
|
|
|
|
|
|
Para crear una caja horizontal llamamos a gtk_hbox_new() y para las
|
|
|
|
|
verticales gtk_vbox_new(). Las funciones usadas para introducir
|
|
|
|
|
objetos dentro son gtk_box_pack_start() y gtk_box_pack_end(). La
|
|
|
|
|
primera llenar<61> de arriba a abajo o de izquierda a derecha. La
|
|
|
|
|
segunda lo har<61> al rev<65>s.
|
|
|
|
|
Usando estas funciones podemos ir metiendo <em/widgets/ con una
|
|
|
|
|
justificaci<EFBFBD>n a la izquierda o a la derecha y adem<65>s podemos
|
|
|
|
|
mezclarlas de cualquier manera para conseguir el efecto
|
|
|
|
|
deseado. Nosotros usaremos gtk_box_pack_start() en la mayoria de
|
|
|
|
|
nuestros ejemplos. Un objeto puede ser otro contenedor o un
|
|
|
|
|
<em/widget/. De hecho, muchos <em/widgets/ son contenedores,
|
|
|
|
|
incluyendo el <em/widget/ bot<6F>n (button) (aunque normalmente lo
|
|
|
|
|
<EFBFBD>nico que meteremos dentro ser<65> una etiqueta de texto).
|
|
|
|
|
|
|
|
|
|
Mediante el uso de estas funciones le decimos a GTK d<>nde queremos
|
|
|
|
|
situar nuestros widgets, y GTK podr<64>, por ejemplo, cambiarles el
|
|
|
|
|
tama<EFBFBD>o de forma autom<6F>tica y hacer otras cosas de
|
|
|
|
|
utilidad. Tambi<62>n hay unas cuantas opciones que tienen que ver con
|
|
|
|
|
la forma en la que los <em/widgets/ ser<65>n empaquetados. Como puede
|
|
|
|
|
imaginarse, este m<>todo nos da una gran flexibilidad a la hora de
|
|
|
|
|
colocar y crear <em/widgets/.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Detalles de la cajas.
|
|
|
|
|
<p>
|
|
|
|
|
Debido a esta flexibilidad el empaquetamiento puede ser confuso al
|
|
|
|
|
principio. Hay muchas opciones y no es obvio como encajan unas con
|
|
|
|
|
otras. Pero en la pr<70>ctica s<>lo hay cinco estilos diferentes.
|
|
|
|
|
|
|
|
|
|
<? <CENTER> >
|
|
|
|
|
<?
|
|
|
|
|
<IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528"
|
|
|
|
|
HEIGHT="235" ALT="Imagen de ejemplo sobre el empaquetado con cajas">
|
|
|
|
|
>
|
|
|
|
|
<? </CENTER> >
|
|
|
|
|
|
|
|
|
|
Cada l<>nea contiene una caja horizontal (hbox) con diferentes
|
|
|
|
|
botones. La llamada a gtk_box_pack es una manera de conseguir
|
|
|
|
|
empaquetar cada uno de los botones dentro de la caja. Eso s<>, cada uno
|
|
|
|
|
de ellos se empaqueta de la misma forma que el resto (se llama con los
|
|
|
|
|
mismos argumentos a gtk_box_pack_start()).
|
|
|
|
|
|
|
|
|
|
Esta es la declaraci<63>n de la funci<63>n gtk_box_pack_start:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_box_pack_start( GtkBox *box,
|
|
|
|
|
GtkWidget *hijo,
|
|
|
|
|
gint expand,
|
|
|
|
|
gint fill,
|
|
|
|
|
gint padding );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El primer argumento es la caja d<>nde se empaqueta, el segundo el
|
|
|
|
|
objeto. Por ahora el objeto ser<65> un bot<6F>n, ya que estamos
|
|
|
|
|
empaquetando botones dentro de las cajas.
|
|
|
|
|
|
|
|
|
|
El argumento <tt/expand/ de gtk_box_pack_start() y de
|
|
|
|
|
gtk_box_pack_end() controla si los <em/widgets/ son expandidos en la
|
|
|
|
|
caja para rellenar todo el espacio de la misma (TRUE) o si por el
|
|
|
|
|
contrario no se usa el espacio extra dentro de la caja
|
|
|
|
|
(FALSE). Poniendo FALSE en <em/expand/ podremos hacer que nuestros
|
|
|
|
|
<em/widgets/ tengan una justaficaci<63>n a la derecha o a la
|
|
|
|
|
izquierda. En caso contrario, los <em/widgets/ se expandir<69>n para
|
|
|
|
|
llenar toda la caja, y podemos conseguir el mismo efecto utilizando
|
|
|
|
|
s<EFBFBD>lo una de las funciones gtk_box_pack_start o pack_end.
|
|
|
|
|
|
|
|
|
|
El argumento <tt/fill/ de gtk_box controla si el espacio extra se mete
|
|
|
|
|
dentro de los objetos (TRUE) o como relleno extra (FALSE). S<>lo
|
|
|
|
|
tiene efecto si el argumento de expansi<73>n tambi<62>n es TRUE.
|
|
|
|
|
|
|
|
|
|
Al crear una nueva ventana la funci<63>n debe ser parecida a esta:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_hbox_new (gint homogeneous,
|
|
|
|
|
gint spacing);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/homogeneous/ (tanto para gtk_hbox_new como para
|
|
|
|
|
gtk_vbox_new) controla si cada objeto en la caja tiene el mismo
|
|
|
|
|
tama<EFBFBD>o (anchura en una hbox o altura en una vbox). Si se activa, el
|
|
|
|
|
argumento <tt/expand/ de las rutinas gtk_box_pack siempre estar<61>
|
|
|
|
|
activado.
|
|
|
|
|
|
|
|
|
|
Puede que el lector se est<73> haciendo la siguiente pregunta:
|
|
|
|
|
<EFBFBD>C<EFBFBD>al es la diferencia entre espaciar (establecido cuando se
|
|
|
|
|
crea la caja) y rellenar (determinado cuando se empaquetan los
|
|
|
|
|
elementos)? El espaciado se a<>ade entre objetos, y el rellenado se
|
|
|
|
|
hace en cada parte de cada objeto. La siguiente figura debe aclarar la
|
|
|
|
|
cuesti<EFBFBD>n.
|
|
|
|
|
|
|
|
|
|
<? <CENTER> >
|
|
|
|
|
<?
|
|
|
|
|
<IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509" HEIGHT="213"
|
|
|
|
|
VSPACE="15" HSPACE="10" ALT="Imagen de ejemplo sobre el empaquetado con cajas">
|
|
|
|
|
>
|
|
|
|
|
<? </CENTER> >
|
|
|
|
|
|
|
|
|
|
Estudiemos el c<>digo usado para crear las im<69>genes
|
|
|
|
|
anteriores. Con los comentarios no deber<65>a de haber ning<6E>n
|
|
|
|
|
problema para entenderlo.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Programa demostraci<63>n de empaquetamiento
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo packbox packbox.c */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include "gtk/gtk.h"
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Hacemos una hbox llena de etiquetas de bot<6F>n. Los argumentos
|
|
|
|
|
* para las variables que estamos interesados son pasados a esta
|
|
|
|
|
* funci<63>n. No mostramos la caja, pero hacemos todo lo que
|
|
|
|
|
* queremos. */
|
|
|
|
|
GtkWidget *make_box (gint homogeneous, gint spacing,
|
|
|
|
|
gint expand, gint fill, gint padding)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *box;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
char padstr[80];
|
|
|
|
|
|
|
|
|
|
/* creamos una nueva caja con los argumentos homogeneous y
|
|
|
|
|
* spacing */
|
|
|
|
|
box = gtk_hbox_new (homogeneous, spacing);
|
|
|
|
|
|
|
|
|
|
/* crear una serie de botones */
|
|
|
|
|
boton = gtk_button_new_with_label ("gtk_box_pack");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("(box,");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("boton,");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
/* Este bot<6F>n llevar<61> por etiqueta el valor de expand */
|
|
|
|
|
if (expand == TRUE)
|
|
|
|
|
boton = gtk_button_new_with_label ("TRUE,");
|
|
|
|
|
else
|
|
|
|
|
boton = gtk_button_new_with_label ("FALSE,");
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
/* Este es el mismo caso que el de arriba, pero m<>s compacto */
|
|
|
|
|
boton = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
sprintf (padstr, "%d);", padding);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label (padstr);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, expand, fill, padding);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
return box;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *caja1;
|
|
|
|
|
GtkWidget *caja2;
|
|
|
|
|
GtkWidget *separator;
|
|
|
|
|
GtkWidget *etiqueta;
|
|
|
|
|
GtkWidget *quitbox;
|
|
|
|
|
int which;
|
|
|
|
|
|
|
|
|
|
/* <20>No olvidar la siguiente llamada! */
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
if (argc != 2) {
|
|
|
|
|
fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
|
|
|
|
|
/* hacemos limpieza en GTK y devolvemos el valor de 1 */
|
|
|
|
|
gtk_exit (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
which = atoi (argv[1]);
|
|
|
|
|
|
|
|
|
|
/* Creamos la ventana */
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
/* Siempre hay que conectar la se<73>al de destrucci<63>n con la
|
|
|
|
|
* ventana principal. Esto es muy importante para que el
|
|
|
|
|
* comportamiento de la ventana sea intuitivo. */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (delete_event), NULL);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* Creamos una caja vertical donde empaquetaremos las cajas
|
|
|
|
|
* horizontales. As<41> podemos apilar las cajas horizontales
|
|
|
|
|
* llenas con botones una encima de las otras. */
|
|
|
|
|
caja1 = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
|
|
|
|
|
/* Aclaramos c<>al es el ejemplo a mostrar. Se corresponde con
|
|
|
|
|
* las im<69>genes anteriores. */
|
|
|
|
|
switch (which) {
|
|
|
|
|
case 1:
|
|
|
|
|
/* creamos una nueva etiqueta. */
|
|
|
|
|
etiqueta = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
|
|
|
|
|
|
|
|
|
|
/* Alineamos la etiqueta a la izquierda. Est<73> funci<63>n
|
|
|
|
|
* ser<65> discutida en detalle en la secci<63>n de los
|
|
|
|
|
* atributos de los widgets. */
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
|
|
|
|
|
|
|
|
|
|
/* Empaquetamos la etiqueta en la caja vertical (vbox
|
|
|
|
|
* caja1). Siempre hay que recordar que los widgets a<>adidos a
|
|
|
|
|
* una vbox ser<65>n empaquetados uno encimo de otro. */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
/* mostramos la etiqueta. */
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
/* llamada a la funci<63>n que hace las cajas. Los argumentos
|
|
|
|
|
* son homogenous = FALSE, expand = FALSE, fill = FALSE,
|
|
|
|
|
* padding = 0 */
|
|
|
|
|
caja2 = make_box (FALSE, 0, FALSE, FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
/* Llamad a la funci<63>n para hacer cajas -
|
|
|
|
|
* homogeneous = FALSE, spacing = 0, expand = FALSE,
|
|
|
|
|
* fill = FALSE, padding = 0 */
|
|
|
|
|
caja2 = make_box (FALSE, 0, TRUE, FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
/* Los argumentos son: homogeneous, spacing, expand, fill,
|
|
|
|
|
* padding */
|
|
|
|
|
caja2 = make_box (FALSE, 0, TRUE, TRUE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* creamos un separador. M<>s tarde aprenderemos m<>s cosas
|
|
|
|
|
* sobre ellos, pero son bastante sencillos. */
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
|
|
|
|
|
/* empaquetamos el separador el la vbox. Los widgets ser<65>n
|
|
|
|
|
* apilados verticalmente. */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
|
|
|
|
|
gtk_widget_show (separator);
|
|
|
|
|
|
|
|
|
|
/* creamos una nueva etiqueta y la mostramos */
|
|
|
|
|
etiqueta = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
/* Los argumentos son: homogeneous, spacing, expand, fill,
|
|
|
|
|
* padding */
|
|
|
|
|
caja2 = make_box (TRUE, 0, TRUE, FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
/* Los argumentos son: homogeneous, spacing, expand, fill,
|
|
|
|
|
* padding */
|
|
|
|
|
caja2 = make_box (TRUE, 0, TRUE, TRUE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
/* un nuevo separador */
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
/* Los tres <20>ltimos argumentos son: expand, fill, padding. */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
|
|
|
|
|
gtk_widget_show (separator);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
|
|
|
|
/* Nueva etiqueta */
|
|
|
|
|
etiqueta = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
/* Los argumentos son: homogeneous, spacing, expand, fill,
|
|
|
|
|
* padding */
|
|
|
|
|
caja2 = make_box (FALSE, 10, TRUE, FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
/* Los argumentos son: homogeneous, spacing, expand, fill,
|
|
|
|
|
* padding */
|
|
|
|
|
caja2 = make_box (FALSE, 10, TRUE, TRUE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
/* Los argumentos son: expand, fill, padding. */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
|
|
|
|
|
gtk_widget_show (separator);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
/* Los argumentos son: homogeneous, spacing, expand, fill,
|
|
|
|
|
* padding */
|
|
|
|
|
caja2 = make_box (FALSE, 0, TRUE, FALSE, 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
/* Los argumentos son: homogeneous, spacing, expand, fill,
|
|
|
|
|
* padding */
|
|
|
|
|
caja2 = make_box (FALSE, 0, TRUE, TRUE, 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
/* Los argumentos son: expand, fill, padding. */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
|
|
|
|
|
gtk_widget_show (separator);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
|
|
|
|
/* Con esto demostramos como hay que usar gtk_box_pack_end ()
|
|
|
|
|
* para conseguir que los
|
|
|
|
|
widgets esten alineados a la izquierda. */
|
|
|
|
|
caja2 = make_box (FALSE, 0, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
/* la <20>ltima etiqueta*/
|
|
|
|
|
etiqueta = gtk_label_new ("end");
|
|
|
|
|
|
|
|
|
|
/* la empaquetamos usando gtk_box_pack_end(), por lo que se
|
|
|
|
|
* sit<69>a en el lado derecho de la hbox.*/
|
|
|
|
|
gtk_box_pack_end (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
/* mostrar la etiqueta */
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* empaquetamos caja2 en caja1 */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* el separador para la parte de abajo. */
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
|
|
|
|
|
/* As<41> se determina el tama<6D>o del separador a 400 pixels
|
|
|
|
|
* de largo por 5 de alto. La hbox tambi<62>n tendr<64> 400
|
|
|
|
|
* pixels de largo y la etiqueta "end" estar<61> separada de
|
|
|
|
|
* las dem<65>s etiquetas en la hbox. Si no establecemos estos
|
|
|
|
|
* par<61>metros todos los widgets en la hbox ser<65>n
|
|
|
|
|
* empaquetados tan juntos como se pueda.*/
|
|
|
|
|
gtk_widget_set_usize (separator, 400, 5);
|
|
|
|
|
|
|
|
|
|
/* Empaquetamos el separador creado al principio de main() en
|
|
|
|
|
* la vbox (caja1). */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 5);
|
|
|
|
|
gtk_widget_show (separator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Creamos otra hbox... recordar que podemos crear tantas como
|
|
|
|
|
* queramos. */
|
|
|
|
|
quitbox = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
|
|
|
|
|
/* El bot<6F>n de salida. */
|
|
|
|
|
boton = gtk_button_new_with_label ("Quit");
|
|
|
|
|
|
|
|
|
|
/* Establecemos la se<73>al de destrucci<63>n de la ventana.
|
|
|
|
|
* Recuerde que emitir<69> la se<73>al de "destroy" que a su vez
|
|
|
|
|
* ser<65> procesada por el controlador de se<73>ales, tal y como
|
|
|
|
|
* ya hemos visto. */
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit),
|
|
|
|
|
GTK_OBJECT (ventana));
|
|
|
|
|
/* Empaquetamos el bot<6F>n en la caja de salida (quitbox).
|
|
|
|
|
* los tres <20>ltimos argumentos de gtk_box_pack_start
|
|
|
|
|
* son:expand, fill, padding. */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), quitbox, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
/* empaquetamos la vbox (caja1) que ya contiene todos los widgets
|
|
|
|
|
* en la ventana principal. */
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), caja1);
|
|
|
|
|
|
|
|
|
|
/* mostramos todo aquello que faltaba por mostrar */
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
gtk_widget_show (quitbox);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (caja1);
|
|
|
|
|
|
|
|
|
|
/* Si mostramos la ventana lo <20>ltimo todo aparece de golpe. */
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
/* por supuesto tenemos una funci<63>n main. */
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
/* El programa llega aqu<71> cuando se llama a gtk_main_quit(),
|
|
|
|
|
* pero no cuando se llama a gtk_exit(). */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo*/
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Empaquetamiento usando tablas
|
|
|
|
|
<p>
|
|
|
|
|
Existe otra forma de empaquetar: usando tablas. Estas pueden llegar a
|
|
|
|
|
ser extremadamente <20>tiles.
|
|
|
|
|
|
|
|
|
|
Usando tablas creamos una cuadr<64>cula donde podemos poner los
|
|
|
|
|
widgets. Estos pueden ocupar tanto espacio como queramos.
|
|
|
|
|
|
|
|
|
|
La primera funci<63>n que conviene estudiar es gtk_table_new:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_table_new( gint rows,
|
|
|
|
|
gint columns,
|
|
|
|
|
gint homogeneous );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como es l<>gico el primer argumento es el n<>mero de filas y el
|
|
|
|
|
segundo el de columnas.
|
|
|
|
|
|
|
|
|
|
El tercero establece el tama<6D>o de las celdas de la tabla. Si es TRUE
|
|
|
|
|
se fuerza a que el tama<6D>o de las celdas sea igual al de la celda
|
|
|
|
|
mayor. Con FALSE se establece el ancho de toda una columna igual al de
|
|
|
|
|
la celda m<>s ancha de esa columna, y la altura de una fila ser<65>
|
|
|
|
|
la de la celda m<>s alta de esa fila.
|
|
|
|
|
|
|
|
|
|
El n<>mero de filas y columnas var<61>a entre 0 y n, donde n es el
|
|
|
|
|
n<EFBFBD>mero especificado en la llamada a gtk_table_new. As<41> si se
|
|
|
|
|
especifica columnas = 2 y filas = 2 la apariencia ser<65> parecida a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
0 1 2
|
|
|
|
|
0+----------+----------+
|
|
|
|
|
| | |
|
|
|
|
|
1+----------+----------+
|
|
|
|
|
| | |
|
|
|
|
|
2+----------+----------+
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Conviene destacar que el origen de coordenadas se sit<69>a en la esquina superior izquierda. Para
|
|
|
|
|
situar un widget en una ventana se usa la siguiente funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_table_attach( GtkTable *table,
|
|
|
|
|
GtkWidget *hijo,
|
|
|
|
|
gint left_attach,
|
|
|
|
|
gint right_attach,
|
|
|
|
|
gint top_attach,
|
|
|
|
|
gint bottom_attach,
|
|
|
|
|
gint xoptions,
|
|
|
|
|
gint yoptions,
|
|
|
|
|
gint xpadding,
|
|
|
|
|
gint ypadding );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El primer argumento (<tt/table/) es el nombre de la tabla y el segundo
|
|
|
|
|
(<tt/hijo/) el <em/widget/ que quiere poner en la tabla.
|
|
|
|
|
|
|
|
|
|
Los argumentos <tt/left_attach/, <tt/right_attach/ especifican donde
|
|
|
|
|
se pone el widget y cuantas cajas se usan. Por ejemplo, supongamos que
|
|
|
|
|
queremos poner un bot<6F>n que s<>lo ocupe la esquina inferior
|
|
|
|
|
izquierda en nuestra tabla 2x2. Los valores ser<65>n left_attach = 1,
|
|
|
|
|
right_attach = 2, top_attach = 2, top_attach = 1, bottom_attach = 2.
|
|
|
|
|
|
|
|
|
|
Supongamos que queremos ocupar toda la fila de nuestra tabla 2x2,
|
|
|
|
|
usar<EFBFBD>amos left_attach = 0, right_attach = 2, top_attach = 0,
|
|
|
|
|
bottom_attach = 1.
|
|
|
|
|
|
|
|
|
|
Las opciones <tt/xoptions/ e <tt/yoptions/ son usadas para especificar
|
|
|
|
|
como queremos el empaquetamiento y podemos utilizar multiples
|
|
|
|
|
opciones simultaneamente con OR.
|
|
|
|
|
|
|
|
|
|
Las opciones son:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>GTK_FILL - Si el relleno es m<>s grande que el widget, y se
|
|
|
|
|
especifica GTK_FILL, el <em/widget/ se expandir<69> ocupando todo el
|
|
|
|
|
espacio disponible.
|
|
|
|
|
|
|
|
|
|
<item>GTK_SHRINK - En el caso de que hayamos dejado espacio sin usar
|
|
|
|
|
cuando el usuario reajuste el tama<6D>o de la ventana los <em/widgets/
|
|
|
|
|
normalmente ser<65>n empujados al fondo de la ventana y
|
|
|
|
|
desaparecer<EFBFBD>n. Si especifica GTK_SHRINK los widgets se reducir<69>n
|
|
|
|
|
con la tabla.
|
|
|
|
|
|
|
|
|
|
<item>GTK_EXPAND - Mediante esta opci<63>n la tabla se expande usando
|
|
|
|
|
todo el espacio libre de la ventana.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
El relleno es igual que con las cajas. Simplemente se crea una zona
|
|
|
|
|
vac<EFBFBD>a alrededor del widget (el tama<6D>o se especifica en pixels).
|
|
|
|
|
|
|
|
|
|
gtk_table_attach() tiene MUCHAS opciones. Asi que hay un atajo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_table_attach_defaults( GtkTable *table,
|
|
|
|
|
GtkWidget *widget,
|
|
|
|
|
gint left_attach,
|
|
|
|
|
gint right_attach,
|
|
|
|
|
gint top_attach,
|
|
|
|
|
gint bottom_attach );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Las opciones X e Y se ponen por defecto a GTK_FILL | GTK_EXPAND, y el
|
|
|
|
|
relleno X e Y se pone a 0. El resto de los argumentos son identicos a
|
|
|
|
|
la funci<63>n anterior.
|
|
|
|
|
|
|
|
|
|
Existen otras funciones como gtk_table_set_row_spacing() y
|
|
|
|
|
gtk_table_set_col_spacing(), que sirven para especificar el espaciado
|
|
|
|
|
entre las columnas/filas en la columna/fila que queramos.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_table_set_row_spacing( GtkTable *table,
|
|
|
|
|
gint row,
|
|
|
|
|
gint spacing );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
y
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_table_set_col_spacing ( GtkTable *table,
|
|
|
|
|
gint column,
|
|
|
|
|
gint spacing );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Conviene destacar que el espaciado se sit<69>a a la derecha de la
|
|
|
|
|
columna y debajo de la fila.
|
|
|
|
|
|
|
|
|
|
Tambien se puede forzar que el espaciado sea el mismo para las filas
|
|
|
|
|
y/o las columnas:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_table_set_row_spacings( GtkTable *table,
|
|
|
|
|
gint spacing );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
y
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_table_set_col_spacings( GtkTable *table,
|
|
|
|
|
gint spacing );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Usando estas funciones las <20>ltimas fila y columna no estar<61>n
|
|
|
|
|
espaciadas.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Ejemplo de empaquetamiento mediante tablas.
|
|
|
|
|
<p>
|
|
|
|
|
Haremos una ventana con tres botones en una tabla 2x2. Los dos
|
|
|
|
|
primeros botones ocupar<61>n la fila de arriba, mientras que el
|
|
|
|
|
tercero (de salida) ocupar<61> toda la fila de abajo. El resultado es
|
|
|
|
|
el siguiente:
|
|
|
|
|
|
|
|
|
|
<? <CENTER> >
|
|
|
|
|
<?
|
|
|
|
|
<IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10"
|
|
|
|
|
ALT="Imagen de ejemplo sobre el empaquetado mediante tablas" WIDTH="180" HEIGHT="120">
|
|
|
|
|
>
|
|
|
|
|
<? </CENTER> >
|
|
|
|
|
|
|
|
|
|
Este es el c<>digo:
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo table table.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* La respuesta, que adem<65>s se imprime en stdout. */
|
|
|
|
|
void callback (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
g_print ("Hello again - %s was pressed\n", (char *) data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Con esta otra respuesta terminamos el programa. */
|
|
|
|
|
void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *table;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Table");
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (delete_event), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 20);
|
|
|
|
|
|
|
|
|
|
table = gtk_table_new (2, 2, TRUE);
|
|
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), table);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("bot<6F>n 1");
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (callback), (gpointer) "bot<6F>n 1");
|
|
|
|
|
|
|
|
|
|
gtk_table_attach_defaults (GTK_TABLE(table), boton, 0, 1, 0, 1);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("bot<6F>n 2");
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (callback), (gpointer) "bot<6F>n 2");
|
|
|
|
|
gtk_table_attach_defaults (GTK_TABLE(table), boton, 1, 2, 0, 1);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("Quit");
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (delete_event), NULL);
|
|
|
|
|
gtk_table_attach_defaults (GTK_TABLE(table), boton, 0, 2, 1, 2);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (table);
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Estudio general de los <em/widgets/
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
Los pasos generales a la hora de crear un <em/widget/ son:
|
|
|
|
|
|
|
|
|
|
<enum>
|
|
|
|
|
|
|
|
|
|
<item> Usar gtk_*_new - Una de las diferentes formas de crear un
|
|
|
|
|
<em/widget/. (Todas ser<65>n explicadas en esta secci<63>n).
|
|
|
|
|
|
|
|
|
|
<item> Connectar todas las se<73>ales y los eventos a los
|
|
|
|
|
controladores apropiados.
|
|
|
|
|
|
|
|
|
|
<item> Establecer los atributos del <em/widget/.
|
|
|
|
|
|
|
|
|
|
<item> Empaquetar el <em/widget/ en un contenedor usando las llamadas
|
|
|
|
|
apropiadas, como gtk_container_add() o gtk_box_pack_start().
|
|
|
|
|
|
|
|
|
|
<item> Mostrar el <em/widget/ usando gtk_widget_show().
|
|
|
|
|
|
|
|
|
|
</enum>
|
|
|
|
|
|
|
|
|
|
Mediante esta <20>ltima llamada GTK `sabe' que hemos acabado de
|
|
|
|
|
establecer los atributos del <em/widget/, y que por lo tanto puede
|
|
|
|
|
mostrarse. Se puede usar gtk_widget_hide para hacer que desaparezca.
|
|
|
|
|
El orden en el que se muestran los <em/widgets/ no es importante, pero
|
|
|
|
|
se recomienda mostrar al final la ventana para que todo aparezca de
|
|
|
|
|
golpe. El hijo de un <em/widget/ no se muestra hasta que lo hace la
|
|
|
|
|
propia ventana (que en este caso es un <em/widget/ padre) mediante
|
|
|
|
|
gtk_widget_show().
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Conversi<73>n de tipos
|
|
|
|
|
<p>
|
|
|
|
|
GTK usa un sistema de conversi<73>n de tipos mediante macros que
|
|
|
|
|
comprueban si se puede realizar la conversi<73>n y en caso
|
|
|
|
|
afirmativo la hacen. Las m<>s comunes son:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_WIDGET(widget)
|
|
|
|
|
<item> GTK_OBJECT(object)
|
|
|
|
|
<item> GTK_SIGNAL_FUNC(function)
|
|
|
|
|
<item> GTK_CONTAINER(container)
|
|
|
|
|
<item> GTK_WINDOW(ventana)
|
|
|
|
|
<item> GTK_BOX(box)
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Todas son usadas para cambiar de tipo los argumentos de una funci<63>n.
|
|
|
|
|
Aparecer<EFBFBD>n mucho en los ejemplos, para usarlas s<>lo hay que mirar la
|
|
|
|
|
declaraci<EFBFBD>n de la funci<63>n.
|
|
|
|
|
|
|
|
|
|
Tal y como se puede ver en el <20>rbol de clases (situado un poco
|
|
|
|
|
m<EFBFBD>s adelante) todos los <em/widgets/ derivan de la clase base
|
|
|
|
|
GtkObject. Esto significa que siempre se puede usar un <em/widget/
|
|
|
|
|
como argumento de una funci<63>n (que acepte un objeto, claro)
|
|
|
|
|
realizando la conversi<73>n de tipo GTK_OBJECT().
|
|
|
|
|
|
|
|
|
|
Por ejemplo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_connect( GTK_OBJECT(boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(callback_function), callback_data);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Hemos hecho que el bot<6F>n pase a ser un objeto y que se cambie el
|
|
|
|
|
puntero a la funci<63>n a una funci<63>n respuesta.
|
|
|
|
|
|
|
|
|
|
Muchos <em/widgets/ son contenedores, por lo que unos pueden derivar
|
|
|
|
|
de otros (la mayor<6F>a lo hace de GtkContainer). Cualquiera puede ser
|
|
|
|
|
usado junto con la macro GTK_CONTAINER como argumento a funciones en
|
|
|
|
|
forma de puntero.
|
|
|
|
|
|
|
|
|
|
Desgraciadamente estas macros no son descritas en detalle en el
|
|
|
|
|
tutorial, por lo que se recomienda echar un vistazo a los archivos de
|
|
|
|
|
cabecera de GTK. En la pr<70>ctica es posible aprender a manejar un
|
|
|
|
|
<em/widget/ leyendo las declaraciones de las funciones.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1><3E>rbol formado por los <em/widgets/
|
|
|
|
|
<p>
|
|
|
|
|
A continuaci<63>n se detallan todas las ramas del <20>rbol que forman
|
|
|
|
|
los <em/widgets/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkObject
|
|
|
|
|
+GtkWidget
|
|
|
|
|
| +GtkMisc
|
|
|
|
|
| | +GtkLabel
|
|
|
|
|
| | | +GtkAccelLabel
|
|
|
|
|
| | | `GtkTipsQuery
|
|
|
|
|
| | +GtkArrow
|
|
|
|
|
| | +GtkImage
|
|
|
|
|
| | `GtkPixmap
|
|
|
|
|
| +GtkContainer
|
|
|
|
|
| | +GtkBin
|
|
|
|
|
| | | +GtkAlignment
|
|
|
|
|
| | | +GtkFrame
|
|
|
|
|
| | | | `GtkAspectFrame
|
|
|
|
|
| | | +GtkButton
|
|
|
|
|
| | | | +GtkToggleButton
|
|
|
|
|
| | | | | `GtkCheckButton
|
|
|
|
|
| | | | | `GtkRadioButton
|
|
|
|
|
| | | | `GtkOptionMenu
|
|
|
|
|
| | | +GtkItem
|
|
|
|
|
| | | | +GtkMenuItem
|
|
|
|
|
| | | | | +GtkCheckMenuItem
|
|
|
|
|
| | | | | | `GtkRadioMenuItem
|
|
|
|
|
| | | | | `GtkTearoffMenuItem
|
|
|
|
|
| | | | +GtkListItem
|
|
|
|
|
| | | | `GtkTreeItem
|
|
|
|
|
| | | +GtkWindow
|
|
|
|
|
| | | | +GtkColorSelectionDialog
|
|
|
|
|
| | | | +GtkDialog
|
|
|
|
|
| | | | | `GtkInputDialog
|
|
|
|
|
| | | | +GtkDrawWindow
|
|
|
|
|
| | | | +GtkFileSelection
|
|
|
|
|
| | | | +GtkFontSelectionDialog
|
|
|
|
|
| | | | `GtkPlug
|
|
|
|
|
| | | +GtkEventBox
|
|
|
|
|
| | | +GtkHandleBox
|
|
|
|
|
| | | +GtkScrolledWindow
|
|
|
|
|
| | | `GtkViewport
|
|
|
|
|
| | +GtkBox
|
|
|
|
|
| | | +GtkButtonBox
|
|
|
|
|
| | | | +GtkHButtonBox
|
|
|
|
|
| | | | `GtkVButtonBox
|
|
|
|
|
| | | +GtkVBox
|
|
|
|
|
| | | | +GtkColorSelection
|
|
|
|
|
| | | | `GtkGammaCurve
|
|
|
|
|
| | | `GtkHBox
|
|
|
|
|
| | | +GtkCombo
|
|
|
|
|
| | | `GtkStatusbar
|
|
|
|
|
| | +GtkCList
|
|
|
|
|
| | | `GtkCTree
|
|
|
|
|
| | +GtkFixed
|
|
|
|
|
| | +GtkNotebook
|
|
|
|
|
| | | `GtkFontSelection
|
|
|
|
|
| | +GtkPaned
|
|
|
|
|
| | | +GtkHPaned
|
|
|
|
|
| | | `GtkVPaned
|
|
|
|
|
| | +GtkLayout
|
|
|
|
|
| | +GtkList
|
|
|
|
|
| | +GtkMenuShell
|
|
|
|
|
| | | +GtkMenuBar
|
|
|
|
|
| | | `GtkMenu
|
|
|
|
|
| | +GtkPacker
|
|
|
|
|
| | +GtkSocket
|
|
|
|
|
| | +GtkTable
|
|
|
|
|
| | +GtkToolbar
|
|
|
|
|
| | `GtkTree
|
|
|
|
|
| +GtkCalendar
|
|
|
|
|
| +GtkDrawingArea
|
|
|
|
|
| | `GtkCurve
|
|
|
|
|
| +GtkEditable
|
|
|
|
|
| | +GtkEntry
|
|
|
|
|
| | | `GtkSpinButton
|
|
|
|
|
| | `GtkText
|
|
|
|
|
| +GtkRuler
|
|
|
|
|
| | +GtkHRuler
|
|
|
|
|
| | `GtkVRuler
|
|
|
|
|
| +GtkRange
|
|
|
|
|
| | +GtkScale
|
|
|
|
|
| | | +GtkHScale
|
|
|
|
|
| | | `GtkVScale
|
|
|
|
|
| | `GtkScrollbar
|
|
|
|
|
| | +GtkHScrollbar
|
|
|
|
|
| | `GtkVScrollbar
|
|
|
|
|
| +GtkSeparator
|
|
|
|
|
| | +GtkHSeparator
|
|
|
|
|
| | `GtkVSeparator
|
|
|
|
|
| +GtkPreview
|
|
|
|
|
| `GtkProgress
|
|
|
|
|
| `GtkProgressBar
|
|
|
|
|
+GtkData
|
|
|
|
|
| +GtkAdjustment
|
|
|
|
|
| `GtkTooltips
|
|
|
|
|
`GtkItemFactory
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1><em/Widgets/ sin ventanas
|
|
|
|
|
<p>
|
|
|
|
|
Los siguientes <em/widgets/ no tienen ventanas asociadas. Si se
|
|
|
|
|
quieren capturar eventos se tendr<64> que utilizar GtkEventBox. En la
|
|
|
|
|
secci<EFBFBD>n <ref id="sec_The_EventBox_Widget" name="El widget
|
|
|
|
|
EventBox"> se pueden encontrar m<>s detalles sobre su uso.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkAlignment
|
|
|
|
|
GtkArrow
|
|
|
|
|
GtkBin
|
|
|
|
|
GtkBox
|
|
|
|
|
GtkImage
|
|
|
|
|
GtkItem
|
|
|
|
|
GtkLabel
|
|
|
|
|
GtkPixmap
|
|
|
|
|
GtkScrolledWindow
|
|
|
|
|
GtkSeparator
|
|
|
|
|
GtkTable
|
|
|
|
|
GtkAspectFrame
|
|
|
|
|
GtkFrame
|
|
|
|
|
GtkVBox
|
|
|
|
|
GtkHBox
|
|
|
|
|
GtkVSeparator
|
|
|
|
|
GtkHSeparator
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Vamos a continuar la explicaci<63>n describiendo cada uno de los
|
|
|
|
|
<em/widgets/ mediante ejemplos. Tambi<62>n se puede consultar el
|
|
|
|
|
programa testgtk.c (Se encuentra en gtk/testgtk.c).
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>El <em/widget/ Bot<6F>n
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Botones normales <label id="sec_Radio_Buttons">
|
|
|
|
|
<p>
|
|
|
|
|
Ya hemos visto pr<70>cticamente todo lo que hay que saber a cerca de
|
|
|
|
|
este <em/widget/. Existen dos formas diferentes de crear un
|
|
|
|
|
bot<EFBFBD>n. Se puede usar gtk_button_new_with_label() para conseguir un
|
|
|
|
|
bot<EFBFBD>n con etiqueta o simplemente gtk_button_new(). Si se quiere se
|
|
|
|
|
puede a<>adir una etiqueta a este <20>ltimo empaquet<65>ndola,
|
|
|
|
|
primero se crea una nueva caja y luego se empaquetan los objetos que
|
|
|
|
|
se quieran mediante gtk_box_pack_start. Una vez finalizado esto se
|
|
|
|
|
relaciona la caja con el bot<6F>n mediante gtk_container_add.
|
|
|
|
|
|
|
|
|
|
Estudiemos un ejemplo de gtk_button_new para crear un bot<6F>n con una
|
|
|
|
|
imagen y una etiqueta. El c<>digo est<73> dividido en dos para que
|
|
|
|
|
pueda ser reusado.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo buttons buttons.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* Creamos la caja con una imagen y una etiqueta empaquetadas. Se
|
|
|
|
|
* devuelve la caja. */
|
|
|
|
|
GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *caja1;
|
|
|
|
|
GtkWidget *etiqueta;
|
|
|
|
|
GtkWidget *pixmapwid;
|
|
|
|
|
GdkPixmap *pixmap;
|
|
|
|
|
GdkBitmap *mask;
|
|
|
|
|
GtkStyle *style;
|
|
|
|
|
|
|
|
|
|
/* create box for xpm and etiqueta */
|
|
|
|
|
caja1 = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja1), 2);
|
|
|
|
|
|
|
|
|
|
/* obtenemos el estilo del bot<6F>n (probablemente para el color
|
|
|
|
|
* de fondo, pero no estoy seguro) */
|
|
|
|
|
style = gtk_widget_get_style(parent);
|
|
|
|
|
|
|
|
|
|
/* cargamos el pixmap. Hay una secci<63>n que describe el proceso
|
|
|
|
|
* en detalle */
|
|
|
|
|
pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
|
|
|
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
|
|
|
xpm_filename);
|
|
|
|
|
pixmapwid = gtk_pixmap_new (pixmap, mask);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new (label_text);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1),
|
|
|
|
|
pixmapwid, FALSE, FALSE, 3);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), etiqueta, FALSE, FALSE, 3);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(pixmapwid);
|
|
|
|
|
gtk_widget_show(etiqueta);
|
|
|
|
|
|
|
|
|
|
return (caja1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* respuesta */
|
|
|
|
|
void callback (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
g_print ("Hola de nuevo. Se ha pulsado %s\n", (char *) data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *caja1;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Botones con dibujos");
|
|
|
|
|
|
|
|
|
|
/* It's a good idea to do this for all windows. */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_exit), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_exit), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
gtk_widget_realize(ventana);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new ();
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (callback),
|
|
|
|
|
(gpointer) "bot<6F>n divertido");
|
|
|
|
|
|
|
|
|
|
caja1 = xpm_label_box(ventana, "info.xpm", "bot<6F>n divertido");
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(caja1);
|
|
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (boton), caja1);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La funci<63>n xpm_label_box puede ser usada para empaquetar xpm y
|
|
|
|
|
etiquetas en cualquier widget que pueda ser un contenedor.
|
|
|
|
|
|
|
|
|
|
El bot<6F>n puede responder a las siguientes se<73>ales:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> pressed
|
|
|
|
|
<item> released
|
|
|
|
|
<item> clicked
|
|
|
|
|
<item> enter
|
|
|
|
|
<item> leave
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Botones de selecci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
Estos botones son muy similares a los normales. La <20>nica diferencia
|
|
|
|
|
es que s<>lo pueden estar en dos posiciones diferentes alternadas
|
|
|
|
|
mediante pulsaciones del rat<61>n.
|
|
|
|
|
|
|
|
|
|
Los botones de selecci<63>n son la base de otros tipos: los de
|
|
|
|
|
comprobaci<EFBFBD>n y los circulares. Por lo tanto muchas de sus llamadas
|
|
|
|
|
seran heredadas por estos.
|
|
|
|
|
|
|
|
|
|
Creamos un nuevo bot<6F>n de selecci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_toggle_button_new( void );
|
|
|
|
|
|
|
|
|
|
GtkWidget *gtk_toggle_button_new_with_label( gchar *etiqueta );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como se ha podido imaginar estas funciones son iguales a las de un
|
|
|
|
|
bot<EFBFBD>n normal. La primera crea un bot<6F>n, mientras que la segunda
|
|
|
|
|
crea un bot<6F>n con una etiqueta.
|
|
|
|
|
|
|
|
|
|
Para saber cual es el estado de un bot<6F>n de selecci<63>n,
|
|
|
|
|
comprobaci<EFBFBD>n o circular se usa una de las macros del ejemplo
|
|
|
|
|
siguiente. En <20>stas se comprueba el estado del bot<6F>n mediante
|
|
|
|
|
una respuesta. La se<73>al que queremos recibir es
|
|
|
|
|
<EFBFBD>toggled<EFBFBD>. Generalmente para comprobar el estado de una se<73>al se
|
|
|
|
|
establece un controlador de se<73>ales y luego se usa la siguiente
|
|
|
|
|
macro. La funci<63>n de respuesta debe ser de la forma:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void toggle_button_callback (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
if (GTK_TOGGLE_BUTTON (widget)->active)
|
|
|
|
|
{
|
|
|
|
|
/* Si el control llega aqu<71> el bot<6F>n est<73> pulsado */
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* El bot<6F>n no est<73> pulsado (sobresale) */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
|
|
|
|
|
gint state );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La llamada de arriba puede ser usada para establecer el estado de un
|
|
|
|
|
bot<EFBFBD>n de selecci<63>n (o de cualquiera de sus hijos: el circular o
|
|
|
|
|
el de comprobaci<63>n). El primer argumento es el bot<6F>n, el segundo
|
|
|
|
|
TRUE cuando queremos que el bot<6F>n no est<73> pulsado o FALSE para
|
|
|
|
|
cuando lo est<73>. Por defecto se establece FALSE.
|
|
|
|
|
|
|
|
|
|
Hay que destacar que cuando se usa gtk_toggle_button_set_state() y se
|
|
|
|
|
cambia el estado del bot<6F>n este emite la se<73>al <20>clicked<65>.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Cambia el estado del bot<6F>n emitiendo la se<73>al <20>toggled<65>.
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Botones de comprobaci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
Los botones de comprobaci<63>n son un poco diferentes a los anteriores, aunque
|
|
|
|
|
sus propiedades y funciones son bastante similares. En lugar de ser botones
|
|
|
|
|
con texto en su interior son peque<75>os cuadrados con texto a su derecha.
|
|
|
|
|
Normalmente son usados para (des)seleccionar opciones.
|
|
|
|
|
|
|
|
|
|
Las dos funciones que los crean son muy similares a las de los botones
|
|
|
|
|
normales.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_check_button_new( void );
|
|
|
|
|
|
|
|
|
|
GtkWidget *gtk_check_button_new_with_label ( gchar *etiqueta );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La funci<63>n new_with_label crea un bot<6F>n de comprobaci<63>n con
|
|
|
|
|
una etiqueta dentro.
|
|
|
|
|
|
|
|
|
|
El proceso para comprobar el estado de un bot<6F>n de este tipo es
|
|
|
|
|
igual al de los de comprobaci<63>n.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Botones circulares
|
|
|
|
|
<p>
|
|
|
|
|
Estos botones son similares a los de selecci<63>n con la salvedad de
|
|
|
|
|
que est<73>n agrupados, de modo que s<>lo uno puede estar
|
|
|
|
|
seleccionado. Por tanto son usados para permitir al usuario
|
|
|
|
|
seleccionar algo de una lista de opciones mutuamente excluyentes.
|
|
|
|
|
|
|
|
|
|
Las llamadas para crear un bot<6F>n circular son:
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_radio_button_new( GSList *group );
|
|
|
|
|
|
|
|
|
|
GtkWidget *gtk_radio_button_new_with_label( GSList *group,
|
|
|
|
|
gchar *etiqueta );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El nuevo argumento sirve para especificar el grupo al que
|
|
|
|
|
pertenecen. La primera llamada debe pasar NULL como primer
|
|
|
|
|
argumento. A continuaci<63>n de <20>sta se puede crear el grupo
|
|
|
|
|
usando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para a<>adir un nuevo bot<6F>n a un grupo hay que usar
|
|
|
|
|
gtk_radio_button_group con el anterior bot<6F>n como argumento. El
|
|
|
|
|
resultado se le pasa a gtk_radio_button_new o a
|
|
|
|
|
gtk_radio_button_new_with_label. As<41> se consigue enlazar una cadena
|
|
|
|
|
de botones. (El ejemplo siguiente sirve para aclarar el proceso)
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n se puede establecer c<>al es el bot<6F>n pulsado por
|
|
|
|
|
defecto:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
|
|
|
|
|
gint state );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
El siguiente ejemplo crea un grupo de tres botones:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* Principio del ejemplo radiobuttons.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
|
|
void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
|
|
|
|
|
gtk_main_quit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main(int argc,char *argv[])
|
|
|
|
|
{
|
|
|
|
|
static GtkWidget *ventana = NULL;
|
|
|
|
|
GtkWidget *caja1;
|
|
|
|
|
GtkWidget *caja2;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *separator;
|
|
|
|
|
GSList *group;
|
|
|
|
|
|
|
|
|
|
gtk_init(&argc,&argv);
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC(close_application),
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "radio buttons");
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 0);
|
|
|
|
|
|
|
|
|
|
caja1 = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), caja1);
|
|
|
|
|
gtk_widget_show (caja1);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_vbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
boton = gtk_radio_button_new_with_label (NULL, "bot<6F>n1");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
group = gtk_radio_button_group (GTK_RADIO_BUTTON (boton));
|
|
|
|
|
boton = gtk_radio_button_new_with_label(group, "bot<6F>n2");
|
|
|
|
|
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (boton), TRUE);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
group = gtk_radio_button_group (GTK_RADIO_BUTTON (boton));
|
|
|
|
|
boton = gtk_radio_button_new_with_label(group, "bot<6F>n3");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (separator);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_vbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("close");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(close_application),
|
|
|
|
|
GTK_OBJECT (ventana));
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
|
|
|
|
|
GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
|
|
|
|
|
gtk_widget_grab_default (boton);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main();
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- TODO: checout out gtk_radio_button_new_from_widget function - TRG -->
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Ajustes (<em/Adjustment/) <label id="sec_Adjustment">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
Existen diferentes <em/widgets/ en GTK+ que pueden ser ajustados
|
|
|
|
|
visualmente por el usuario mediante el rat<61>n o el teclado. Un
|
|
|
|
|
ejemplo son los <em/widgets/ de selecci<63>n descritos en la
|
|
|
|
|
secci<EFBFBD>n <ref id="sec_Range_Widgets" name="Widgets de selecci<63>n
|
|
|
|
|
de rango">. Tambi<62>n hay otros widgets que pueden ser ajustados
|
|
|
|
|
parcialmente, por ejemplo el <em/widget/ de texto o el <em/viewport/.
|
|
|
|
|
|
|
|
|
|
Como es l<>gico el programa tiene que poder reaccionar a los
|
|
|
|
|
cambios que el usuario realiza en los <em/widgets/ de selecci<63>n de
|
|
|
|
|
rango. Una forma de hacer que el programa reaccione ser<65>a tener
|
|
|
|
|
cada <em/widget/ emitiendo su propio tipo de se<73>al cuando cambie el
|
|
|
|
|
ajuste, y bien pasar el nuevo valor al manejador de se<73>al o bien
|
|
|
|
|
obligarle a que mire dentro de la estructura de datos del <em/widget/
|
|
|
|
|
para conocer este valor. Pero tambi<62>n puede ser que quiera conectar
|
|
|
|
|
los ajustes de varios <em/widgets/, para que as<61> cuando se ajuste
|
|
|
|
|
uno, los dem<65>s se ajusten autom<6F>ticamente. El ejemplo m<>s
|
|
|
|
|
obvio es conectar una barra de desplazamiento a una regi<67>n con
|
|
|
|
|
texto. Si cada <em/widget/ posee su propia forma de establecer u
|
|
|
|
|
obtener sus valores de ajuste el programador puede que tenga que
|
|
|
|
|
escribir sus propios controladores de se<73>ales para traducir el
|
|
|
|
|
resultado de la se<73>al producida por un <em/widget/ como el
|
|
|
|
|
argumento de una funci<63>n usada para determinar valores en otro
|
|
|
|
|
<em/widget/.
|
|
|
|
|
|
|
|
|
|
Para resolver este problema GTK+ usa objetos del tipo GtkAdjustment.
|
|
|
|
|
Con ellos se consigue almacenar y traspasar informaci<63>n de una forma
|
|
|
|
|
abstracta y flexible. El uso m<>s obvio es el de almacenes de
|
|
|
|
|
p<EFBFBD>rametros para <em/widgets/ de escala (barras deslizantes y
|
|
|
|
|
escalas). Como los GtkAdjustment derivan de GtkObject poseen
|
|
|
|
|
cualidades intr<74>nsecas que les permiten ser algo m<>s que simples
|
|
|
|
|
estructuras de datos. Lo m<>s importante es que pueden emitir
|
|
|
|
|
se<EFBFBD>ales que a su vez pueden ser usadas tanto para reaccionar frente
|
|
|
|
|
al cambio de datos introducidos por el usuario como para transferir
|
|
|
|
|
los nuevos valores de forma transparente entre <em/widgets/ ajustables.
|
|
|
|
|
|
|
|
|
|
<sect1>Creando un ajuste
|
|
|
|
|
<p>
|
|
|
|
|
Los ajustes se pueden crear usando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkObject *gtk_adjustment_new( gfloat value,
|
|
|
|
|
gfloat lower,
|
|
|
|
|
gfloat upper,
|
|
|
|
|
gfloat step_increment,
|
|
|
|
|
gfloat page_increment,
|
|
|
|
|
gfloat page_size );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/value/ es el valor inicial que le queremos dar
|
|
|
|
|
al ajuste. Normalmente se corresponde con las posiciones situadas
|
|
|
|
|
m<EFBFBD>s arriba y a la izquierda de un <em/widget/ ajustable. El argumento
|
|
|
|
|
<tt/lower/ especifica los valores m<>s peque<75>os que el ajuste
|
|
|
|
|
puede contener. A su vez con <tt/step_increment/ se especifica el
|
|
|
|
|
valor m<>s peque<75>o en el que se puede variar la magnitud en
|
|
|
|
|
cuesti<EFBFBD>n (valor de paso asociado), mientras que <tt/page_increment/
|
|
|
|
|
es el mayor. Con <tt/page_size/ se determina el valor visible de un
|
|
|
|
|
<em/widget/.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Forma sencilla de usar los ajustes
|
|
|
|
|
<p>
|
|
|
|
|
Los <em/widgets/ ajust<73>bles se pueden dividir en dos categorias
|
|
|
|
|
diferentes, aquellos que necesitan saber las unidades de la cantidad
|
|
|
|
|
almacenada y los que no. Este <20>ltimo grupo incluye los <em/widgets/
|
|
|
|
|
de tama<6D>o (barras deslizantes, escalas, barras de estado, o botones
|
|
|
|
|
giratorios). Normalmente estos <em/widgets/ son ajustados
|
|
|
|
|
<EFBFBD>directamente<EFBFBD> por el usuario. Los argumentos <tt/lower/ y
|
|
|
|
|
<tt/upper/ ser<65>n los limites dentro de los cuales el usuario puede
|
|
|
|
|
manipular los ajustes. Por defecto s<>lo se modificar<61> el
|
|
|
|
|
<tt/value/ (valor) de un ajuste.
|
|
|
|
|
|
|
|
|
|
El otro grupo incluye los <em/widgets/ de texto, la lista compuesta o
|
|
|
|
|
la ventana con barra deslizante. Estos <em/widgets/ usan valores en
|
|
|
|
|
pixels para sus ajustes, y normalmente son ajustados
|
|
|
|
|
<EFBFBD>indirectamente<EFBFBD> mediante barras deslizantes. Aunque todos los
|
|
|
|
|
<em/widgets/ pueden crear sus propios ajustes o usar otros creados por
|
|
|
|
|
el programador con el segundo grupo suele ser conveniente dejarles que
|
|
|
|
|
creen sus propios ajustes. Normalmente no tendr<64>n en cuenta ninguno
|
|
|
|
|
de los valores de un ajuste proporcionado por el programador, excepto
|
|
|
|
|
<tt/value/, pero los resultados son, en general, indefinidos
|
|
|
|
|
(entiendase que tendr<64> que leer el c<>digo fuente para saber que
|
|
|
|
|
pasa con cada widget).
|
|
|
|
|
|
|
|
|
|
Probablemente ya se habr<62> dado cuenta de que como los <em/widgets/
|
|
|
|
|
de texto (y todos los <em/widgets/ del segundo grupo), insisten en
|
|
|
|
|
establecer todos los valores excepto <tt/value/, mientras que las
|
|
|
|
|
barras deslizantes s<>lo modifican <tt/value/, si se comparte un
|
|
|
|
|
objeto de ajuste entre una barra deslizante y un <em/widget/ de texto
|
|
|
|
|
al manipular la barra se modificar<61> el <em/widget/ de texto. Ahora
|
|
|
|
|
queda completamente demostrada la utilidad de los ajustes. Veamos un
|
|
|
|
|
ejemplo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* creamos un ajuste */
|
|
|
|
|
text = gtk_text_new (NULL, NULL);
|
|
|
|
|
/* lo usamos con la barra deslizante */
|
|
|
|
|
vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Descripci<63>n detallada de los ajustes
|
|
|
|
|
<p>
|
|
|
|
|
Puede que se est<73> preguntando c<>mo es posible crear sus propios
|
|
|
|
|
controladores para responder a las modificaciones producidas por
|
|
|
|
|
el usuario y c<>mo obtener el valor del ajuste hecho por este.
|
|
|
|
|
Para aclarar esto y otras cosas vamos a estudiar la estructura
|
|
|
|
|
del ajuste
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GtkAdjustment
|
|
|
|
|
{
|
|
|
|
|
GtkData data;
|
|
|
|
|
|
|
|
|
|
gfloat lower;
|
|
|
|
|
gfloat upper;
|
|
|
|
|
gfloat value;
|
|
|
|
|
gfloat step_increment;
|
|
|
|
|
gfloat page_increment;
|
|
|
|
|
gfloat page_size;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Lo primero que hay que aclarar es que no hay ninguna macro o funci<63>n
|
|
|
|
|
de acceso que permita obtener el <tt/value/ de un GtkAdjustment, por
|
|
|
|
|
lo que tendr<64> que hacerlo usted mismo. Tampoco se preocupe mucho
|
|
|
|
|
porque la macro <tt>GTK_ADJUSTMENT (Object)</tt> comprueba los tipos
|
|
|
|
|
durante el proceso de ejecuci<63>n (como hacen todas las macros de GTK+
|
|
|
|
|
que sirven para comprobar los tipos).
|
|
|
|
|
|
|
|
|
|
Cuando se establece el <tt/value/ de un ajuste normalmente se quiere
|
|
|
|
|
que cualquier <em/widget/ se entere del cambio producido. Para ello
|
|
|
|
|
GTK+ posee una funci<63>n especial:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_adjustment_set_value( GtkAdjustment *adjustment,
|
|
|
|
|
gfloat value );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Tal y como se mencion<6F> antes GtkAdjustment es una subclase de GtkObject
|
|
|
|
|
y por tanto puede emitir se<73>ales. As<41> se consigue que se actualicen
|
|
|
|
|
los valores de los ajustes cuando se comparten entre varios <em/widgets/.
|
|
|
|
|
Por tanto todos los <em/widgets/ ajustables deben conectar controladores
|
|
|
|
|
de se<73>ales a sus se<73>ales del tipo <tt/value_changed/. Esta es la
|
|
|
|
|
definici<EFBFBD>n de la se<73>al como viene en <tt/struct _GtkAdjustmentClass/
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void (* value_changed) (GtkAdjustment *adjustment);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Todos los <em/widgets/ que usan GtkAdjustment deben emitir esta
|
|
|
|
|
se<EFBFBD>al cuando cambie el valor de alg<6C>n ajuste. Esto sucede cuando
|
|
|
|
|
el usuario cambia algo o el programa modifica los ajustes
|
|
|
|
|
mediante. Por ejemplo si queremos que rote una figura cuando
|
|
|
|
|
modificamos un <em/widget/ de escala habr<62>a que usar una respuesta
|
|
|
|
|
como esta:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
|
|
|
|
|
{
|
|
|
|
|
set_picture_rotation (picture, adj->value);
|
|
|
|
|
...
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
y conectarla con el ajuste del <em/widget/ de escala mediante:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
|
|
|
|
|
GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
<EFBFBD>Qu<EFBFBD> pasa cuando un <em/widget/ reconfigura los valores
|
|
|
|
|
<tt/upper/ o <tt/lower/ (por ejemplo cuando se a<>ade m<>s texto)?
|
|
|
|
|
Simplemente que se emite la se<73>al <tt/changed/, que debe ser
|
|
|
|
|
parecida a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void (* changed) (GtkAdjustment *adjustment);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los <em/widgets/ de tama<6D>o normalmente conectan un controlador a
|
|
|
|
|
esta se<73>al, que cambia el aspecto de <20>ste para reflejar el
|
|
|
|
|
cambio. Por ejemplo el tama<6D>o de la gu<67>a en una barra deslizante
|
|
|
|
|
que se alarga o encoge seg<65>n la inversa de la diferencia de los
|
|
|
|
|
valores <tt/lower/ y <tt/upper/.
|
|
|
|
|
|
|
|
|
|
Probablemente nunca tenga que conectar un controlador a esta se<73>al
|
|
|
|
|
a no ser que est<73> escribiendo un nuevo tipo de <em/widget/. Pero si
|
|
|
|
|
cambia directamente alguno de los valores de GtkAdjustment debe hacer
|
|
|
|
|
que se emita la siguiente se<73>al para reconfigurar todos aquellos
|
|
|
|
|
<em/widgets/ que usen ese ajuste:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
|
</sect>
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Los <em/widgets/ de selecci<63>n de rango <label id="sec_Range_Widgets">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
Este tipo de <em/widgets/ incluye a las barras de desplazamiento
|
|
|
|
|
(<em>scroollbar</em>) y la menos conocida escala
|
|
|
|
|
(<em/scale</em>). Ambos pueden ser usados para muchas cosas, pero como
|
|
|
|
|
sus funciones y su implementaci<63>n son muy parecidas los describimos
|
|
|
|
|
al mismo tiempo. Principalmente se utilizan para permitirle al usuario
|
|
|
|
|
escoger un valor dentro de un rango ya prefijado.
|
|
|
|
|
|
|
|
|
|
Todos los <em/widgets/ de selecci<63>n comparten elementos
|
|
|
|
|
gr<EFBFBD>ficos, cada uno de los cuales tiene su propia ventana X window y
|
|
|
|
|
recibe eventos. Todos contienen una gu<67>a y un rect<63>ngulo para
|
|
|
|
|
determinar la posici<63>n dentro de la gu<67>a (en una procesador de
|
|
|
|
|
textos con entorno gr<67>fico se encuentra situado a la derecha del
|
|
|
|
|
texto y sirve para situarnos en las diferentes partes del texto). Con
|
|
|
|
|
el rat<61>n podemos subir o bajar el rect<63>ngulo, mientras que si
|
|
|
|
|
hacemos `click' dentro de la gu<67>a, pero no sobre el rect<63>ngulo,
|
|
|
|
|
este se mueve hacia donde hemos hecho el click. Dependiendo del
|
|
|
|
|
bot<EFBFBD>n pulsado el rect<63>ngulo se mover<65> hasta la posici<63>n
|
|
|
|
|
del click o una cantidad prefijada de ante mano.
|
|
|
|
|
|
|
|
|
|
Tal y como se mencion<6F> en <ref id="sec_Adjustment" name="Ajustes">
|
|
|
|
|
todos los <em/widgets/ usados para seleccionar un rango estan
|
|
|
|
|
asociados con un objeto de ajuste, a partir del cual calculan la
|
|
|
|
|
longitud de la barra y su posici<63>n. Cuando el usuario manipula la
|
|
|
|
|
barra de desplazamiento el widget cambiar<61> el valor del ajuste.
|
|
|
|
|
|
|
|
|
|
<sect1>El <em/widget/ barra de desplazamiento
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ barra de desplazamiento solamente debe utilizarse para
|
|
|
|
|
hacer <em/scroll/ sobre otro <em/widget/, como una lista, una caja de
|
|
|
|
|
texto, o un puerto de visi<73>n (y en muchos es m<>s f<>cil utilizar
|
|
|
|
|
el <em/widget/ scrolled window). Para el resto de los casos, deber<65>a
|
|
|
|
|
utilizar los <em/widgets/ de escala, ya son m<>s sencillos de usar y
|
|
|
|
|
m<EFBFBD>s potentes.
|
|
|
|
|
|
|
|
|
|
Hay dos tipos separados de barras de desplazamiento, seg<65>n sea
|
|
|
|
|
horizontal o vertical. Realmente no hay mucho que a<>adir. Puede
|
|
|
|
|
crear estos <em/widgets/ utilizar las funciones siguientes, definidas
|
|
|
|
|
en <tt><gtk/gtkhscrollbar.h></tt> y
|
|
|
|
|
<tt><gtk/gtkvscrollbar.h></tt>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_hscrollbar_new( GtkAdjustment *adjustment );
|
|
|
|
|
|
|
|
|
|
GtkWidget* gtk_vscrollbar_new( GtkAdjustment *adjustment );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
y esto es todo lo que hay (si no me cree, <20>mire los ficheros de
|
|
|
|
|
cabecera!). El argumento <tt/adjustment/ puede ser un puntero a un
|
|
|
|
|
ajuste ya existente, o puede ser NULL, en cuyo caso se crear<61>
|
|
|
|
|
uno. Es <20>til especificar NULL si quiere pasar el ajuste reci<63>n
|
|
|
|
|
creado a la funci<63>n constructora de alg<6C>n otro <em/widget/ (como
|
|
|
|
|
por ejemplo el <em/widget/ texto) que se ocupar<61> de configurarlo
|
|
|
|
|
correctamente por usted.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1><em/Widgets/ de escala
|
|
|
|
|
<p>
|
|
|
|
|
Los <em/widgets/ de escala se usan para determinar el valor de una
|
|
|
|
|
cantidad que se puede interpretar visualmente. El usuario
|
|
|
|
|
probablemente fijar<61> el valor a ojo. Por ejemplo el <em/widget/
|
|
|
|
|
GtkColorSelection contiene <em/widgets/ de escala que controlan las
|
|
|
|
|
componentes del color a seleccionar. Normalmente el valor preciso es
|
|
|
|
|
menos importante que el efecto visual, por lo que el color se
|
|
|
|
|
selecciona con el rat<61>n y no mediante un n<>mero concreto.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2>Creaci<63>n de un <em/widget/ de escala
|
|
|
|
|
<p>
|
|
|
|
|
Existen dos tipos de <em/widgets/ de escala: GtkHScale (que es
|
|
|
|
|
horizontal) y GtkVscale (vertical). Como funcionan de la misma manera
|
|
|
|
|
los vamos a describir a la vez. Las funciones definidas en
|
|
|
|
|
<tt><gtk/gtkvscale.h></tt> y <tt><gtk/gtkhscale.h></tt>,
|
|
|
|
|
crean <em/widgets/ de escala verticales y horizontales
|
|
|
|
|
respectivamente.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_vscale_new( GtkAdjustment *adjustment );
|
|
|
|
|
|
|
|
|
|
GtkWidget* gtk_hscale_new( GtkAdjustment *adjustment );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El <tt/ajuste/ (adjustment) puede ser tanto un ajuste creado
|
|
|
|
|
mediante <tt/gtk_adjustment_new()/ como <tt/NULL/. En este
|
|
|
|
|
<EFBFBD>ltimo caso se crea un GtkAdjustment an<61>nimo con todos sus
|
|
|
|
|
valores iguales a <tt/0.0/. Si no ha quedado claro el uso de esta
|
|
|
|
|
funci<EFBFBD>n consulte la secci<63>n <ref id="sec_Adjustment"
|
|
|
|
|
name="Ajustes"> para una discusi<73>n m<>s detallada.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Funciones y se<73>ales
|
|
|
|
|
<p>
|
|
|
|
|
Los <em/widgets/ de escala pueden indicar su valor actual como un
|
|
|
|
|
n<EFBFBD>mero. Su comportamiento por defecto es mostrar este valor, pero
|
|
|
|
|
se puede modificar usando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_scale_set_draw_value( GtkScale *scale,
|
|
|
|
|
gint draw_value );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los valores posibles de <tt/draw_value son/ son <tt/TRUE/ o <tt/FALSE/.
|
|
|
|
|
Con el primero se muestra el valor y con el segundo no.
|
|
|
|
|
|
|
|
|
|
El valor mostrado por un <em/widget/ de escala por defecto se redondea
|
|
|
|
|
a un valor decimal (igual que con <tt/value/ en un GtkAdjustment). Se
|
|
|
|
|
puede cambiar con:
|
|
|
|
|
|
|
|
|
|
<tscreen>
|
|
|
|
|
<verb>
|
|
|
|
|
void gtk_scale_set_digits( GtkScale *scale,
|
|
|
|
|
gint digits );
|
|
|
|
|
</verb>
|
|
|
|
|
</tscreen>
|
|
|
|
|
|
|
|
|
|
donde <tt/digits/ es el n<>mero de posiciones decimales que se
|
|
|
|
|
quiera. En la pr<70>ctica s<>lo se mostrar<61>n 13 como m<>ximo.
|
|
|
|
|
|
|
|
|
|
Por <20>ltimo, el valor se puede dibujar en diferentes posiciones con
|
|
|
|
|
respecto a la posici<63>n del rectangulo que hay dentro de la gu<67>a:
|
|
|
|
|
|
|
|
|
|
<tscreen>
|
|
|
|
|
<verb>
|
|
|
|
|
void gtk_scale_set_value_pos( GtkScale *scale,
|
|
|
|
|
GtkPositionType pos );
|
|
|
|
|
</verb>
|
|
|
|
|
</tscreen>
|
|
|
|
|
|
|
|
|
|
Si ha leido la secci<63>n acerca del <em/widget/ libro de notas
|
|
|
|
|
entonces ya conoce cuales son los valores posibles de <tt/pos/. Estan
|
|
|
|
|
definidos en <tt><gtk/gtkscale.h></tt> como <tt/enum GtkPositionType/
|
|
|
|
|
y son auto explicatorios. Si se escoge un lateral de la gu<67>a,
|
|
|
|
|
entonces seguir<69> al rect<63>ngulo a lo largo de la gu<67>a.
|
|
|
|
|
|
|
|
|
|
Todas las funcioenes precedentes se encuentran definidas en:
|
|
|
|
|
<tt><gtk/gtkscale.h></tt>.
|
|
|
|
|
</sect2>
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Funciones comunes <label id="sec_funciones_range">
|
|
|
|
|
<p>
|
|
|
|
|
La descripci<63>n interna de la clase GtkRange es bastante complicada,
|
|
|
|
|
pero al igual que con el resto de las <20>clases base<73> s<>lo es
|
|
|
|
|
interesante si se quiere <20>hackear<61>. Casi todas las se<73>ales y
|
|
|
|
|
funciones s<>lo son <20>tiles para desarrollar derivados. Para un
|
|
|
|
|
usuario normal las funciones interesantes son aquellas definidas en:
|
|
|
|
|
<tt><gtk/gtkrange.h></tt> y funcionan igual en todos los
|
|
|
|
|
<em/widgets/ de rango.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Estableciendo cada c<>anto se actualizan
|
|
|
|
|
<p>
|
|
|
|
|
La pol<6F>tica de actualizaci<63>n de un <em/widget/ define en que
|
|
|
|
|
puntos de la interacci<63>n con el usuario debe cambiar el valor
|
|
|
|
|
<tt/value/ en su GtkAdjustment y emitir la se<73>al
|
|
|
|
|
<EFBFBD>value_changed<EFBFBD>. Las actualizaciones definidas en
|
|
|
|
|
<tt><gtk/gtkenums.h></tt> como <tt>enum GtkUpdateType</tt>, son:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>GTK_UPDATE_POLICY_CONTINUOUS - Este es el valor por defecto.La
|
|
|
|
|
se<EFBFBD>al <20>value_changed<65> se emite continuamente, por ejemplo cuando
|
|
|
|
|
la barra deslizante se mueve incluso aunque sea un poquito.
|
|
|
|
|
</item>
|
|
|
|
|
<item>GTK_UPDATE_POLICY_DISCONTINUOUS - La se<73>al <20>value_changed<65>
|
|
|
|
|
s<EFBFBD>lo se emite cuando se ha parado de mover la barra y el usuario ha
|
|
|
|
|
soltado el bot<6F>n del rat<61>n.
|
|
|
|
|
</item>
|
|
|
|
|
<item>GTK_UPDATE_POLICY_DELAYED - La se<73>al s<>lo se emite cuando
|
|
|
|
|
el usuario suelta el bot<6F>n del rat<61>n o si la barra no se mueve
|
|
|
|
|
durante un periodo largo de tiempo.
|
|
|
|
|
</item>
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Para establecer la pol<6F>tica de actualizaci<63>n se usa la
|
|
|
|
|
conversi<EFBFBD>n definida en la macro
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_range_set_update_policy( GtkRange *range,
|
|
|
|
|
GtkUpdateType policy) ;
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2>Obteniendo y estableciendo Ajustes
|
|
|
|
|
<p>
|
|
|
|
|
Para obtener o establecer el ajuste de un <em/widget/ de rango se usa:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
|
|
|
|
|
|
|
|
|
|
void gtk_range_set_adjustment( GtkRange *range,
|
|
|
|
|
GtkAdjustment *adjustment );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La funci<63>n <tt/gtk_range_get_adjustment()/ devuelve un puntero al
|
|
|
|
|
ajuste al que <tt/range/ est<73> conectado.
|
|
|
|
|
|
|
|
|
|
La funci<63>n <tt/gtk_range_set_adjustment()/ no hace nada si se le
|
|
|
|
|
pasa como argumento el valor <tt/range/ del ajuste que esta siendo
|
|
|
|
|
usado (aunque se haya modificado alg<6C>n valor). En el caso de que
|
|
|
|
|
sea un ajuste nuevo (GtkAdjustment) dejar<61> de usar el antiguo
|
|
|
|
|
(probablemente lo destruir<69>) y conectar<61> las se<73>ales
|
|
|
|
|
apropiadas al nuevo. A continuaci<63>n llamar<61> a la funci<63>n
|
|
|
|
|
<tt/gtk_range_adjustment_changed()/ que en teor<6F>a recalcular<61> el
|
|
|
|
|
tama<EFBFBD>o y/o la posici<63>n de la barra, redibuj<75>ndola en caso de
|
|
|
|
|
que sea necesario. Tal y como se mencion<6F> en la secci<63>n de los
|
|
|
|
|
ajustes si se quiere reusar el mismo GtkAdjustment cuando se modifican
|
|
|
|
|
sus valores se debe emitir la se<73>al <20>changed<65>. Por ejemplo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
</sect2>
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Enlaces con el teclado y el rat<61>n
|
|
|
|
|
<p>
|
|
|
|
|
Todos los <em/widgets/ de rango reaccionan m<>s o menos de la misma
|
|
|
|
|
manera a las pulsaciones del rat<61>n. Al pulsar el bot<6F>n 1 sobre
|
|
|
|
|
el rect<63>ngulo de la barra el <tt/value/ del ajuste aumentar<61> o
|
|
|
|
|
disminuir<EFBFBD> seg<65>n <tt/page_increment/. Con el bot<6F>n 2 la barra
|
|
|
|
|
se desplazar<61> al punto en el que el bot<6F>n fue pulsado. Con cada
|
|
|
|
|
pulsaci<EFBFBD>n de cualquier bot<6F>n sobre las flechas el valor del
|
|
|
|
|
ajuste se modifica una cantidad igual a <tt/step_increment/.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Acostumbrarse a que tanto las barras deslizantes como los <em/widgets/ de
|
|
|
|
|
escala puedan tomar la atenci<63>n del teclado puede ser un proceso largo.
|
|
|
|
|
Si que se cree que los usuarios no lo van a entender se puede anular
|
|
|
|
|
mediante la funci<63>n GTK_WIDGET_UNSET_FLAGS y con GTK_CAN_FOCUS como
|
|
|
|
|
argumento:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los enlaces entre teclas (que s<>lo estan activos cuando el
|
|
|
|
|
<em/widget/ tiene la atenci<63>n (focus)) se comportan de manera
|
|
|
|
|
diferente para los <em/widgets/ de rango horizontales que para los
|
|
|
|
|
verticales. Tambi<62>n son diferentes para los <em/widgets/ de escala
|
|
|
|
|
y para las barras deslizantes. (Simplemente para evitar confusiones
|
|
|
|
|
entre las teclas de las barras deslizantes horizontales y verticales,
|
|
|
|
|
ya que ambas act<63>an sobre la misma <20>rea)
|
|
|
|
|
|
|
|
|
|
<sect2><em/Widgets/ de rango vertical
|
|
|
|
|
<p>
|
|
|
|
|
Todos los <em/widgets/ de rango pueden ser manipulados con las teclas
|
|
|
|
|
arriba, abajo, <tt/Re P<>g/, <tt/ Av P<>g/. Las flechas mueven las
|
|
|
|
|
barras la cantidad fijada mediante <tt/step_increment/, mientras que
|
|
|
|
|
<tt/Re P<>g/ y <tt/Av Pag/ lo hacen seg<65>n <tt/page_increment/.
|
|
|
|
|
|
|
|
|
|
El usuario tambi<62>n puede mover la barra de un extremo al otro de la
|
|
|
|
|
gu<EFBFBD>a mediante el teclado. Con el <em/widget/ GtkVScale podemos ir a
|
|
|
|
|
los extremos utilizando las teclas <tt/Inicio/ y <tt/Final/ mientras
|
|
|
|
|
que con el <em/widget/ GtkVScrollbar habr<62> que utilizar
|
|
|
|
|
<tt/Control-Re P<>g/ y <tt/Control-Av P<>g/.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2><em/Widgets/ de rango horizontal
|
|
|
|
|
<p>
|
|
|
|
|
Las teclas izquierda y derecha funcionan tal y como espera que
|
|
|
|
|
funcionen en estos <em/widgets/: mueven la barra una cantidad dada por
|
|
|
|
|
<tt/step_increment/. A su vez <tt/Inicio/ y <tt/Final/ sirven para
|
|
|
|
|
pasar de un extremo al otro de la gu<67>a. Para el <em/widget/
|
|
|
|
|
GtkHScale el mover la barra una cantidad dada por <tt/page_increment/
|
|
|
|
|
se consigue mediante <tt>Control-Izquierda</tt> y
|
|
|
|
|
<tt>Control-derecha</tt>, mientras que para el <em/widget/
|
|
|
|
|
GtkHScrollbar se consigue con <tt/Control-Inicio/ y
|
|
|
|
|
<tt/Control-Final/.
|
|
|
|
|
</sect2>
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Ejemplo <label id="sec_Ejemplo_Rango">
|
|
|
|
|
<p>
|
|
|
|
|
Este ejemplo es una versi<73>n modificada del test <20>range controls<6C>
|
|
|
|
|
que a su vez forma parte de <tt/testgtk.c/. Simplemente dibuja una
|
|
|
|
|
ventana con tres <em/widgets/ de rango conectados al mismo ajuste, y
|
|
|
|
|
un conjunto de controles para ajustar algunos de los par<61>metros
|
|
|
|
|
ya mencionados. As<41> se consigue ver como funcionan estos
|
|
|
|
|
<em/widgets/ al ser manipulados por el usuario.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo widgets de selecci<63>n de rango rangewidgets.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
GtkWidget *hscale, *vscale;
|
|
|
|
|
|
|
|
|
|
void cb_pos_menu_select( GtkWidget *item,
|
|
|
|
|
GtkPositionType pos )
|
|
|
|
|
{
|
|
|
|
|
/* Establece el valor position en los widgets de escala */
|
|
|
|
|
gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
|
|
|
|
|
gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cb_update_menu_select( GtkWidget *item,
|
|
|
|
|
GtkUpdateType policy )
|
|
|
|
|
{
|
|
|
|
|
/* Establece la pol<6F>tica de actualizaci<63>n para los widgets
|
|
|
|
|
* de escala */
|
|
|
|
|
gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
|
|
|
|
|
gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cb_digits_scale( GtkAdjustment *adj )
|
|
|
|
|
{
|
|
|
|
|
/* Establece el n<>mero de cifras decimales a las que se
|
|
|
|
|
* redondear<61> adj->value */
|
|
|
|
|
gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
|
|
|
|
|
gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cb_page_size( GtkAdjustment *get,
|
|
|
|
|
GtkAdjustment *set )
|
|
|
|
|
{
|
|
|
|
|
/* Establece el tama<6D>o de la p<>gina y el incremento del
|
|
|
|
|
* ajuste al valor especificado en la escala "Page Size" */
|
|
|
|
|
set->page_size = get->value;
|
|
|
|
|
set->page_increment = get->value;
|
|
|
|
|
/* Ahora emite la se<73>al "changed" para reconfigurar todos los
|
|
|
|
|
* widgets que est<73>n enlazados a este ajuste */
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (set), "changed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void cb_draw_value( GtkToggleButton *boton )
|
|
|
|
|
{
|
|
|
|
|
/* Activa o desactiva el valor display en los widgets de escala
|
|
|
|
|
* dependiendo del estado del bot<6F>n de comprobaci<63>n */
|
|
|
|
|
gtk_scale_set_draw_value (GTK_SCALE (hscale), boton->active);
|
|
|
|
|
gtk_scale_set_draw_value (GTK_SCALE (vscale), boton->active);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Funciones varias */
|
|
|
|
|
|
|
|
|
|
GtkWidget *make_menu_item( gchar *name,
|
|
|
|
|
GtkSignalFunc callback,
|
|
|
|
|
gpointer data )
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *item;
|
|
|
|
|
|
|
|
|
|
item = gtk_menu_item_new_with_label (name);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (item), "activate",
|
|
|
|
|
callback, data);
|
|
|
|
|
gtk_widget_show (item);
|
|
|
|
|
|
|
|
|
|
return(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void scale_set_default_values( GtkScale *scale )
|
|
|
|
|
{
|
|
|
|
|
gtk_range_set_update_policy (GTK_RANGE (scale),
|
|
|
|
|
GTK_UPDATE_CONTINUOUS);
|
|
|
|
|
gtk_scale_set_digits (scale, 1);
|
|
|
|
|
gtk_scale_set_value_pos (scale, GTK_POS_TOP);
|
|
|
|
|
gtk_scale_set_draw_value (scale, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* crea la ventana principal */
|
|
|
|
|
|
|
|
|
|
void create_range_controls( void )
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *caja1, *caja2, *caja3;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *scrollbar;
|
|
|
|
|
GtkWidget *separator;
|
|
|
|
|
GtkWidget *opt, *menu, *item;
|
|
|
|
|
GtkWidget *etiqueta;
|
|
|
|
|
GtkWidget *scale;
|
|
|
|
|
GtkObject *adj1, *adj2;
|
|
|
|
|
|
|
|
|
|
/* creaci<63>n est<73>ndar de una ventana */
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC(gtk_main_quit),
|
|
|
|
|
NULL);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "range controls");
|
|
|
|
|
|
|
|
|
|
caja1 = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), caja1);
|
|
|
|
|
gtk_widget_show (caja1);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_hbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
/* value, lower, upper, step_increment, page_increment, page_size */
|
|
|
|
|
/* Observe que el valor de page_size solo sirve para los widgets
|
|
|
|
|
* barras de desplazamiento (scrollbar), y que el valor m<>s
|
|
|
|
|
* alto que obtendr<64> ser<65> (upper - page_size). */
|
|
|
|
|
adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
|
|
|
|
|
|
|
|
|
|
vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
|
|
|
|
|
scale_set_default_values (GTK_SCALE (vscale));
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), vscale, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (vscale);
|
|
|
|
|
|
|
|
|
|
caja3 = gtk_vbox_new (FALSE, 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), caja3, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja3);
|
|
|
|
|
|
|
|
|
|
/* Reutilizamos el mismo ajuste */
|
|
|
|
|
hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
|
|
|
|
|
gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30);
|
|
|
|
|
scale_set_default_values (GTK_SCALE (hscale));
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja3), hscale, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (hscale);
|
|
|
|
|
|
|
|
|
|
/* Reutilizamos de nuevo el mismo ajuste */
|
|
|
|
|
scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
|
|
|
|
|
/* Observe que con esto conseguimos que la escala siempre se
|
|
|
|
|
* actualice de una forma continua cuando se mueva la barra de
|
|
|
|
|
* desplazamiento */
|
|
|
|
|
gtk_range_set_update_policy (GTK_RANGE (scrollbar),
|
|
|
|
|
GTK_UPDATE_CONTINUOUS);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja3), scrollbar, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (scrollbar);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_hbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
/* Un bot<6F>n para comprobar si el valor se muestra o no*/
|
|
|
|
|
boton = gtk_check_button_new_with_label("Display value on scale widgets");
|
|
|
|
|
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (boton), TRUE);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "toggled",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_draw_value), NULL);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_hbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
|
|
|
|
|
/* Una opci<63>n en el men<65> para cambiar la posici<63>n del
|
|
|
|
|
* valor */
|
|
|
|
|
etiqueta = gtk_label_new ("Scale Value Position:");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
opt = gtk_option_menu_new();
|
|
|
|
|
menu = gtk_menu_new();
|
|
|
|
|
|
|
|
|
|
item = make_menu_item ("Top",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_pos_menu_select),
|
|
|
|
|
GINT_TO_POINTER (GTK_POS_TOP));
|
|
|
|
|
gtk_menu_append (GTK_MENU (menu), item);
|
|
|
|
|
|
|
|
|
|
item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select),
|
|
|
|
|
GINT_TO_POINTER (GTK_POS_BOTTOM));
|
|
|
|
|
gtk_menu_append (GTK_MENU (menu), item);
|
|
|
|
|
|
|
|
|
|
item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select),
|
|
|
|
|
GINT_TO_POINTER (GTK_POS_LEFT));
|
|
|
|
|
gtk_menu_append (GTK_MENU (menu), item);
|
|
|
|
|
|
|
|
|
|
item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select),
|
|
|
|
|
GINT_TO_POINTER (GTK_POS_RIGHT));
|
|
|
|
|
gtk_menu_append (GTK_MENU (menu), item);
|
|
|
|
|
|
|
|
|
|
gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), opt, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (opt);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_hbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
|
|
|
|
|
/* S<>, otra opci<63>n de men<65>, esta vez para la pol<6F>tica
|
|
|
|
|
* de actualizaci<63>n de los widgets */
|
|
|
|
|
etiqueta = gtk_label_new ("Scale Update Policy:");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
opt = gtk_option_menu_new();
|
|
|
|
|
menu = gtk_menu_new();
|
|
|
|
|
|
|
|
|
|
item = make_menu_item ("Continuous",
|
|
|
|
|
GTK_SIGNAL_FUNC (cb_update_menu_select),
|
|
|
|
|
GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
|
|
|
|
|
gtk_menu_append (GTK_MENU (menu), item);
|
|
|
|
|
|
|
|
|
|
item = make_menu_item ("Discontinuous",
|
|
|
|
|
GTK_SIGNAL_FUNC (cb_update_menu_select),
|
|
|
|
|
GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
|
|
|
|
|
gtk_menu_append (GTK_MENU (menu), item);
|
|
|
|
|
|
|
|
|
|
item = make_menu_item ("Delayed",
|
|
|
|
|
GTK_SIGNAL_FUNC (cb_update_menu_select),
|
|
|
|
|
GINT_TO_POINTER (GTK_UPDATE_DELAYED));
|
|
|
|
|
gtk_menu_append (GTK_MENU (menu), item);
|
|
|
|
|
|
|
|
|
|
gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), opt, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (opt);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_hbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
|
|
|
|
|
/* Un widget GtkHScale para ajustar el n<>mero de d<>gitos en
|
|
|
|
|
* la escala. */
|
|
|
|
|
etiqueta = gtk_label_new ("Scale Digits:");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
|
|
|
|
|
GTK_SIGNAL_FUNC (cb_digits_scale), NULL);
|
|
|
|
|
scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
|
|
|
|
|
gtk_scale_set_digits (GTK_SCALE (scale), 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), scale, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (scale);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_hbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
|
|
|
|
|
/* Y un <20>ltimo widget GtkHScale para ajustar el tama<6D>o de la
|
|
|
|
|
* p<>gina de la barra de desplazamiento. */
|
|
|
|
|
etiqueta = gtk_label_new ("Scrollbar Page Size:");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), etiqueta, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
|
|
|
|
|
GTK_SIGNAL_FUNC (cb_page_size), adj1);
|
|
|
|
|
scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
|
|
|
|
|
gtk_scale_set_digits (GTK_SCALE (scale), 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), scale, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (scale);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (separator);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_vbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("Quit");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(gtk_main_quit),
|
|
|
|
|
NULL);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
|
|
|
|
|
GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
|
|
|
|
|
gtk_widget_grab_default (boton);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main( int argc,
|
|
|
|
|
char *argv[] )
|
|
|
|
|
{
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
|
|
|
|
create_range_controls();
|
|
|
|
|
|
|
|
|
|
gtk_main();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Observe que el programa no llama a <tt/gtk_signal_connect/ para
|
|
|
|
|
conectar el <20>delete_event<6E>, y que s<>lo conecta la se<73>al
|
|
|
|
|
<EFBFBD>destroy<EFBFBD>. Con esto seguimos realizando la funci<63>n deseada, ya que
|
|
|
|
|
un <20>delete_event<6E> no manejado desenboca en una se<73>al <20>destroy<6F>
|
|
|
|
|
para la ventana.
|
|
|
|
|
</sect1>
|
|
|
|
|
</sect>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect><em/Widgets/ varios
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Etiquetas
|
|
|
|
|
<p>
|
|
|
|
|
Las etiquetas se usan mucho en GTK y son bastante simples de manejar.
|
|
|
|
|
No pueden emitir se<73>ales ya que no tienen ventanas X window
|
|
|
|
|
asociadas. Si se desea capturar se<73>ales se debe usar el <em/widget/
|
|
|
|
|
EventBox o un <em/widget/ bot<6F>n.
|
|
|
|
|
|
|
|
|
|
Para crear una nueva etiqueta se usa:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_label_new( char *str );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El <20>nico argumento es la cadena de texto que se quiere mostrar.
|
|
|
|
|
|
|
|
|
|
Para cambiarla despu<70>s de que haya sido creada se usa:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_label_set( GtkLabel *etiqueta,
|
|
|
|
|
char *str );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
En este caso el primer argumento es la etiqueta ya creada (cambiado su
|
|
|
|
|
tipo mediante la macro <tt/GTK_LABEL()/) y el segundo es la nueva cadena.
|
|
|
|
|
El espacio que necesite la nueva etiqueta se ajustar<61>
|
|
|
|
|
autom<EFBFBD>ticamente, si es necesario.
|
|
|
|
|
|
|
|
|
|
Para obtener el estado de la cadena en un momento dado existe la
|
|
|
|
|
funci<EFBFBD>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_label_get( GtkLabel *etiqueta,
|
|
|
|
|
char **str );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
El primer argumento es la etiqueta, mientras que el segundo es el
|
|
|
|
|
valor devuelto para la cadena. No libere la memoria de la cadena
|
|
|
|
|
devuelta, ya que se utiliza internamente por GTK.
|
|
|
|
|
|
|
|
|
|
El texto de la etiqueta se puede justificar utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_label_set_justify( GtkLabel *etiqueta,
|
|
|
|
|
GtkJustification jtype );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los valores posibles para <tt/jtype/ son:
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_JUSTIFY_LEFT
|
|
|
|
|
<item> GTK_JUSTIFY_RIGHT
|
|
|
|
|
<item> GTK_JUSTIFY_CENTER (the default)
|
|
|
|
|
<item> GTK_JUSTIFY_FILL
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
El <em/widget/ etiqueta tambi<62>n es capaz de separar el texto de forma
|
|
|
|
|
autom<EFBFBD>tica cuando se llega al final de una linea. Esto se puede
|
|
|
|
|
conseguir utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_label_set_line_wrap (GtkLabel *etiqueta,
|
|
|
|
|
gboolean wrap);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/wrap/ toma el valor TRUE o FALSE.
|
|
|
|
|
|
|
|
|
|
Si quiere que su etiqueta salga subrayada, puede especificar un motivo
|
|
|
|
|
para el subrayado con:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_label_set_pattern (GtkLabel *etiqueta,
|
|
|
|
|
const gchar *pattern);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/pattern/ indica cual debe ser el aspecto del
|
|
|
|
|
subrayado. Consiste en una cadena de espacios en blanco y car<61>cteres
|
|
|
|
|
de subrayado. Por ejemplo, la cadena <tt/"__ __"/ debe hacer que
|
|
|
|
|
se subrayen los dos primeros y el octavo y el noveno car<61>cter.
|
|
|
|
|
|
|
|
|
|
A continuaci<63>n tenemos un peque<75>o ejemplo que ilustra el uso de estas
|
|
|
|
|
funciones. Este ejemplo utiliza el <em/widget/ marco (<em/frame/) para
|
|
|
|
|
hacer una mejor demostraci<63>n de los estilos de la etiqueta. Por ahora
|
|
|
|
|
puede ignorarlo, ya que el <em/widget/ <ref id="sec_Frames"
|
|
|
|
|
name="Frame"> se explicar<61> m<>s tarde.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo label label.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
int main( int argc,
|
|
|
|
|
char *argv[] )
|
|
|
|
|
{
|
|
|
|
|
static GtkWidget *ventana = NULL;
|
|
|
|
|
GtkWidget *hbox;
|
|
|
|
|
GtkWidget *vbox;
|
|
|
|
|
GtkWidget *frame;
|
|
|
|
|
GtkWidget *etiqueta;
|
|
|
|
|
|
|
|
|
|
/* Inicializa GTK */
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC(gtk_main_quit),
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Etiqueta");
|
|
|
|
|
vbox = gtk_vbox_new (FALSE, 5);
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 5);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), hbox);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (ventana), 5);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new ("Normal Label");
|
|
|
|
|
etiqueta = gtk_label_new ("This is a Normal label");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), etiqueta);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new ("Multi-line Label");
|
|
|
|
|
etiqueta = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
|
|
|
|
|
"Third line");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), etiqueta);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new ("Left Justified Label");
|
|
|
|
|
etiqueta = gtk_label_new ("This is a Left-Justified\n" \
|
|
|
|
|
"Multi-line label.\nThird line");
|
|
|
|
|
gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_LEFT);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), etiqueta);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new ("Right Justified Label");
|
|
|
|
|
etiqueta = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
|
|
|
|
|
"Fourth line, (j/k)");
|
|
|
|
|
gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_RIGHT);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), etiqueta);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new (FALSE, 5);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
|
|
|
|
|
frame = gtk_frame_new ("Line wrapped label");
|
|
|
|
|
etiqueta = gtk_label_new ("This is an example of a line-wrapped label. It " \
|
|
|
|
|
"should not be taking up the entire " /* big space to test spacing */\
|
|
|
|
|
"width allocated to it, but automatically " \
|
|
|
|
|
"wraps the words to fit. " \
|
|
|
|
|
"The time has come, for all good men, to come to " \
|
|
|
|
|
"the aid of their party. " \
|
|
|
|
|
"The sixth sheik's six sheep's sick.\n" \
|
|
|
|
|
" It supports multiple paragraphs correctly, " \
|
|
|
|
|
"and correctly adds "\
|
|
|
|
|
"many extra spaces. ");
|
|
|
|
|
gtk_label_set_line_wrap (GTK_LABEL (etiqueta), TRUE);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), etiqueta);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new ("Filled, wrapped label");
|
|
|
|
|
etiqueta = gtk_label_new ("This is an example of a line-wrapped, filled label. " \
|
|
|
|
|
"It should be taking "\
|
|
|
|
|
"up the entire width allocated to it. " \
|
|
|
|
|
"Here is a seneance to prove "\
|
|
|
|
|
"my point. Here is another sentence. "\
|
|
|
|
|
"Here comes the sun, do de do de do.\n"\
|
|
|
|
|
" This is a new paragraph.\n"\
|
|
|
|
|
" This is another newer, longer, better " \
|
|
|
|
|
"paragraph. It is coming to an end, "\
|
|
|
|
|
"unfortunately.");
|
|
|
|
|
gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_FILL);
|
|
|
|
|
gtk_label_set_line_wrap (GTK_LABEL (etiqueta), TRUE);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), etiqueta);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new ("Underlined label");
|
|
|
|
|
etiqueta = gtk_label_new ("This label is underlined!\n"
|
|
|
|
|
"This one is underlined in quite a funky fashion");
|
|
|
|
|
gtk_label_set_justify (GTK_LABEL (etiqueta), GTK_JUSTIFY_LEFT);
|
|
|
|
|
gtk_label_set_pattern (GTK_LABEL (etiqueta),
|
|
|
|
|
"_________________________ _ _________ _ ______ __ _______ ___");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), etiqueta);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show_all (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Flechas
|
|
|
|
|
<p>
|
|
|
|
|
En <em/widget/ flecha (<em/arrow/) dibuja la punta de una flecha,
|
|
|
|
|
con un estilo y hacia una direcci<63>n a escoger. Puede ser muy <20>til
|
|
|
|
|
en muchas aplicaciones cuando se coloca en un bot<6F>n.
|
|
|
|
|
|
|
|
|
|
S<EFBFBD>lo hay dos funciones para manipular el <em/widget/ flecha:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_arrow_new( GtkArrowType arrow_type,
|
|
|
|
|
GtkShadowType shadow_type );
|
|
|
|
|
|
|
|
|
|
void gtk_arrow_set( GtkArrow *arrow,
|
|
|
|
|
GtkArrowType arrow_type,
|
|
|
|
|
GtkShadowType shadow_type );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La primera crea un nuevo <em/widget/ flecha del tipo y apariencia
|
|
|
|
|
indicados. La segunda permite alterar posteriormente estos valores. El
|
|
|
|
|
argumento <tt/arrow_type/ puede tomar uno de los valores siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_ARROW_UP
|
|
|
|
|
<item> GTK_ARROW_DOWN
|
|
|
|
|
<item> GTK_ARROW_LEFT
|
|
|
|
|
<item> GTK_ARROW_RIGHT
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Naturalmente, estos valores indican la direcci<63>n a la que debe apuntar
|
|
|
|
|
la flecha. El argumento <tt/shadow_type/ puede tomar uno de los
|
|
|
|
|
valores siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_SHADOW_IN
|
|
|
|
|
<item> GTK_SHADOW_OUT (por defecto)
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_IN
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_OUT
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> tenemos un peque<75>o ejemplo para ilustrar la utilizaci<63>n de la
|
|
|
|
|
flecha.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo arrow arrow.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* Crea un widget flecha con los par<61>metros especificados
|
|
|
|
|
* y lo empaqueta en un bot<6F>n */
|
|
|
|
|
GtkWidget *create_arrow_button( GtkArrowType arrow_type,
|
|
|
|
|
GtkShadowType shadow_type )
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *arrow;
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new();
|
|
|
|
|
arrow = gtk_arrow_new (arrow_type, shadow_type);
|
|
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (boton), arrow);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
gtk_widget_show(arrow);
|
|
|
|
|
|
|
|
|
|
return(boton);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main( int argc,
|
|
|
|
|
char *argv[] )
|
|
|
|
|
{
|
|
|
|
|
/* GtkWidget es el tipo utilizado para los widgets */
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *box;
|
|
|
|
|
|
|
|
|
|
/* Inicializa el toolkit */
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* Crea una nueva ventana */
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Arrow Buttons");
|
|
|
|
|
|
|
|
|
|
/* Es una buena idea hacer esto con todas las ventanas. */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
|
|
|
|
|
|
|
|
|
|
/* Establece el ancho del borde de la ventana. */
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* Crea una caja para almacenar las flechas/botones */
|
|
|
|
|
box = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (box), 2);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), box);
|
|
|
|
|
|
|
|
|
|
/* Empaqueta y muestra todos nuestros widgets */
|
|
|
|
|
gtk_widget_show(box);
|
|
|
|
|
|
|
|
|
|
boton = create_arrow_button(GTK_ARROW_UP, GTK_SHADOW_IN);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
|
|
|
|
|
|
|
|
|
|
boton = create_arrow_button(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
|
|
|
|
|
|
|
|
|
|
boton = create_arrow_button(GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
|
|
|
|
|
|
|
|
|
|
boton = create_arrow_button(GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (box), boton, FALSE, FALSE, 3);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
/* Nos quedamos en gtk_main y <20>esperamos que empiece la diversi<73>n! */
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>El <em/widget/ de informaci<63>n r<>pida (<em/tooltip/)
|
|
|
|
|
<p>
|
|
|
|
|
Estos <em/widgets/ son las peque<75>as etiquetas que texto que
|
|
|
|
|
aparecen cuando se sit<69>a el puntero del rat<61>n sobre un bot<6F>n
|
|
|
|
|
u otro <em/widget/ durante algunos segundos. Son bastante f<>ciles
|
|
|
|
|
de usar, as<61> que no se dar<61> ning<6E>n ejemplo. Si quiere ver
|
|
|
|
|
alg<EFBFBD>n ejemplo se recomienda leer el programa testgtk.c que
|
|
|
|
|
acompa<EFBFBD>a a GTK.
|
|
|
|
|
|
|
|
|
|
Algunos <em/widgets/ (como la etiqueta) no pueden llevar asociado un
|
|
|
|
|
<em/tooltip/.
|
|
|
|
|
|
|
|
|
|
Para cada funci<63>n s<>lo hay que hacer una llamada para conseguir
|
|
|
|
|
un <em/tooltip/. El objeto <tt/GtkTooltip/ que devuelve la siguiente
|
|
|
|
|
funci<EFBFBD>n puede ser usado para crear m<>ltiples <em/widgets/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkTooltips *gtk_tooltips_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Una vez que el <em/tooltip/ ha sido creado (y el <em/widget/ sobre el
|
|
|
|
|
que se quiere usar) simplemente hay que usar la siguiente llamada para
|
|
|
|
|
pegarlo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tooltips_set_tip( GtkTooltips *tooltips,
|
|
|
|
|
GtkWidget *widget,
|
|
|
|
|
const gchar *tip_text,
|
|
|
|
|
const gchar *tip_private );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El primer argumento es el <em/tooltip/ que ya ha creado, seguido del
|
|
|
|
|
<em/widget/ al que se desea asociar el <em/tooltip/, el tercero es el
|
|
|
|
|
texto que se quiere que aparezca y el <20>ltimo es una cadena de texto
|
|
|
|
|
que puede ser usada como un identificador cuando se usa GtkTipsQuery
|
|
|
|
|
para desarollar ayuda sensible al contexto. Por ahora conviene dejarlo
|
|
|
|
|
como NULL.
|
|
|
|
|
|
|
|
|
|
<!-- TODO: sort out what how to do the context sensitive help -->
|
|
|
|
|
|
|
|
|
|
Veamos un ejemplo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkTooltips *tooltips;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
...
|
|
|
|
|
tooltips = gtk_tooltips_new ();
|
|
|
|
|
boton = gtk_button_new_with_label ("bot<6F>n 1");
|
|
|
|
|
...
|
|
|
|
|
gtk_tooltips_set_tip (tooltips, boton, "Este es el bot<6F>n 1", NULL);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Existen otras funciones que pueden ser usadas con los <em/tooltips/.
|
|
|
|
|
Solamente vamos a enumerlarlas a<>adiendo una peque<75>a descripci<63>n
|
|
|
|
|
de que hace cada una.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tooltips_enable( GtkTooltips *tooltips );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Permite que funcionen un conjunto de <em/tooltips/
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tooltips_disable( GtkTooltips *tooltips );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Oculta un conjunto de <em/tooltips/ para que no pueda ser mostrado.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tooltips_set_delay( GtkTooltips *tooltips,
|
|
|
|
|
gint delay );
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Establece cuantos milisegundos tiene que estar el puntero sobre el
|
|
|
|
|
<em/widget/ para que aparezca el <em/tooltip/. Por defecto se usan 1000
|
|
|
|
|
milisegundos (1 segundo).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tooltips_set_colors( GtkTooltips *tooltips,
|
|
|
|
|
GdkColor *background,
|
|
|
|
|
GdkColor *foreground );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Establece el color del texto y del fondo del <em/tooltip/. No se como
|
|
|
|
|
se especifica el color.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Barras de progreso <label id="sec_ProgressBar">
|
|
|
|
|
<p>
|
|
|
|
|
Estas barras se usan para mostrar el estado de una operaci<63>n. Son
|
|
|
|
|
bastante sencillas de utilizar, tal y como se ver<65> en los ejemplos
|
|
|
|
|
siguientes. Pero primero vamos a ver cuales son las funciones que hay
|
|
|
|
|
que utilizar para crear una nueva barra de progreso.
|
|
|
|
|
|
|
|
|
|
Hay dos formas de crear una nueva barra de progreso, la sencilla no
|
|
|
|
|
necesita de argumentos, y la otra recibe un objeto GtkAdjustment. Si
|
|
|
|
|
se utiliza la primera forma, la barra de progreso crear<61> su propio
|
|
|
|
|
GtkAdjustment.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_progress_bar_new( void );
|
|
|
|
|
|
|
|
|
|
GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El segundo m<>todo tiene la ventaja de que podemos utilizar el objeto
|
|
|
|
|
adjustment para especificar nuestro propio rango de par<61>metros para la
|
|
|
|
|
barra de progreso.
|
|
|
|
|
|
|
|
|
|
El ajuste de una barra de progreso se puede cambiar de forma din<69>mica
|
|
|
|
|
utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_set_adjustment( GtkProgress *progress,
|
|
|
|
|
GtkAdjustment *adjustment );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Ahora que hemos creado la barra de progreso ya podemos utilizarla.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_bar_update( GtkProgressBar *pbar,
|
|
|
|
|
gfloat percentage );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El primer argumento es la barra que se quiere manejar, el segundo es
|
|
|
|
|
tanto por ciento que ha sido `completado' (indica cuanto ha sido
|
|
|
|
|
llenada la barra y oscila entre 0-100%). El valor que se le tiene que
|
|
|
|
|
pasar oscila entre 0 y 1.
|
|
|
|
|
|
|
|
|
|
GTK+ v1.2 ha a<>adido una nueva caracter<65>stica a la barra de progreso,
|
|
|
|
|
y es que ahora permite mostrar su valor de varias maneras distintas, e
|
|
|
|
|
informar al usuario del valor y rango actual.
|
|
|
|
|
|
|
|
|
|
Una barra de progreso puede mostrarse con distintas orientaciones
|
|
|
|
|
utilizando la funci<63>n
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
|
|
|
|
|
GtkProgressBarOrientation orientation );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Donde el argumento <tt/orientaci<63>n/ puede tomar uno de los valores que
|
|
|
|
|
vienen a continuaci<63>n para indicar la direcci<63>n en la que se mueve la
|
|
|
|
|
barra de progreso:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_PROGRESS_LEFT_TO_RIGHT
|
|
|
|
|
<item> GTK_PROGRESS_RIGHT_TO_LEFT
|
|
|
|
|
<item> GTK_PROGRESS_BOTTOM_TO_TOP
|
|
|
|
|
<item> GTK_PROGRESS_TOP_TO_BOTTOM
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Cuando se utiliza como una medida de cuanto se ha completado de un
|
|
|
|
|
proceso, la barra de progreso puede configurarse para que muestre su
|
|
|
|
|
valor de una forma continua o discreta. En modo continuo, la barra de
|
|
|
|
|
progreso se actualiza mediante un n<>mero discreto de bloques, el
|
|
|
|
|
n<EFBFBD>mero de bloques tambi<62>n es configurable.
|
|
|
|
|
|
|
|
|
|
Se puede configurar el estilo de la barra de progreso utilizando la
|
|
|
|
|
siguiente funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_bar_set_bar_style( GtkProgressBar *pbar,
|
|
|
|
|
GtkProgressBarStyle style );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El par<61>metro <tt/style/ puede tomar uno de los dos valores siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>GTK_PROGRESS_CONTINUOUS
|
|
|
|
|
<item>GTK_PROGRESS_DISCRETE
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
El n<>mero de bloques se puede establecer utilizando
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
|
|
|
|
|
guint blocks );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La barra de progreso tambi<62>n se puede utilizar, a parte de para
|
|
|
|
|
indicar lo <20>avanzado<64> de una tarea, para indicar que hay alg<6C>n tipo
|
|
|
|
|
de actividad. Esto puede ser <20>til en situaciones donde no se pueda
|
|
|
|
|
medir el progreso de una tarea con un rango de valores. Para el modo
|
|
|
|
|
actividad, no sirve el estilo de barra que se ha descrito m<>s
|
|
|
|
|
arriba. Este modo hay que seleccionarlo utilizando la siguiente
|
|
|
|
|
funci<EFBFBD>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_set_activity_mode( GtkProgress *progress,
|
|
|
|
|
guint activity_mode );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El tama<6D>o del paso del indicador de actividad, y el n<>mero de bloques
|
|
|
|
|
se indican usando las siguientes funciones:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
|
|
|
|
|
guint step );
|
|
|
|
|
|
|
|
|
|
void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
|
|
|
|
|
guint blocks );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Cuando estamos en modo continuo, la barra de progreso puede mostrar un
|
|
|
|
|
texto configurable dentro la barra misma, utilizando la funci<63>n
|
|
|
|
|
siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_set_format_string( GtkProgress *progress,
|
|
|
|
|
gchar *format);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/format/ es parecido al que se utiliza en una orden
|
|
|
|
|
<tt/printf/ de C. Se pueden utilizar las siguientes opciones para el
|
|
|
|
|
formateado de la cadena:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> %p - porcentaje
|
|
|
|
|
<item> %v - valor
|
|
|
|
|
<item> %l - valor inferior del rango
|
|
|
|
|
<item> %u - valor superior del rango
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Puede activar o desactivar el texto utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_set_show_text( GtkProgress *progress,
|
|
|
|
|
gint show_text );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/show_text/ es un valor booleano TRUE/FALSE. La
|
|
|
|
|
apariencia del texto puede modificarse utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_set_text_alignment( GtkProgress *progress,
|
|
|
|
|
gfloat x_align,
|
|
|
|
|
gfloat y_align );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los argumentos <tt/x_align/ y <tt/y_align/ toman un valor entre 0.0 y
|
|
|
|
|
1.0. Este valor indica la posici<63>n de la cadena de texto dentro de la
|
|
|
|
|
barra. Si ponemos 0.0 en los dos sitios la cadena de texto aparecer<65>
|
|
|
|
|
en la esquina superior izquierda; un valor de 0.5 (el que se utiliza
|
|
|
|
|
por defecto) centra el texto, y un valor de 1.0 coloca el texto en la
|
|
|
|
|
esquina inferior derecha.
|
|
|
|
|
|
|
|
|
|
Se pueden leer los par<61>metros actuales del texto de un objeto barra
|
|
|
|
|
de progreso utilizando las dos funciones que se muestran a
|
|
|
|
|
continuaci<EFBFBD>n. La cadena de car<61>cteres devuelta por estas funciones
|
|
|
|
|
debe liberarse en la aplicaci<63>n (utilizando la funci<63>n
|
|
|
|
|
g_free()). Estas funciones devuelven el texto formateado que se
|
|
|
|
|
mostrar<EFBFBD> en la barra.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gchar *gtk_progress_get_current_text( GtkProgress *progress );
|
|
|
|
|
|
|
|
|
|
gchar *gtk_progress_get_text_from_value( GtkProgress *progress,
|
|
|
|
|
gfloat value );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Hay otra forma de cambiar el rango y el valor de un objeto barra de
|
|
|
|
|
progreso utilizando la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_configure( GtkProgress *progress,
|
|
|
|
|
gfloat value,
|
|
|
|
|
gfloat min,
|
|
|
|
|
gfloat max );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n proporciona una interfaz sencilla al rango y valor de una
|
|
|
|
|
barra de progreso.
|
|
|
|
|
|
|
|
|
|
Las funciones restantes se pueden utilizar para obtener y establecer
|
|
|
|
|
el valor actual de una barra de progreso utilizando distintos tipos y
|
|
|
|
|
formatos para el valor.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_progress_set_percentage( GtkProgress *progress,
|
|
|
|
|
gfloat percentage );
|
|
|
|
|
|
|
|
|
|
void gtk_progress_set_value( GtkProgress *progress,
|
|
|
|
|
gfloat value );
|
|
|
|
|
|
|
|
|
|
gfloat gtk_progress_get_value( GtkProgress *progress );
|
|
|
|
|
|
|
|
|
|
gfloat gtk_progress_get_current_percentage( GtkProgress *progress );
|
|
|
|
|
|
|
|
|
|
gfloat gtk_progress_get_percentage_from_value( GtkProgress *progress,
|
|
|
|
|
gfloat value );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Estas funciones son autoexplicatorias. La <20>ltima funci<63>n utiliza el
|
|
|
|
|
ajuste de la barra de progreso especificada para calcular el
|
|
|
|
|
porcentaje dentro del rango de valores de la barra.
|
|
|
|
|
|
|
|
|
|
Las barras de progreso se usan con otras funciones como los tiempos de
|
|
|
|
|
espera (<em/timeouts/), secci<63>n <ref id="sec_timeouts"
|
|
|
|
|
name="Tiempos de espera, E/S (I/O) y funciones ociosas (idle)">) para
|
|
|
|
|
crear la ilusi<73>n de la multitarea. Todas usan la funci<63>n
|
|
|
|
|
gtk_progress_bar_update de la misma manera.
|
|
|
|
|
|
|
|
|
|
Estudiemos un ejemplo de barras de progreso actualizada usando
|
|
|
|
|
tiempos de espera. Tambi<62>n se muestra como se debe reestablecer una
|
|
|
|
|
barra.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* comienzo del programa-ejemplo progressbar.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
typedef struct _ProgressData {
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *pbar;
|
|
|
|
|
int timer;
|
|
|
|
|
} ProgressData;
|
|
|
|
|
|
|
|
|
|
/* Actualiza el valor de la barra de progreso para que
|
|
|
|
|
* podamos ver alg<6C>n movimiento */
|
|
|
|
|
gint progress_timeout( gpointer data )
|
|
|
|
|
{
|
|
|
|
|
gfloat new_val;
|
|
|
|
|
GtkAdjustment *adj;
|
|
|
|
|
|
|
|
|
|
/* Calcula el valor de la barra de progreso utilizando
|
|
|
|
|
* el rango de valores establecido en el ajuste de la
|
|
|
|
|
* barra */
|
|
|
|
|
|
|
|
|
|
new_val = gtk_progress_get_value( GTK_PROGRESS(data) ) + 1;
|
|
|
|
|
|
|
|
|
|
adj = GTK_PROGRESS (data)->adjustment;
|
|
|
|
|
if (new_val > adj->upper)
|
|
|
|
|
new_val = adj->lower;
|
|
|
|
|
|
|
|
|
|
/* Establece el nuevo valor */
|
|
|
|
|
|
|
|
|
|
gtk_progress_set_value (GTK_PROGRESS (data), new_val);
|
|
|
|
|
|
|
|
|
|
/* Como esta es una funci<63>n de espera, devolvemos TRUE
|
|
|
|
|
* para que continue siendo llamada */
|
|
|
|
|
|
|
|
|
|
return(TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Funci<63>n de llamada que activa/desactiva el texto de dentro
|
|
|
|
|
* de la barra de progreso */
|
|
|
|
|
void toggle_show_text( GtkWidget *widget,
|
|
|
|
|
ProgressData *pdata )
|
|
|
|
|
{
|
|
|
|
|
gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
|
|
|
|
|
GTK_TOGGLE_BUTTON (widget)->active);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Funci<63>n de llamada que activa/desactiva el modo actividad
|
|
|
|
|
* de la barra de progreso */
|
|
|
|
|
void toggle_activity_mode( GtkWidget *widget,
|
|
|
|
|
ProgressData *pdata )
|
|
|
|
|
{
|
|
|
|
|
gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
|
|
|
|
|
GTK_TOGGLE_BUTTON (widget)->active);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Funci<63>n de llamada que activa/desactiva el modo continuo
|
|
|
|
|
* de la barra de progreso */
|
|
|
|
|
void set_continuous_mode( GtkWidget *widget,
|
|
|
|
|
ProgressData *pdata )
|
|
|
|
|
{
|
|
|
|
|
gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
|
|
|
|
|
GTK_PROGRESS_CONTINUOUS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Funci<63>n de llamada que activa/desactiva el modo discreto
|
|
|
|
|
* de la barra de progreso */
|
|
|
|
|
void set_discrete_mode( GtkWidget *widget,
|
|
|
|
|
ProgressData *pdata )
|
|
|
|
|
{
|
|
|
|
|
gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
|
|
|
|
|
GTK_PROGRESS_DISCRETE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Libera la memoria y elimina el temporizador */
|
|
|
|
|
void destroy_progress( GtkWidget *widget,
|
|
|
|
|
ProgressData *pdata)
|
|
|
|
|
{
|
|
|
|
|
gtk_timeout_remove (pdata->timer);
|
|
|
|
|
pdata->timer = 0;
|
|
|
|
|
pdata->ventana = NULL;
|
|
|
|
|
g_free(pdata);
|
|
|
|
|
gtk_main_quit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main( int argc,
|
|
|
|
|
char *argv[])
|
|
|
|
|
{
|
|
|
|
|
ProgressData *pdata;
|
|
|
|
|
GtkWidget *align;
|
|
|
|
|
GtkWidget *separator;
|
|
|
|
|
GtkWidget *table;
|
|
|
|
|
GtkAdjustment *adj;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *check;
|
|
|
|
|
GtkWidget *vbox;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* Reserva memoria para los datos que se le pasan a las funciones
|
|
|
|
|
* de llamada */
|
|
|
|
|
pdata = g_malloc( sizeof(ProgressData) );
|
|
|
|
|
|
|
|
|
|
pdata->ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_policy (GTK_WINDOW (pdata->ventana), FALSE, FALSE, TRUE);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (pdata->ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (destroy_progress),
|
|
|
|
|
pdata);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (pdata->ventana), "GtkProgressBar");
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (pdata->ventana), 0);
|
|
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new (FALSE, 5);
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (pdata->ventana), vbox);
|
|
|
|
|
gtk_widget_show(vbox);
|
|
|
|
|
|
|
|
|
|
/* Crea un objeto de alineamiento centrado */
|
|
|
|
|
align = gtk_alignment_new (0.5, 0.5, 0, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
|
|
|
|
|
gtk_widget_show(align);
|
|
|
|
|
|
|
|
|
|
/* Crea un objeto GtkAdjusment para albergar el rango de la barra
|
|
|
|
|
* de progreso */
|
|
|
|
|
adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* Crea la GtkProgressBar utilizando el ajuste */
|
|
|
|
|
pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
|
|
|
|
|
|
|
|
|
|
/* Establece el formato de la cadena de texto que puede mostrarse
|
|
|
|
|
* en la barra de progreso:
|
|
|
|
|
* %p - porcentaje
|
|
|
|
|
* %v - valor
|
|
|
|
|
* %l - valor inferior del rango
|
|
|
|
|
* %u - valor superior del rango */
|
|
|
|
|
gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
|
|
|
|
|
"%v from [%l-%u] (=%p%%)");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
|
|
|
|
|
gtk_widget_show(pdata->pbar);
|
|
|
|
|
|
|
|
|
|
/* A<>ade un temporizador para la actualizaci<63>n del valor de la
|
|
|
|
|
* barra de progreso */
|
|
|
|
|
pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
|
|
|
|
|
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show(separator);
|
|
|
|
|
|
|
|
|
|
/* filas, columnas, homog<6F>neo */
|
|
|
|
|
table = gtk_table_new (2, 3, FALSE);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
|
|
|
|
|
gtk_widget_show(table);
|
|
|
|
|
|
|
|
|
|
/* A<>ade un bot<6F>n de comprobaci<63>n para seleccionar si se debe
|
|
|
|
|
* mostrar el texto dentro de la barra */
|
|
|
|
|
check = gtk_check_button_new_with_label ("Show text");
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
|
|
|
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
|
|
|
|
|
5, 5);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (check), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (toggle_show_text),
|
|
|
|
|
pdata);
|
|
|
|
|
gtk_widget_show(check);
|
|
|
|
|
|
|
|
|
|
/* A<>ade un bot<6F>n de comprobaci<63>n para activar/desactivar el modo
|
|
|
|
|
* actividad */
|
|
|
|
|
check = gtk_check_button_new_with_label ("Activity mode");
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
|
|
|
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
|
|
|
|
|
5, 5);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (check), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (toggle_activity_mode),
|
|
|
|
|
pdata);
|
|
|
|
|
gtk_widget_show(check);
|
|
|
|
|
|
|
|
|
|
separator = gtk_vseparator_new ();
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
|
|
|
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
|
|
|
|
|
5, 5);
|
|
|
|
|
gtk_widget_show(separator);
|
|
|
|
|
|
|
|
|
|
/* A<>ade un bot<6F>n circular para seleccionar el modo continuo */
|
|
|
|
|
boton = gtk_radio_button_new_with_label (NULL, "Continuous");
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), boton, 2, 3, 0, 1,
|
|
|
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
|
|
|
|
|
5, 5);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (set_continuous_mode),
|
|
|
|
|
pdata);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
/* A<>ade un bot<6F>n circular para seleccionar el modo discreto */
|
|
|
|
|
boton = gtk_radio_button_new_with_label(
|
|
|
|
|
gtk_radio_button_group (GTK_RADIO_BUTTON (boton)),
|
|
|
|
|
"Discrete");
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), boton, 2, 3, 1, 2,
|
|
|
|
|
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
|
|
|
|
|
5, 5);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (set_discrete_mode),
|
|
|
|
|
pdata);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show(separator);
|
|
|
|
|
|
|
|
|
|
/* A<>ade un bot<6F>n para salir del programa */
|
|
|
|
|
boton = gtk_button_new_with_label ("close");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
(GtkSignalFunc) gtk_widget_destroy,
|
|
|
|
|
GTK_OBJECT (pdata->ventana));
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), boton, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
/* Esto hace que este bot<6F>n sea el bot<6F>n pueda utilizarse por
|
|
|
|
|
* defecto defecto. */
|
|
|
|
|
GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
|
|
|
|
|
|
|
|
|
|
/* Esto marca este bot<6F>n para que sea el bot<6F>n por
|
|
|
|
|
* defecto. Simplemente utilizando la tecla "Intro" haremos que se
|
|
|
|
|
* active este bot<6F>n. */
|
|
|
|
|
gtk_widget_grab_default (boton);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (pdata->ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Cuadros de di<64>logo
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ del cuadro de di<64>logo es bastante simple, s<>lo es una
|
|
|
|
|
ventana con algunas cosas ya preempaquetadas. Su estructura es la
|
|
|
|
|
siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct GtkDialog
|
|
|
|
|
{
|
|
|
|
|
GtkWindow ventana;
|
|
|
|
|
|
|
|
|
|
GtkWidget *vbox;
|
|
|
|
|
GtkWidget *action_area;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Simplemente se crea una ventana en la cual se empaqueta una vbox, un
|
|
|
|
|
separador y una hbox llamada <20>action_area<65>.
|
|
|
|
|
|
|
|
|
|
Este tipo de <em/widgets/ pueden ser usados como mensages <em/pop-up/
|
|
|
|
|
(peque<75>as ventanas con texto en su interior que aparecen cuando el
|
|
|
|
|
usuario hace algo y queremos informarle de alguna cosa) y otras cosas
|
|
|
|
|
parecidas. Su manejo desde el punto de vista del programador
|
|
|
|
|
es bastante f<>cil, s<>lo hay que usar una funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_dialog_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para crear un nuevo cuadro de di<64>logo hay que llamar a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
ventana = gtk_dialog_new ();
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Una vez que el cuadro ha sido creado s<>lo hay que usarlo. Por
|
|
|
|
|
ejemplo para empaquetar un bot<6F>n en la action_area escribir<69>amos
|
|
|
|
|
algo as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
boton = ...
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->action_area), boton,
|
|
|
|
|
TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Otra cosa que nos puede interesar es empaquetar una etiqueta en la
|
|
|
|
|
vbox:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
etiqueta = gtk_label_new ("Dialogs are groovy");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->vbox), etiqueta, TRUE,
|
|
|
|
|
TRUE, 0);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Otros ejemplo posible es poner dos botones en el action_area (uno
|
|
|
|
|
para cancelar y el otro para permitir algo) junto con una etiqueta en
|
|
|
|
|
la vbox el usuario puede seleccionar lo que quiera.
|
|
|
|
|
|
|
|
|
|
Si se precisa algo m<>s complejo siempre se puede empaquetar otro
|
|
|
|
|
<em/widget/ en cualquiera de las cajas (p.j. una tabla en una vbox).
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> <em/Pixmaps/ <label id="sec_Pixmaps">
|
|
|
|
|
<p>
|
|
|
|
|
Los <em/pixmaps/ son estructuras de datos que contienen dibujos. Estos
|
|
|
|
|
pueden ser usados en diferentes lugares, pero los iconos y los
|
|
|
|
|
cursores son los m<>s comunes.
|
|
|
|
|
|
|
|
|
|
Un <em/bitmap/ es un <em/pixmap/ que s<>lo tiene dos colores, y hay
|
|
|
|
|
unas cuantas rutinas especiales para controlar este caso particular.
|
|
|
|
|
|
|
|
|
|
Para comprender los <em/pixmaps/, puede ayudar entender como funciona
|
|
|
|
|
X-windows. Bajo X-windows, las aplicaciones no tienen porque estar
|
|
|
|
|
ejecut<EFBFBD>ndose en el ordenador que est<73> interactuando con el
|
|
|
|
|
usuario. Las distintas aplicaciones, llamadas <20>clientes<65>, comunican
|
|
|
|
|
con un programa que muestra los gr<67>ficos y que controla el tecledo y
|
|
|
|
|
el rat<61>n. Este programa que interactua directamente con el usuario se
|
|
|
|
|
llama un <20><em/display server/<2F> o <20>servidor X<>. Como la
|
|
|
|
|
comunicaci<EFBFBD>n entre el servidor y el cliente puede llevarse a cabo
|
|
|
|
|
mediante una red, es importante mantener alguna informaci<63>n en el
|
|
|
|
|
servidor X. Los <em/pixmaps/ por ejemplo, se almacenan en la memoria
|
|
|
|
|
del servidor X. Esto significa que una vez que se establecen los
|
|
|
|
|
valores del <em/pixmap/, no tienen que estar transmiti<74>ndose por la
|
|
|
|
|
red; en su lugar lo <20>nico que hay que enviar es una orden del estilo
|
|
|
|
|
<EFBFBD>mostrar <em/pixmap/ n<>mero XYZ aqu<71><75>. Incluso si no est<73> utilizando
|
|
|
|
|
X-windows con GTK, al utilizar construcciones como los <em/pixmaps/
|
|
|
|
|
conseguir<EFBFBD> que sus programas funciones de forma aceptable bajo
|
|
|
|
|
X-windows.
|
|
|
|
|
|
|
|
|
|
Para usar un <em/pixmap/ en GTK primero tiene que construir una
|
|
|
|
|
estructura del tipo GdkPixmap usando rutinas de GDK. Los <em/pixmaps/
|
|
|
|
|
se pueden crear usando datos que se encuentren en la memoria o en un
|
|
|
|
|
archivo. Veremos con detalle cada una de las dos posibilidades.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *ventana,
|
|
|
|
|
gchar *data,
|
|
|
|
|
gint width,
|
|
|
|
|
gint height );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta rutina se utiliza para crear un <em/bitmap/ a partir de datos
|
|
|
|
|
almacenados en la memoria. Cada bit de informaci<63>n indica si el
|
|
|
|
|
<em/pixel/ luce o no. Tanto la altura como la anchura estan expresadas
|
|
|
|
|
en <em/pixels/. El puntero del tipo GdkWindow indica la ventana en
|
|
|
|
|
cuesti<EFBFBD>n, ya que los <em/pixmaps/ s<>lo tienen sentido dentro de
|
|
|
|
|
la pantalla en la que van a ser mostrados.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *ventana,
|
|
|
|
|
gchar *data,
|
|
|
|
|
gint width,
|
|
|
|
|
gint height,
|
|
|
|
|
gint depth,
|
|
|
|
|
GdkColor *fg,
|
|
|
|
|
GdkColor *bg );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Con esto creamos un <em/pixmap/ con la profundidad (n<>mero de
|
|
|
|
|
colores) especificada en los datos del <em/bitmap/. Los valores
|
|
|
|
|
<tt/fg/ y <tt/bg/ son los colores del frente y del fondo
|
|
|
|
|
respectivamente.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow *ventana,
|
|
|
|
|
GdkBitmap **mask,
|
|
|
|
|
GdkColor *transparent_color,
|
|
|
|
|
const gchar *filename );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El formato XPM es una representacion de los <em/pixmaps/ para el
|
|
|
|
|
sistema X Window. Es bastante popular y existen muchos programas para
|
|
|
|
|
crear im<69>genes en este formato. El archivo especificado mediante
|
|
|
|
|
<tt/filename/ debe contener una imagen en ese formato para que sea
|
|
|
|
|
cargada en la estructura. La m<>scara especifica que bits son
|
|
|
|
|
opacos. Todos los dem<65>s bits se colorean usando el color
|
|
|
|
|
especificado en <tt/transparent_color/. M<>s adelante veremos un
|
|
|
|
|
ejemplo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow *ventana,
|
|
|
|
|
GdkBitmap **mask,
|
|
|
|
|
GdkColor *transparent_color,
|
|
|
|
|
gchar **data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se pueden incorporar im<69>genes peque<75>as dentro de un programa en
|
|
|
|
|
formato XPM. Un <em/pixmap/ se crea usando esta informaci<63>n, en
|
|
|
|
|
lugar de leerla de un archivo. Un ejemplo ser<65>a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* XPM */
|
|
|
|
|
static const char * xpm_data[] = {
|
|
|
|
|
"16 16 3 1",
|
|
|
|
|
" c None",
|
|
|
|
|
". c #000000000000",
|
|
|
|
|
"X c #FFFFFFFFFFFF",
|
|
|
|
|
" ",
|
|
|
|
|
" ...... ",
|
|
|
|
|
" .XXX.X. ",
|
|
|
|
|
" .XXX.XX. ",
|
|
|
|
|
" .XXX.XXX. ",
|
|
|
|
|
" .XXX..... ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" ......... ",
|
|
|
|
|
" ",
|
|
|
|
|
" "};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Cuando hayamos acabado de usar un <em/pixmap/ y no lo vayamos a usar
|
|
|
|
|
durante un tiempo suele ser conveniente liberar el recurso mediante
|
|
|
|
|
gdk_pixmap_unref(). (Los <em/pixmaps/ deben ser considerados recursos
|
|
|
|
|
preciosos).
|
|
|
|
|
|
|
|
|
|
Una vez que hemos creado el <em/pixmap/ lo podemos mostrar como un
|
|
|
|
|
<em/widget/ GTK. Primero tenemos que crear un <em/widget pixmap/ que
|
|
|
|
|
contenga un <em/pixmap/ GDK. Esto se hace usando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
|
|
|
|
|
GdkBitmap *mask );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Las otras funciones del <em/widget pixmap/ son:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_pixmap_get_type( void );
|
|
|
|
|
|
|
|
|
|
void gtk_pixmap_set( GtkPixmap *pixmap,
|
|
|
|
|
GdkPixmap *val,
|
|
|
|
|
GdkBitmap *mask );
|
|
|
|
|
|
|
|
|
|
void gtk_pixmap_get( GtkPixmap *pixmap,
|
|
|
|
|
GdkPixmap **val,
|
|
|
|
|
GdkBitmap **mask);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La funci<63>n gtk_pixmap_set se usa para cambiar los datos del
|
|
|
|
|
<em/pixmap/ que el <em/widget/ est<73> manejando en ese
|
|
|
|
|
momento. <tt/val/ es el <em/pixmap/ creado usando GDK.
|
|
|
|
|
|
|
|
|
|
El ejemplo siguiente usa un <em/pixmap/ en un bot<6F>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* comienzo del ejemplo pixmap.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Datos en formato XPM del icono de apertura de archivo */
|
|
|
|
|
static const char * xpm_data[] = {
|
|
|
|
|
"16 16 3 1",
|
|
|
|
|
" c None",
|
|
|
|
|
". c #000000000000",
|
|
|
|
|
"X c #FFFFFFFFFFFF",
|
|
|
|
|
" ",
|
|
|
|
|
" ...... ",
|
|
|
|
|
" .XXX.X. ",
|
|
|
|
|
" .XXX.XX. ",
|
|
|
|
|
" .XXX.XXX. ",
|
|
|
|
|
" .XXX..... ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" .XXXXXXX. ",
|
|
|
|
|
" ......... ",
|
|
|
|
|
" ",
|
|
|
|
|
" "};
|
|
|
|
|
|
|
|
|
|
/* Cuando se llama a esta funci<63>n (usando signal delete_event) se
|
|
|
|
|
* termina la aplicaci<63>n*/
|
|
|
|
|
|
|
|
|
|
void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
|
|
|
|
|
gtk_main_quit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Al presionar el bot<6F>n aparece el mensaje */
|
|
|
|
|
void button_clicked( GtkWidget *widget, gpointer data ) {
|
|
|
|
|
printf( "bot<6F>n pulsado\n" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main( int argc, char *argv[] )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
GtkWidget *ventana, *pixmapwid, *boton;
|
|
|
|
|
GdkPixmap *pixmap;
|
|
|
|
|
GdkBitmap *mask;
|
|
|
|
|
GtkStyle *style;
|
|
|
|
|
|
|
|
|
|
/* Creamos la ventana principal y relacionamos la se<73>al
|
|
|
|
|
* delete_event con acabar el programa.*/
|
|
|
|
|
gtk_init( &argc, &argv );
|
|
|
|
|
ventana = gtk_window_new( GTK_WINDOW_TOPLEVEL );
|
|
|
|
|
gtk_signal_connect( GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (close_application), NULL );
|
|
|
|
|
gtk_container_border_width( GTK_CONTAINER (ventana), 10 );
|
|
|
|
|
gtk_widget_show( ventana );
|
|
|
|
|
|
|
|
|
|
/* Ahora para el pixmap de gdk */
|
|
|
|
|
style = gtk_widget_get_style( ventana );
|
|
|
|
|
pixmap = gdk_pixmap_create_from_xpm_d( ventana->window, &mask,
|
|
|
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
|
|
|
(gchar **)xpm_data );
|
|
|
|
|
|
|
|
|
|
/* Un pixmap widget que contendr<64> al pixmap */
|
|
|
|
|
pixmapwid = gtk_pixmap_new( pixmap, mask );
|
|
|
|
|
gtk_widget_show( pixmapwid );
|
|
|
|
|
|
|
|
|
|
/* Un bot<6F>n para contener al pixmap */
|
|
|
|
|
boton = gtk_button_new();
|
|
|
|
|
gtk_container_add( GTK_CONTAINER(boton), pixmapwid );
|
|
|
|
|
gtk_container_add( GTK_CONTAINER(ventana), boton );
|
|
|
|
|
gtk_widget_show( boton );
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect( GTK_OBJECT(boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(button_clicked), NULL );
|
|
|
|
|
|
|
|
|
|
/* mostramos la ventana */
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para cargar un archivo llamado icon0.xpm con la informaci<63>n XPM (que
|
|
|
|
|
se encuentra en en directorio actual) habr<62>amos usado:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* cargar un pixmap desde un fichero */
|
|
|
|
|
pixmap = gdk_pixmap_create_from_xpm( ventana->window, &mask,
|
|
|
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
|
|
|
"./icon0.xpm" );
|
|
|
|
|
pixmapwid = gtk_pixmap_new( pixmap, mask );
|
|
|
|
|
gtk_widget_show( pixmapwid );
|
|
|
|
|
gtk_container_add( GTK_CONTAINER(ventana), pixmapwid );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Una desventaja de los <em/pixmaps/ es que la imagen mostrada siempre
|
|
|
|
|
es rectangular (independientemente de como sea la imagen en s<>). Si
|
|
|
|
|
queremos usar im<69>genes con otras formas debemos usar ventanas con
|
|
|
|
|
forma (<em/shaped windows/).
|
|
|
|
|
|
|
|
|
|
Este tipo de ventanas son pixmaps en los que el fondo es
|
|
|
|
|
transparente. As<41> cuando la imagen del fondo tiene muchos colores
|
|
|
|
|
no los sobreescribimos con el borde de nuestro icono. El ejemplo
|
|
|
|
|
siguiente muestra la imagen de una carretilla en el escritorio.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* comienzo del ejemplo carretilla wheelbarrow.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* XPM */
|
|
|
|
|
static char * WheelbarrowFull_xpm[] = {
|
|
|
|
|
"48 48 64 1",
|
|
|
|
|
" c None",
|
|
|
|
|
". c #DF7DCF3CC71B",
|
|
|
|
|
"X c #965875D669A6",
|
|
|
|
|
"o c #71C671C671C6",
|
|
|
|
|
"O c #A699A289A699",
|
|
|
|
|
"+ c #965892489658",
|
|
|
|
|
"@ c #8E38410330C2",
|
|
|
|
|
"# c #D75C7DF769A6",
|
|
|
|
|
"$ c #F7DECF3CC71B",
|
|
|
|
|
"% c #96588A288E38",
|
|
|
|
|
"& c #A69992489E79",
|
|
|
|
|
"* c #8E3886178E38",
|
|
|
|
|
"= c #104008200820",
|
|
|
|
|
"- c #596510401040",
|
|
|
|
|
"; c #C71B30C230C2",
|
|
|
|
|
": c #C71B9A699658",
|
|
|
|
|
"> c #618561856185",
|
|
|
|
|
", c #20811C712081",
|
|
|
|
|
"< c #104000000000",
|
|
|
|
|
"1 c #861720812081",
|
|
|
|
|
"2 c #DF7D4D344103",
|
|
|
|
|
"3 c #79E769A671C6",
|
|
|
|
|
"4 c #861782078617",
|
|
|
|
|
"5 c #41033CF34103",
|
|
|
|
|
"6 c #000000000000",
|
|
|
|
|
"7 c #49241C711040",
|
|
|
|
|
"8 c #492445144924",
|
|
|
|
|
"9 c #082008200820",
|
|
|
|
|
"0 c #69A618611861",
|
|
|
|
|
"q c #B6DA71C65144",
|
|
|
|
|
"w c #410330C238E3",
|
|
|
|
|
"e c #CF3CBAEAB6DA",
|
|
|
|
|
"r c #71C6451430C2",
|
|
|
|
|
"t c #EFBEDB6CD75C",
|
|
|
|
|
"y c #28A208200820",
|
|
|
|
|
"u c #186110401040",
|
|
|
|
|
"i c #596528A21861",
|
|
|
|
|
"p c #71C661855965",
|
|
|
|
|
"a c #A69996589658",
|
|
|
|
|
"s c #30C228A230C2",
|
|
|
|
|
"d c #BEFBA289AEBA",
|
|
|
|
|
"f c #596545145144",
|
|
|
|
|
"g c #30C230C230C2",
|
|
|
|
|
"h c #8E3882078617",
|
|
|
|
|
"j c #208118612081",
|
|
|
|
|
"k c #38E30C300820",
|
|
|
|
|
"l c #30C2208128A2",
|
|
|
|
|
"z c #38E328A238E3",
|
|
|
|
|
"x c #514438E34924",
|
|
|
|
|
"c c #618555555965",
|
|
|
|
|
"v c #30C2208130C2",
|
|
|
|
|
"b c #38E328A230C2",
|
|
|
|
|
"n c #28A228A228A2",
|
|
|
|
|
"m c #41032CB228A2",
|
|
|
|
|
"M c #104010401040",
|
|
|
|
|
"N c #492438E34103",
|
|
|
|
|
"B c #28A2208128A2",
|
|
|
|
|
"V c #A699596538E3",
|
|
|
|
|
"C c #30C21C711040",
|
|
|
|
|
"Z c #30C218611040",
|
|
|
|
|
"A c #965865955965",
|
|
|
|
|
"S c #618534D32081",
|
|
|
|
|
"D c #38E31C711040",
|
|
|
|
|
"F c #082000000820",
|
|
|
|
|
" ",
|
|
|
|
|
" .XoO ",
|
|
|
|
|
" +@#$%o& ",
|
|
|
|
|
" *=-;#::o+ ",
|
|
|
|
|
" >,<12#:34 ",
|
|
|
|
|
" 45671#:X3 ",
|
|
|
|
|
" +89<02qwo ",
|
|
|
|
|
"e* >,67;ro ",
|
|
|
|
|
"ty> 459@>+&& ",
|
|
|
|
|
"$2u+ ><ipas8* ",
|
|
|
|
|
"%$;=* *3:.Xa.dfg> ",
|
|
|
|
|
"Oh$;ya *3d.a8j,Xe.d3g8+ ",
|
|
|
|
|
" Oh$;ka *3d$a8lz,,xxc:.e3g54 ",
|
|
|
|
|
" Oh$;kO *pd$%svbzz,sxxxxfX..&wn> ",
|
|
|
|
|
" Oh$@mO *3dthwlsslszjzxxxxxxx3:td8M4 ",
|
|
|
|
|
" Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B* ",
|
|
|
|
|
" Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5& ",
|
|
|
|
|
" Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM* ",
|
|
|
|
|
" OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
|
|
|
|
|
" 2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
|
|
|
|
|
" :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
|
|
|
|
|
" +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
|
|
|
|
|
" *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
|
|
|
|
|
" p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
|
|
|
|
|
" OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
|
|
|
|
|
" 3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
|
|
|
|
|
" @26MvzxNzvlbwfpdettttttttttt.c,n& ",
|
|
|
|
|
" *;16=lsNwwNwgsvslbwwvccc3pcfu<o ",
|
|
|
|
|
" p;<69BvwwsszslllbBlllllllu<5+ ",
|
|
|
|
|
" OS0y6FBlvvvzvzss,u=Blllj=54 ",
|
|
|
|
|
" c1-699Blvlllllu7k96MMMg4 ",
|
|
|
|
|
" *10y8n6FjvllllB<166668 ",
|
|
|
|
|
" S-kg+>666<M<996-y6n<8* ",
|
|
|
|
|
" p71=4 m69996kD8Z-66698&& ",
|
|
|
|
|
" &i0ycm6n4 ogk17,0<6666g ",
|
|
|
|
|
" N-k-<> >=01-kuu666> ",
|
|
|
|
|
" ,6ky& &46-10ul,66, ",
|
|
|
|
|
" Ou0<> o66y<ulw<66& ",
|
|
|
|
|
" *kk5 >66By7=xu664 ",
|
|
|
|
|
" <<M4 466lj<Mxu66o ",
|
|
|
|
|
" *>> +66uv,zN666* ",
|
|
|
|
|
" 566,xxj669 ",
|
|
|
|
|
" 4666FF666> ",
|
|
|
|
|
" >966666M ",
|
|
|
|
|
" oM6668+ ",
|
|
|
|
|
" *4 ",
|
|
|
|
|
" ",
|
|
|
|
|
" "};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
|
|
|
|
|
gtk_main_quit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
GtkWidget *ventana, *pixmap, *fixed;
|
|
|
|
|
GdkPixmap *gdk_pixmap;
|
|
|
|
|
GdkBitmap *mask;
|
|
|
|
|
GtkStyle *style;
|
|
|
|
|
GdkGC *gc;
|
|
|
|
|
|
|
|
|
|
/* Creamos la ventana principal y relacionamos la se<73>al
|
|
|
|
|
* delete_event para terminar la aplicaci<63>n. Conviene destacar
|
|
|
|
|
* que la ventana no tendr<64> t<>tulo puesto que es popup.*/
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
ventana = gtk_window_new( GTK_WINDOW_POPUP );
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (close_application), NULL);
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
style = gtk_widget_get_default_style();
|
|
|
|
|
gc = style->black_gc;
|
|
|
|
|
gdk_pixmap = gdk_pixmap_create_from_xpm_d( ventana->window, &mask,
|
|
|
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
|
|
|
WheelbarrowFull_xpm );
|
|
|
|
|
pixmap = gtk_pixmap_new( gdk_pixmap, mask );
|
|
|
|
|
gtk_widget_show( pixmap );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fixed = gtk_fixed_new();
|
|
|
|
|
gtk_widget_set_usize( fixed, 200, 200 );
|
|
|
|
|
gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
|
|
|
|
|
gtk_container_add( GTK_CONTAINER(ventana), fixed );
|
|
|
|
|
gtk_widget_show( fixed );
|
|
|
|
|
|
|
|
|
|
/* Con esto cubrimos todo menos la imagen */
|
|
|
|
|
gtk_widget_shape_combine_mask( ventana, mask, 0, 0 );
|
|
|
|
|
|
|
|
|
|
/* mostramos la ventana */
|
|
|
|
|
gtk_widget_set_uposition( ventana, 20, 400 );
|
|
|
|
|
gtk_widget_show( ventana );
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para que la carretilla sea m<>s realista podr<64>amos relacionar la
|
|
|
|
|
pulsaci<EFBFBD>n del bot<6F>n con que haga algo. Con las l<>neas
|
|
|
|
|
siguientes la pulsaci<63>n del bot<6F>n hace que se acabe el programa.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_widget_set_events( ventana,
|
|
|
|
|
gtk_widget_get_events( ventana ) |
|
|
|
|
|
GDK_BUTTON_PRESS_MASK );
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect( GTK_OBJECT(ventana), "button_press_event",
|
|
|
|
|
GTK_SIGNAL_FUNC(close_application), NULL );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Reglas
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
Las reglas son usadas para indicar la posici<63>n del puntero del
|
|
|
|
|
rat<EFBFBD>n en una ventana dada. Una ventana puede tener una regla
|
|
|
|
|
vertical a lo largo de su alto y una horizontal a lo largo de su
|
|
|
|
|
ancho. Un peque<75>o indicador triangular muestra la relaci<63>n entre
|
|
|
|
|
el puntero del rat<61>n y la regla.
|
|
|
|
|
|
|
|
|
|
Las reglas (horizontales y verticales) se crean usando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_hruler_new( void ); /* horizontal */
|
|
|
|
|
GtkWidget *gtk_vruler_new( void ); /* vertical */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Las unidades de la regla pueden ser pixels, pulgadas o cent<6E>metros
|
|
|
|
|
(GKD_PIXELS, GDK_INCHES, GDK_CENTIMETRES). Esto se hace usando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_ruler_set_metric( GtkRuler *ruler,
|
|
|
|
|
GtkMetricType metric );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El valor por defecto es GTK_PIXELS.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Otra caracter<65>stica importante de las reglas es c<>mo mostrar las
|
|
|
|
|
unidades de escala y la posicion inicial d<>nde se situa el indicador.
|
|
|
|
|
Todo esto se consigue mediante:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_ruler_set_range( GtkRuler *ruler,
|
|
|
|
|
gfloat lower,
|
|
|
|
|
gfloat upper,
|
|
|
|
|
gfloat posicion,
|
|
|
|
|
gfloat max_size );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los argumentos <tt/lower/ (valor m<>s bajo) y <tt/upper/ (m<>s
|
|
|
|
|
alto) delimitan la extensi<73>n de la regla. El argumento
|
|
|
|
|
<tt/max_size/ es el n<>mero m<>s alto que ser<65> mostrado. Como
|
|
|
|
|
es l<>gico <tt/posicion/ define la posici<63>n inicial del indicador
|
|
|
|
|
dentro de la regla.
|
|
|
|
|
|
|
|
|
|
Una regla vertical puede puede llegar a ser de 800 pixels:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Las marcas dentro de la regla oscilar<61>n entre 0 y 800 con una
|
|
|
|
|
periodicidad de 100. Si queremos que var<61>e entre 7 y 16
|
|
|
|
|
debemos usar:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El indicador de la regla es un peque<75>o tri<72>ngulo que se<73>ala la
|
|
|
|
|
posici<EFBFBD>n del puntero con relaci<63>n a la regla. Si la regla debe
|
|
|
|
|
seguir al puntero del rat<61>n la se<73>al motion_notify_event debe estar
|
|
|
|
|
conectada con el motion_notify_event de la regla. Para seguir todos
|
|
|
|
|
los movimientos dentro de una ventana conviene usar:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
#define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
|
|
|
|
|
(GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
|
|
|
|
|
GTK_OBJECT(ruler) );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El siguiente ejemplo crea una zona de dibujo con una regla horizontal
|
|
|
|
|
y otra vertical. El tama<6D>o de la zona de dibujo es de 600 x 400
|
|
|
|
|
<em/pixels/. La regla horizontal oscila entre 7 y 13 con marcas cada
|
|
|
|
|
100 <em/pixels/, mientras que la vertical va desde 0 a 400 con
|
|
|
|
|
separaciones cada 100. La zona de dibujo y las reglas se sit<69>an
|
|
|
|
|
usando una tabla.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* comienzo del ejemplo rulers.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
#define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
|
|
|
|
|
|
|
|
|
|
#define XSIZE 600
|
|
|
|
|
#define YSIZE 400
|
|
|
|
|
|
|
|
|
|
/* Esta rutina toma el control cuando se pulsa el bot<6F>n close
|
|
|
|
|
*/
|
|
|
|
|
void close_application( GtkWidget *widget, GdkEvent *event, gpointer data ) {
|
|
|
|
|
gtk_main_quit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main( int argc, char *argv[] ) {
|
|
|
|
|
GtkWidget *ventana, *table, *area, *hrule, *vrule;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gtk_init( &argc, &argv );
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new( GTK_WINDOW_TOPLEVEL );
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC( close_application ), NULL);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* creaci<63>n de la tabla donde pondremos las reglas y la zona de
|
|
|
|
|
* dibujo */
|
|
|
|
|
table = gtk_table_new( 3, 2, FALSE );
|
|
|
|
|
gtk_container_add( GTK_CONTAINER(ventana), table );
|
|
|
|
|
|
|
|
|
|
area = gtk_drawing_area_new();
|
|
|
|
|
gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
|
|
|
|
|
gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
|
|
|
|
|
GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
|
|
|
|
|
gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK );
|
|
|
|
|
|
|
|
|
|
/* La regla horizontal est<73> arriba. Cuando el rat<61>n se mueve
|
|
|
|
|
* a lo largo de la zona de dibujo el controlador de eventos de la
|
|
|
|
|
* regla recibe motion_notify_event. */
|
|
|
|
|
hrule = gtk_hruler_new();
|
|
|
|
|
gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
|
|
|
|
|
gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
|
|
|
|
|
gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
|
|
|
|
|
(GtkSignalFunc)EVENT_METHOD(hrule,
|
|
|
|
|
motion_notify_event),
|
|
|
|
|
GTK_OBJECT(hrule) );
|
|
|
|
|
/* GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
|
|
|
|
|
gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
|
|
|
|
|
GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* la zona de dibujo el controlador de eventos de la regla recibe
|
|
|
|
|
* motion_notify_event. */
|
|
|
|
|
vrule = gtk_vruler_new();
|
|
|
|
|
gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
|
|
|
|
|
gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
|
|
|
|
|
gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
|
|
|
|
|
(GtkSignalFunc)
|
|
|
|
|
GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->
|
|
|
|
|
motion_notify_event,
|
|
|
|
|
GTK_OBJECT(vrule) );
|
|
|
|
|
gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
|
|
|
|
|
GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* mostramos todo */
|
|
|
|
|
gtk_widget_show( area );
|
|
|
|
|
gtk_widget_show( hrule );
|
|
|
|
|
gtk_widget_show( vrule );
|
|
|
|
|
gtk_widget_show( table );
|
|
|
|
|
gtk_widget_show( ventana );
|
|
|
|
|
gtk_main();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Barras de estado
|
|
|
|
|
<p>
|
|
|
|
|
Las barras de estado son widgets usados para mostrar un mensaje. Todo
|
|
|
|
|
aquello que haya sido mostrado se guarda en una pila, con lo que es
|
|
|
|
|
muy f<>cil repetir el <20>ltimo mensaje.
|
|
|
|
|
|
|
|
|
|
Para permitir que diferentes partes del programa usen la misma barra
|
|
|
|
|
de estado <20>stas usan Identificadores por Contexto (Context
|
|
|
|
|
Identifiers) para identificar a los `usuarios'. El mensaje que est<73>
|
|
|
|
|
en lo alto de la pila ser<65> el siguiente en mostrarse, sin importar
|
|
|
|
|
el contexto en el que se est<73>. Los mensajes se almacenan en el
|
|
|
|
|
orden el <20>ltimo en entrar es el primero en salir, y el
|
|
|
|
|
Identificador por Contexto no influye en este orden.
|
|
|
|
|
|
|
|
|
|
Las barras de estado se crean con una llamada a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_statusbar_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se pide un nuevo Identificador por Contexto con una peque<75>a
|
|
|
|
|
descripci<EFBFBD>n textual del contexto y una llamada a la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
|
|
|
|
|
const gchar *context_description );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Hay tres funciones que pueden manipular las barras de estado:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_statusbar_push( GtkStatusbar *statusbar,
|
|
|
|
|
guint context_id,
|
|
|
|
|
gchar *text );
|
|
|
|
|
|
|
|
|
|
void gtk_statusbar_pop( GtkStatusbar *statusbar)
|
|
|
|
|
guint context_id );
|
|
|
|
|
|
|
|
|
|
void gtk_statusbar_remove( GtkStatusbar *statusbar,
|
|
|
|
|
guint context_id,
|
|
|
|
|
guint message_id );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La primera, gtk_statusbar_push, se utiliza para a<>adir un nuevo
|
|
|
|
|
mensaje a la barra de estado. Devuelve un Identificador de Mensaje,
|
|
|
|
|
que podemos pasarle m<>s tarde a la funci<63>n gtk_statusbar_remove para
|
|
|
|
|
eliminar el mensaje con los Identificadores de Contexto y de Mensaje
|
|
|
|
|
que hay en la pila de barras de estado.
|
|
|
|
|
|
|
|
|
|
La funci<63>n gtk_statusbar_pop elimina el mensaje que se encuentra
|
|
|
|
|
m<EFBFBD>s alto en pila y que contiene el Identificador por Contexto
|
|
|
|
|
especificado.
|
|
|
|
|
|
|
|
|
|
El ejemplo siguiente crea una barra de estado y dos botones, uno para
|
|
|
|
|
meter un elemento en la barra y el otro para sacar el <20>ltimo elemento
|
|
|
|
|
introducido.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* Principio del ejemplo de barras de estado statusbar.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
|
|
GtkWidget *status_bar;
|
|
|
|
|
|
|
|
|
|
void push_item (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
static int count = 1;
|
|
|
|
|
char buff[20];
|
|
|
|
|
|
|
|
|
|
g_snprintf(buff, 20, "Item %d", count++);
|
|
|
|
|
gtk_statusbar_push( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data), buff);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void pop_item (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_statusbar_pop( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data) );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *vbox;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
|
|
|
|
|
int context_id;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* crear una nueva ventana */
|
|
|
|
|
ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_widget_set_usize( GTK_WIDGET (ventana), 200, 100);
|
|
|
|
|
gtk_window_set_title(GTK_WINDOW (ventana), "GTK Statusbar Example");
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
(GtkSignalFunc) gtk_exit, NULL);
|
|
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new(FALSE, 1);
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(ventana), vbox);
|
|
|
|
|
gtk_widget_show(vbox);
|
|
|
|
|
|
|
|
|
|
status_bar = gtk_statusbar_new();
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (status_bar);
|
|
|
|
|
|
|
|
|
|
context_id = gtk_statusbar_get_context_id(
|
|
|
|
|
GTK_STATUSBAR(status_bar), "Statusbar example");
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label("push item");
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (push_item), &context_id);
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), boton, TRUE, TRUE, 2);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label("pop last item");
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (pop_item), &context_id);
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), boton, TRUE, TRUE, 2);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
/* siempre mostramos la ventana en el <20>ltimo paso para que todo se
|
|
|
|
|
* dibuje en la pantalla de un golpe. */
|
|
|
|
|
gtk_widget_show(ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* Final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Entrada de texto
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ Entry permite mostrar e introducir texto en una l<>nea
|
|
|
|
|
de un cuadro de di<64>logo. El texto se puede poner con llamadas a funciones
|
|
|
|
|
que permiten reemplazar, prea<65>adir o a<>adir el texto al contenido
|
|
|
|
|
actual del <em/widget/ Entry.
|
|
|
|
|
|
|
|
|
|
Hay dos funciones para crear un <em/widget/ Entry:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_entry_new( void );
|
|
|
|
|
|
|
|
|
|
GtkWidget *gtk_entry_new_with_max_length( guint16 max );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La primera sirve para crear un nuevo <em/widget/ Entry, mientras que la
|
|
|
|
|
segunda crea el <em/widget/ y adem<65>s establece un l<>mite en la longitud
|
|
|
|
|
del texto que ir<69> en el mismo.
|
|
|
|
|
|
|
|
|
|
hay varias funciones que sirven para alterar el que texto que se est<73>
|
|
|
|
|
en el <em/widget/ Entry.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_entry_set_text( GtkEntry *entry,
|
|
|
|
|
const gchar *text );
|
|
|
|
|
|
|
|
|
|
void gtk_entry_append_text( GtkEntry *entry,
|
|
|
|
|
const gchar *text );
|
|
|
|
|
|
|
|
|
|
void gtk_entry_prepend_text( GtkEntry *entry,
|
|
|
|
|
const gchar *text );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La funci<63>n <tt/gtk_entry_set_text/ cambia el contenido actual del
|
|
|
|
|
<em/widget/ Entry. Las funciones <tt/gtk_entry_append_text/ y
|
|
|
|
|
<tt/gtk_entry_prepend_text/ permiten a<>adir o prea<65>adir texto.
|
|
|
|
|
|
|
|
|
|
Las funci<63>n siguientes permiten decir donde poner el punto de inserci<63>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_entry_set_position( GtkEntry *entry,
|
|
|
|
|
gint posicion );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se pueden obtener los contenidos del <em/widget/ llamando a la funci<63>n
|
|
|
|
|
que se describe a continuaci<63>n. Obtener los contenidos del <em/widget/
|
|
|
|
|
puede ser <20>til en las funciones de llamada descritas m<>s adelante.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gchar *gtk_entry_get_text( GtkEntry *entry );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Si quiere impedir que alguien cambie el contenido del <em/widget/ escribiendo
|
|
|
|
|
en <20>l, utilice la funci<63>n
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_entry_set_editable( GtkEntry *entry,
|
|
|
|
|
gboolean editable );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n permite camiar el estado de edici<63>n de un <em/widget/ Entry,
|
|
|
|
|
siendo el argumento <tt/editable/ TRUE o FALSE.
|
|
|
|
|
|
|
|
|
|
Si estamos utilizando el <em/widget/ Entry en un sitio donde no queremos
|
|
|
|
|
que el texto que se introduce sea visible, como por ejemplo cuando estamos
|
|
|
|
|
introduciendo una clave, podemos utilizar la funci<63>n siguiente, que tambi<62>n
|
|
|
|
|
admite como argumento una bandera booleana.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_entry_set_visibility( GtkEntry *entry,
|
|
|
|
|
gboolean visible );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se puede seleccionar una regi<67>n del texto utilizando la siguiente funci<63>n.
|
|
|
|
|
Esta funci<63>n se puede utilizar despu<70>s de poner alg<6C>n texto por defecto en
|
|
|
|
|
el <em/widget/, haci<63>ndole f<>cil al usuario eliminar este texto.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_entry_select_region( GtkEntry *entry,
|
|
|
|
|
gint start,
|
|
|
|
|
gint end );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Si queremos saber el momento en el que el usuario ha introducido el texto,
|
|
|
|
|
podemos conectar con las se<73>ales <tt/activate/ o <tt/changed/. <tt/activate/
|
|
|
|
|
se activa cuando el usuario aprieta la tecla enter en el <em/widget/.
|
|
|
|
|
<tt/changed/ se activa cuando cambia algo del texto, p.e. cuando se introduce
|
|
|
|
|
o se elimina alg<6C>n car<61>cter.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* Principio del ejemplo entry entry.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
void enter_callback(GtkWidget *widget, GtkWidget *entry)
|
|
|
|
|
{
|
|
|
|
|
gchar *entry_text;
|
|
|
|
|
entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
|
|
|
|
|
printf("Entry contents: %s\n", entry_text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void entry_toggle_editable (GtkWidget *checkbutton,
|
|
|
|
|
GtkWidget *entry)
|
|
|
|
|
{
|
|
|
|
|
gtk_entry_set_editable(GTK_ENTRY(entry),
|
|
|
|
|
GTK_TOGGLE_BUTTON(checkbutton)->active);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void entry_toggle_visibility (GtkWidget *checkbutton,
|
|
|
|
|
GtkWidget *entry)
|
|
|
|
|
{
|
|
|
|
|
gtk_entry_set_visibility(GTK_ENTRY(entry),
|
|
|
|
|
GTK_TOGGLE_BUTTON(checkbutton)->active);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *vbox, *hbox;
|
|
|
|
|
GtkWidget *entry;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *check;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* crear una nueva ventana */
|
|
|
|
|
ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_widget_set_usize( GTK_WIDGET (ventana), 200, 100);
|
|
|
|
|
gtk_window_set_title(GTK_WINDOW (ventana), "GTK Entry");
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
(GtkSignalFunc) gtk_exit, NULL);
|
|
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), vbox);
|
|
|
|
|
gtk_widget_show (vbox);
|
|
|
|
|
|
|
|
|
|
entry = gtk_entry_new_with_max_length (50);
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(entry), "activate",
|
|
|
|
|
GTK_SIGNAL_FUNC(enter_callback),
|
|
|
|
|
entry);
|
|
|
|
|
gtk_entry_set_text (GTK_ENTRY (entry), "hello");
|
|
|
|
|
gtk_entry_append_text (GTK_ENTRY (entry), " world");
|
|
|
|
|
gtk_entry_select_region (GTK_ENTRY (entry),
|
|
|
|
|
0, GTK_ENTRY(entry)->text_length);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (entry);
|
|
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (vbox), hbox);
|
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
|
|
|
|
|
|
check = gtk_check_button_new_with_label("Editable");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(check), "toggled",
|
|
|
|
|
GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
|
|
|
|
|
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
|
|
|
|
|
gtk_widget_show (check);
|
|
|
|
|
|
|
|
|
|
check = gtk_check_button_new_with_label("Visible");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(check), "toggled",
|
|
|
|
|
GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
|
|
|
|
|
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
|
|
|
|
|
gtk_widget_show (check);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("Close");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(gtk_exit),
|
|
|
|
|
GTK_OBJECT (ventana));
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), boton, TRUE, TRUE, 0);
|
|
|
|
|
GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
|
|
|
|
|
gtk_widget_grab_default (boton);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main();
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Botones <em/spin/
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ bot<6F>n <em/spin/ se utiliza normalmente para permitir
|
|
|
|
|
que el usuario elija un valor de un rango de valores. Consiste en una
|
|
|
|
|
caja para la entrada de texto con una flecha para arriba y otra para
|
|
|
|
|
abajo justo al lado de la caja. Si utilizamos alguna de las flechas
|
|
|
|
|
haremos que el valor suba o baje dentro del rango de los valores
|
|
|
|
|
posibles. Tambi<62>n podemos introducir directamente un valor espec<65>fico
|
|
|
|
|
(utilizando la caja de texto).
|
|
|
|
|
|
|
|
|
|
El <em/widget/ bot<6F>n <em/spin/ permite tener valores con un n<>mero de
|
|
|
|
|
cifras decimales (o sin cifras decimales) y la posibilidad de
|
|
|
|
|
incrementarlo/decrementarlo en pasos configurables. La acci<63>n de
|
|
|
|
|
matener pulsado uno de los botones puede resultar (es opcional) en una
|
|
|
|
|
aceleraci<EFBFBD>n del cambio en el valor de acuerdo con el tiempo que se
|
|
|
|
|
mantenga pulsado.
|
|
|
|
|
|
|
|
|
|
El bot<6F>n <em/spin/ utiliza un objeto <ref id="sec_Adjustment"
|
|
|
|
|
name="Ajuste"> para conservar la informaci<63>n referente al rango de
|
|
|
|
|
valores que puede tomar el bot<6F>n <em/spin/. Esto hace que el
|
|
|
|
|
<em/widget/ bot<6F>n <em/spin/ sea muy poderoso.
|
|
|
|
|
|
|
|
|
|
Recuerde que un <em/widget/ ajuste puede crearse con la siguiente
|
|
|
|
|
funci<EFBFBD>n, que ilustra la informaci<63>n que se guarda:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkObject *gtk_adjustment_new( gfloat valor,
|
|
|
|
|
gfloat inferior,
|
|
|
|
|
gfloat superior,
|
|
|
|
|
gfloat paso,
|
|
|
|
|
gfloat incremento_pagina,
|
|
|
|
|
gfloat tamano_pagina );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Estos atributos de un ajuste se utilizan en un bot<6F>n <em/spin/ de la
|
|
|
|
|
forma siguiente:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> <tt/valor/: valor inicial del bot<6F>n <em/spin/
|
|
|
|
|
<item> <tt/inferior/: valor inferior del rango
|
|
|
|
|
<item> <tt/superior/: valor superior del rango
|
|
|
|
|
<item> <tt/paso/: valor a incrementar/decrementar cuando pulsemos el
|
|
|
|
|
bot<EFBFBD>n 1 en una flecha
|
|
|
|
|
<item> <tt/incremento_pagina/: valor a incrementar/decrementar cuando
|
|
|
|
|
pulsemos el bot<6F>n 2 en una flecha
|
|
|
|
|
<item> <tt/tamano_pagina/: no se utiliza
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Adem<EFBFBD>s, se puede utilizar el bot<6F>n 3 para saltar directamente a los
|
|
|
|
|
valores <tt/superior/ o <tt/inferior/ cuando se pulsa en una de las
|
|
|
|
|
flechas. Veamos como crear un bot<6F>n <em/spin/:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_spin_button_new( GtkAdjustment *ajuste,
|
|
|
|
|
gfloat aceleracion,
|
|
|
|
|
guint digitos );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/aceleracion/ toma un valor entre 0.0 y 1.0 e indica
|
|
|
|
|
la aceleraci<63>n que tendr<64> el bot<6F>n <em/spin/. El argumento
|
|
|
|
|
<tt/digitos/ especifica el n<>mero de cifras decimales con que se
|
|
|
|
|
mostrar<EFBFBD> el valor.
|
|
|
|
|
|
|
|
|
|
Se puede reconfigurar un bot<6F>n <em/spin/ despu<70>s de su creaci<63>n
|
|
|
|
|
utilizando la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_configure( GtkSpinButton *boton_spin,
|
|
|
|
|
GtkAdjustment *ajuste,
|
|
|
|
|
gfloat aceleracion,
|
|
|
|
|
guint digitos );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/boton_spin/ especifica el bot<6F>n <em/spin/ que va a
|
|
|
|
|
reconfigurarse. El resto de argumentos son los que acabamos de
|
|
|
|
|
explicar.
|
|
|
|
|
|
|
|
|
|
Podemos establecer y obtener el ajuste utilizando las dos funciones
|
|
|
|
|
siguientes:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_set_adjustment( GtkSpinButton *boton_spin,
|
|
|
|
|
GtkAdjustment *ajuste );
|
|
|
|
|
|
|
|
|
|
GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *boton_spin );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El n<>mero de cifras decimales tambi<62>n puede alterarse utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_set_digits( GtkSpinButton *boton_spin,
|
|
|
|
|
guint digitos) ;
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El valor que un bot<6F>n <em/spin/ est<73> mostrando actualmente puede
|
|
|
|
|
cambiarse utilizando las siguientes funciones:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_set_value( GtkSpinButton *boton_spin,
|
|
|
|
|
gfloat valor );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El valor actual de un bot<6F>n <em/spin/ puede obtenerse como un entero o
|
|
|
|
|
como un flotante con las funciones siguientes:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *boton_spin );
|
|
|
|
|
|
|
|
|
|
gint gtk_spin_button_get_value_as_int( GtkSpinButton *boton_spin );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Si quiere alterar el valor de un <em/spin/ de forma relativa a su
|
|
|
|
|
valor actual, puede utilizar la siguiente funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_spin( GtkSpinButton *boton_spin,
|
|
|
|
|
GtkSpinType direccion,
|
|
|
|
|
gfloat incremento );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El par<61>metro <tt/direccion/ puede tomar uno de los valores siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_SPIN_STEP_FORWARD
|
|
|
|
|
<item> GTK_SPIN_STEP_BACKWARD
|
|
|
|
|
<item> GTK_SPIN_PAGE_FORWARD
|
|
|
|
|
<item> GTK_SPIN_PAGE_BACKWARD
|
|
|
|
|
<item> GTK_SPIN_HOME
|
|
|
|
|
<item> GTK_SPIN_END
|
|
|
|
|
<item> GTK_SPIN_USER_DEFINED
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Tratar<EFBFBD> de explicar todas las posibilidades que ofrece esta
|
|
|
|
|
funci<EFBFBD>n. Algunos de los valores que puede utilizar <tt/direccion/
|
|
|
|
|
hacen que se utilicen valores que est<73>n almacenados en el objeto
|
|
|
|
|
Ajuste que est<73> asociado con el bot<6F>n <em/spin/.
|
|
|
|
|
|
|
|
|
|
GTK_SPIN_STEP_FORWARD y GTK_SPIN_STEP_BACKWARD aumentan o disminuyen
|
|
|
|
|
(respectivamente) el valor del bot<6F>n <em/spin/ por la cantidad
|
|
|
|
|
especificada por <tt/incremento/, a menos que <tt/incremento/ sea
|
|
|
|
|
igual a 0, en cuyo caso el valor se aumentar<61> o disminuir<69> por el
|
|
|
|
|
valor especificado en <tt/paso/ dentro del Ajuste.
|
|
|
|
|
|
|
|
|
|
GTK_SPIN_PAGE_FORWARD y GTK_SPIN_PAGE_BACKWARD sencillamente alteran
|
|
|
|
|
el valor del bot<6F>n <em/spin/ por la cantidad <tt/incremento/.
|
|
|
|
|
|
|
|
|
|
GTK_SPIN_HOME hace que el bot<6F>n <em/spin/ tenga el mismo valor que el
|
|
|
|
|
valor inferior del rango Ajuste.
|
|
|
|
|
|
|
|
|
|
GTK_SPIN_END hace que el bot<6F>n <em/spin/ tenga el mismo valor que el
|
|
|
|
|
valor superior del rango Ajuste.
|
|
|
|
|
|
|
|
|
|
GTK_SPIN_USER_DEFINED cambia el valor del bot<6F>n <em/spin/ por la
|
|
|
|
|
cantidad especificada.
|
|
|
|
|
|
|
|
|
|
Ahora vamos a dejar de lado las funciones para establecer y obtener el
|
|
|
|
|
rango de los atributos del bot<6F>n <em/spin/, y vamos a pasar a las
|
|
|
|
|
funciones que afectan a la apariencia y al comportamiento del
|
|
|
|
|
<em/widget/ bot<6F>n <em/spin/ en s<> mismo.
|
|
|
|
|
|
|
|
|
|
La primera de estas funciones se utiliza para restringir el contenido
|
|
|
|
|
de la caja de texto de un bot<6F>n <em/spin/ a un valor num<75>rico. Esto
|
|
|
|
|
evita que un usuario introduzca cualquier valor no n<>merico.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_set_numeric( GtkSpinButton *boton_spin,
|
|
|
|
|
gboolean numerico );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Puede indicar si un bot<6F>n <em/spin/ pasar<61> del l<>mite superior al
|
|
|
|
|
inferior utilizando la siguiente funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_set_wrap( GtkSpinButton *boton_spin,
|
|
|
|
|
gboolean wrap );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Puede hacer que un bot<6F>n <em/spin/ redondee su valor al <tt/paso/ m<>s
|
|
|
|
|
cercano, que se indica cuando creamos el Ajuste que se utiliza con el
|
|
|
|
|
bot<EFBFBD>n <em/spin/. Para hacer que redondee tenemos que utilizar la
|
|
|
|
|
funci<EFBFBD>n siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_set_snap_to_ticks( GtkSpinButton *boton_spin,
|
|
|
|
|
gboolean redondear );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para pol<6F>tica de actualizaci<63>n de un bot<6F>n <em/spin/ puede cambiarse
|
|
|
|
|
con la siguiente funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_set_update_policy( GtkSpinButton *boton_spin,
|
|
|
|
|
GtkSpinButtonUpdatePolicy politica );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- TODO: find out what this does - TRG -->
|
|
|
|
|
|
|
|
|
|
Los valores posibles de <tt/politica/ son o GTK_UPDATE_ALWAYS o
|
|
|
|
|
GTK_UPDATE_IF_VALID.
|
|
|
|
|
|
|
|
|
|
Estas pol<6F>ticas afectan al comportamiento de un bot<6F>n <em/spin/ cuando
|
|
|
|
|
se lee el texto insertado en la caja de texto y se sincroniza con los
|
|
|
|
|
valores del Ajuste.
|
|
|
|
|
|
|
|
|
|
En el caso de GTK_UPDATE_IF_VALID el valor de un bot<6F>n <em/spin/
|
|
|
|
|
cambiar<EFBFBD> si el texto introducido es un valor num<75>rico contenido dentro
|
|
|
|
|
del rango especificado por el Ajuste. En caso contrario el texto
|
|
|
|
|
introducido se convierte al valor del bot<6F>n <em/spin/.
|
|
|
|
|
|
|
|
|
|
En caso de utilizar GTK_UPDATE_ALWAYS se ignorar<61>n los errores que
|
|
|
|
|
puedan ocurrir en la conversi<73>n del texto en un valor num<75>rico.
|
|
|
|
|
|
|
|
|
|
El aspecto de los botones utilizados en un bot<6F>n <em/spin/ pueden
|
|
|
|
|
cambiarse utilizando las siguientes funciones:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_set_shadow_type( GtkSpinButton *boton_spin,
|
|
|
|
|
GtkShadowType tipo_sombra );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como siempre, el <tt/tipo_sombra/ puede ser uno de los siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_SHADOW_IN
|
|
|
|
|
<item> GTK_SHADOW_OUT
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_IN
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_OUT
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Finalmente, puede pedir de forma expl<70>cita que un bot<6F>n <em/spin/ se
|
|
|
|
|
actualice a s<> mismo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_spin_button_update( GtkSpinButton *boton_spin );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Es hora de un nuevo ejemplo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo spinbutton spinbutton.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
static GtkWidget *spinner1;
|
|
|
|
|
|
|
|
|
|
void toggle_snap( GtkWidget *widget,
|
|
|
|
|
GtkSpinButton *spin )
|
|
|
|
|
{
|
|
|
|
|
gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)->active);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void toggle_numeric( GtkWidget *widget,
|
|
|
|
|
GtkSpinButton *spin )
|
|
|
|
|
{
|
|
|
|
|
gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)->active);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void change_digits( GtkWidget *widget,
|
|
|
|
|
GtkSpinButton *spin )
|
|
|
|
|
{
|
|
|
|
|
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
|
|
|
|
|
gtk_spin_button_get_value_as_int (spin));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void get_value( GtkWidget *widget,
|
|
|
|
|
gpointer data )
|
|
|
|
|
{
|
|
|
|
|
gchar buf[32];
|
|
|
|
|
GtkLabel *etiqueta;
|
|
|
|
|
GtkSpinButton *spin;
|
|
|
|
|
|
|
|
|
|
spin = GTK_SPIN_BUTTON (spinner1);
|
|
|
|
|
etiqueta = GTK_LABEL (gtk_object_get_user_data (GTK_OBJECT (widget)));
|
|
|
|
|
if (GPOINTER_TO_INT (data) == 1)
|
|
|
|
|
sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
|
|
|
|
|
else
|
|
|
|
|
sprintf (buf, "%0.*f", spin->digits,
|
|
|
|
|
gtk_spin_button_get_value_as_float (spin));
|
|
|
|
|
gtk_label_set_text (etiqueta, buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main( int argc,
|
|
|
|
|
char *argv[] )
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *frame;
|
|
|
|
|
GtkWidget *hbox;
|
|
|
|
|
GtkWidget *main_vbox;
|
|
|
|
|
GtkWidget *vbox;
|
|
|
|
|
GtkWidget *vbox2;
|
|
|
|
|
GtkWidget *spinner2;
|
|
|
|
|
GtkWidget *spinner;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *etiqueta;
|
|
|
|
|
GtkWidget *val_label;
|
|
|
|
|
GtkAdjustment *adj;
|
|
|
|
|
|
|
|
|
|
/* Inicializar GTK */
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit),
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Spin Button");
|
|
|
|
|
|
|
|
|
|
main_vbox = gtk_vbox_new (FALSE, 5);
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), main_vbox);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new ("Not accelerated");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
|
|
|
|
|
|
|
|
/* spin del d<>a, mes y a<>o */
|
|
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
vbox2 = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new ("Day :");
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
|
|
|
|
|
5.0, 0.0);
|
|
|
|
|
spinner = gtk_spin_button_new (adj, 0, 0);
|
|
|
|
|
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
|
|
|
|
|
gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
|
|
|
|
|
GTK_SHADOW_OUT);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
vbox2 = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new ("Month :");
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
|
|
|
|
|
5.0, 0.0);
|
|
|
|
|
spinner = gtk_spin_button_new (adj, 0, 0);
|
|
|
|
|
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
|
|
|
|
|
gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
|
|
|
|
|
GTK_SHADOW_ETCHED_IN);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
vbox2 = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new ("Year :");
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
|
|
|
|
|
1.0, 100.0, 0.0);
|
|
|
|
|
spinner = gtk_spin_button_new (adj, 0, 0);
|
|
|
|
|
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
|
|
|
|
|
gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
|
|
|
|
|
GTK_SHADOW_IN);
|
|
|
|
|
gtk_widget_set_usize (spinner, 55, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new ("Accelerated");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
|
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
vbox2 = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new ("Value :");
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
|
|
|
|
|
0.5, 100.0, 0.0);
|
|
|
|
|
spinner1 = gtk_spin_button_new (adj, 1.0, 2);
|
|
|
|
|
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
|
|
|
|
|
gtk_widget_set_usize (spinner1, 100, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
vbox2 = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new ("Digits :");
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta), 0, 0.5);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), etiqueta, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
|
|
|
|
|
spinner2 = gtk_spin_button_new (adj, 0.0, 0);
|
|
|
|
|
gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
|
|
|
|
|
GTK_SIGNAL_FUNC (change_digits),
|
|
|
|
|
(gpointer) spinner2);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
boton = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (toggle_snap),
|
|
|
|
|
spinner1);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), boton, TRUE, TRUE, 0);
|
|
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (boton), TRUE);
|
|
|
|
|
|
|
|
|
|
boton = gtk_check_button_new_with_label ("Numeric only input mode");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (toggle_numeric),
|
|
|
|
|
spinner1);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), boton, TRUE, TRUE, 0);
|
|
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (boton), TRUE);
|
|
|
|
|
|
|
|
|
|
val_label = gtk_label_new ("");
|
|
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
|
|
|
|
|
boton = gtk_button_new_with_label ("Value as Int");
|
|
|
|
|
gtk_object_set_user_data (GTK_OBJECT (boton), val_label);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (get_value),
|
|
|
|
|
GINT_TO_POINTER (1));
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), boton, TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("Value as Float");
|
|
|
|
|
gtk_object_set_user_data (GTK_OBJECT (boton), val_label);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (get_value),
|
|
|
|
|
GINT_TO_POINTER (2));
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), boton, TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
|
|
|
|
|
gtk_label_set_text (GTK_LABEL (val_label), "0");
|
|
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("Close");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
|
|
|
|
GTK_OBJECT (ventana));
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), boton, TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show_all (ventana);
|
|
|
|
|
|
|
|
|
|
/* Entramos dentro del bucle de eventos */
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Caja combinada (<em/Combo Box/)
|
|
|
|
|
<p>
|
|
|
|
|
La caja combinada o <em/combo box/ es otro sencillo <em/widget/
|
|
|
|
|
exclusivamente compuesto por otros <em/widgets/. Desde el punto de
|
|
|
|
|
vista del usuario, el <em/widget/ consiste en una caja para la
|
|
|
|
|
introducci<EFBFBD>n de texto y un men<65> desplegable desde el que el usuario
|
|
|
|
|
puede seleccionar una de un conjunto predefinido de entradas. De forma
|
|
|
|
|
alternativa, el usuario puede introducir una opci<63>n diferente en la
|
|
|
|
|
caja de texto.
|
|
|
|
|
|
|
|
|
|
El siguiente extracto de la estructura que define un Combo Box
|
|
|
|
|
identifica algunos de sus componentes:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GtkCombo {
|
|
|
|
|
GtkHBox hbox;
|
|
|
|
|
GtkWidget *entry;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *popup;
|
|
|
|
|
GtkWidget *popwin;
|
|
|
|
|
GtkWidget *list;
|
|
|
|
|
... };
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como puede ver, el Combo Box tiene dos partes principales que tiene
|
|
|
|
|
que conocer: un <em/widget entry/ y un <em/widget list/ (lista).
|
|
|
|
|
|
|
|
|
|
Lo primero, para crear un combo box, utilice:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_combo_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Ahora, si quiere indicar la cadena que debe aparecer en la secci<63>n
|
|
|
|
|
entry del combo box, podr<64> hacerlo manipulando directamente el
|
|
|
|
|
<em/widget/ <tt/entry/:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "Mi cadena.");
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para introducir valores en la lista desplegable, puede utilizar la
|
|
|
|
|
funci<EFBFBD>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_combo_set_popdown_strings( GtkCombo *combo,
|
|
|
|
|
GList *cadenas );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Antes de llamar a esta funci<63>n, tiene que ensamblar una GList con las
|
|
|
|
|
cadenas que quiere. GList es una implementaci<63>n de una lista enlazada
|
|
|
|
|
que forma parte de <ref id="sec_glib" name="glib">, una biblioteca
|
|
|
|
|
base de GTK. Por el momento, la explicaci<63>n fea y r<>pida es que tiene
|
|
|
|
|
que crear un puntero GList, hacerlo igual a NULL, y a<>adirle cadenas
|
|
|
|
|
de texto con la funci<63>n
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GList *g_list_append( GList *glist,
|
|
|
|
|
gpointer datos );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Es importante que inicialice el puntero GList a NULL antes de
|
|
|
|
|
utilizarlo. El valor devuelto por la funci<63>n g_list_append debe
|
|
|
|
|
utilizarse como el nuevo puntero a la GList.
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> tenemos un trozo de c<>digo t<>pico para crear un conjunto de
|
|
|
|
|
opciones:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GList *glist=NULL;
|
|
|
|
|
|
|
|
|
|
glist = g_list_append(glist, "Cadena 1");
|
|
|
|
|
glist = g_list_append(glist, "Cadena 2");
|
|
|
|
|
glist = g_list_append(glist, "Cadena 3");
|
|
|
|
|
glist = g_list_append(glist, "Cadena 4");
|
|
|
|
|
|
|
|
|
|
gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ;
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
A partir de este momento tendr<64> un combo box completo funcionando. Hay
|
|
|
|
|
unos cuantos aspectos de su funcionamiento que puede cambiar. Para
|
|
|
|
|
hacerlo tiene las funciones siguientes:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_combo_set_use_arrows( GtkCombo *combo,
|
|
|
|
|
gint valor );
|
|
|
|
|
|
|
|
|
|
void gtk_combo_set_use_arrows_always( GtkCombo *combo,
|
|
|
|
|
gint valor );
|
|
|
|
|
|
|
|
|
|
void gtk_combo_set_case_sensitive( GtkCombo *combo,
|
|
|
|
|
gint valor );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/gtk_combo_set_use_arrows()/ le deja al usuario cambiar el valor
|
|
|
|
|
del combo box utilizando las flechas de arriba/abajo. Utilizando estas
|
|
|
|
|
teclas no haremos salir la lista, pero se reemplazar<61> el texto actual
|
|
|
|
|
del combo box con el siguiente elemento de la lista (superior o
|
|
|
|
|
inferior, seg<65>n la tecla que se pulse). Esto se consigue buscando en
|
|
|
|
|
la lista el elemento correspondiente al valor actual del combo box y
|
|
|
|
|
seleccionando el anterior o el posterior (seg<65>n corresponda).
|
|
|
|
|
Normalmente en una caja de entrada de texto las flechas se utilizan
|
|
|
|
|
para cambiar el foco (ie. el <em/widget/ que recibe la entrada del
|
|
|
|
|
teclado), pero en este caso ser<65> el TAB quien se ocupe. Cuando el
|
|
|
|
|
elemento actual sea el <20>ltimo de la lista y presione la flecha abajo
|
|
|
|
|
se cambiar<61> el foco (lo mismo se aplica cuando estamos sobre el primer
|
|
|
|
|
elemento y pulsamos la tecla arriba).
|
|
|
|
|
|
|
|
|
|
Si el valor actual en la caja de entrada de texto no est<73> en la lista,
|
|
|
|
|
entonces se desactiva la funci<63>n de <tt/gtk_combo_set_use_arrows()/.
|
|
|
|
|
|
|
|
|
|
<tt/gtk_combo_set_use_arrows_always()/ igualmente permite la
|
|
|
|
|
utilizaci<EFBFBD>n de las flechas arriba/abajo para cambiar el elemento
|
|
|
|
|
seleccionado por el siguiente/anterior de la lista, pero adem<65>s trata
|
|
|
|
|
la lista como si fuese circular (ie. pasa del <20>ltimo al primer
|
|
|
|
|
elemento), desactivando completamente la utilidad de las teclas arriba
|
|
|
|
|
y abajo para cambiar el foco.
|
|
|
|
|
|
|
|
|
|
<tt/gtk_combo_set_case_sensitive()/ cambia entre una b<>squeda por la
|
|
|
|
|
lista que discrimine entre may<61>sculas y min<69>sculas y una b<>squeda que
|
|
|
|
|
no discrimine. Se utiliza cuando se quiere que el <em/widget/ combo
|
|
|
|
|
complete el valor que se est<73> introduciendo con un valor de la
|
|
|
|
|
lista. Dependiendo de esta funci<63>n, se completar<61> distinguiendo entre
|
|
|
|
|
may<EFBFBD>sculas y min<69>sculas o no. El <em/widget/ combo completar<61> la
|
|
|
|
|
entrada actual si el usuario presiona la combinaci<63>n de teclas MOD-1 y
|
|
|
|
|
`Tab'. MOD-1 normalmente es la tecla `Alt'. Hay algunos
|
|
|
|
|
administradores de ventanas que tambi<62>n utilizan esta combinaci<63>n de
|
|
|
|
|
teclas, con lo que perderemos su posible utilizaci<63>n por parte de GTK.
|
|
|
|
|
|
|
|
|
|
Ahora que tenemos un combo box que actua como queremos que actue, todo
|
|
|
|
|
lo que nos queda es saber como hay que hacer para obtener los datos
|
|
|
|
|
que nos puede proporcionar. Esto es relativamente sencillo. La mayor<6F>a
|
|
|
|
|
del tiempo, de lo <20>nico que tiene que preocuparse es de obtener datos
|
|
|
|
|
de la caja de texto. Podemos acceder a la caja de texto mediante
|
|
|
|
|
GTK_ENTRY(GTK_COMBO(combo)->entry). Las dos cosas que son interesantes
|
|
|
|
|
hacer con esta caja son: enlazarla con la se<73>al <tt/activate/, que
|
|
|
|
|
indica que el usuario ha presionado la tecla <20>Intro<72>, y leer el
|
|
|
|
|
texto. Lo primero podemos hacerlo utilizando algo as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate",
|
|
|
|
|
GTK_SIGNAL_FUNC (mi_funcion_respuesta), mis_datos);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para conseguir el texto que hay en la caja en cualquier momento s<>lo
|
|
|
|
|
tenemos que utilizar la funci<63>n siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gchar *gtk_entry_get_text(GtkEntry *entry);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
De esta forma:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
char *cadena;
|
|
|
|
|
|
|
|
|
|
cadena = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esto es todo lo interesante. Existe otra funci<63>n,
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_combo_disable_activate(GtkCombo *combo);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
que permite desactivar la se<73>al <tt/activate/ en el <em/widget/ entry
|
|
|
|
|
dentro del combo box. Personalmente no se me ocurre ning<6E>n motivo para
|
|
|
|
|
utilizarla, pero existir existe.
|
|
|
|
|
|
|
|
|
|
<!-- There are also a function to set the string on a particular item, void
|
|
|
|
|
gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
|
|
|
|
|
*item_value), but this requires that you have a pointer to the
|
|
|
|
|
appropriate GtkItem. Frankly, I have no idea how to do that.
|
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
|
<!-- ************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Selecci<63>n de Color
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ selecci<63>n de color, nos permite (<28>sorpresa!) la selecci<63>n
|
|
|
|
|
interactiva de colores. Este <em/widget/ compuesto le permite al usuario
|
|
|
|
|
seleccionar un color manipulando los tripletes RGB (rojo, verde y azul) y
|
|
|
|
|
HSV (tono, saturaci<63>n, valor). Para conseguirlo puede ajustar cada variable
|
|
|
|
|
mediante las regletas o introduciendo directamente el valor deseado.
|
|
|
|
|
Tambi<EFBFBD>n puede pinchar en la rueda de colores y seleccionar as<61> el color
|
|
|
|
|
deseado. Tambi<62>n se puede establecer, opcionalmente, la transparencia
|
|
|
|
|
del color.
|
|
|
|
|
|
|
|
|
|
El <em/widget/ de selecci<63>n de color emite (por ahora) s<>lo una se<73>al,
|
|
|
|
|
<tt/color_changed/, que se emite cuando cambia el color seleccionado,
|
|
|
|
|
ya sea mediante un cambio que haga el usuario o median el resultado
|
|
|
|
|
de una llamada a la funci<63>n <tt/gtk_color_selection_set_color()/.
|
|
|
|
|
|
|
|
|
|
Ech<EFBFBD>mosle un vistazo a lo que nos ofrece el <em/widget/ de selecci<63>n de color.
|
|
|
|
|
El <em/widget/ tiene dos <20>sabores<65> diferentes; <tt/gtk_color_selection/
|
|
|
|
|
y <tt/gtk_color_selection_dialog/:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_color_selection_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Probablemente no utilizar<61> este constructor directamente. Crea un <em/widget/
|
|
|
|
|
GtkColorSelection hu<68>rfano al que le tendr<64> que asignarle un padre. El
|
|
|
|
|
<em/widget/ GtkColorSelection est<73> heredado del <em/widget/ GtkVBox.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<EFBFBD>ste es el constructor del cuadro de selecci<63>n de color m<>s com<6F>n. Crea un
|
|
|
|
|
<tt/GtkColorSelectionDialog/, heredado de un <tt/GtkDialog/. Consiste en un
|
|
|
|
|
<tt/GtkFrame/ con un <tt/GtkColorSelection/, un <tt/GtkHSeparator/ y un
|
|
|
|
|
<tt/GtkHBox/ con tres botones, <20>Aceptar<61>, <20>Cancelar<61> y <20>Ayuda<64>.
|
|
|
|
|
Puede utilizar estos botones accediendo a los <em/widgets/ <tt/ok_button/,
|
|
|
|
|
<tt/cancel_button/ y <tt/help_button/ de la estructura GtkColorSelectionDialog,
|
|
|
|
|
(es decir GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel,
|
|
|
|
|
GtkUpdateType policy );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n se utiliza para indicar la pol<6F>tica de actuaci<63>n. La pol<6F>tica
|
|
|
|
|
por defecto es <tt/GTK_UPDATE_CONTINUOUS/ que significa que el color
|
|
|
|
|
seleccionado se actualiza continuamente cuando el usuario arrastra la barra
|
|
|
|
|
o selecciona con el rat<61>n un color de la rueda de colores. Si tiene problemas
|
|
|
|
|
de rendimiento, puede poner la pol<6F>tica <tt/GTK_UPDATE_DISCONTINUOUS/ o
|
|
|
|
|
<tt/GTK_UPDATE_DELAYED/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
|
|
|
|
|
gint use_opacity );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El <em/widget/ de selecci<63>n de color admite el ajuste de la transparencia
|
|
|
|
|
de un color (tambi<62>n conocido como el canal alfa). Esta opci<63>n est<73>
|
|
|
|
|
desactivada por defecto. Si se llama a esta funci<63>n con <tt/use_opacity/
|
|
|
|
|
como TRUE se activa la transparencia. Si se utiliza <tt/use_opacity/ como
|
|
|
|
|
FALSE se desactiva la transparencia.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_color_selection_set_color( GtkColorSelection *colorsel,
|
|
|
|
|
gdouble *color );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Puede poner el color actual explicitamente haciendo uso de esta funci<63>n con
|
|
|
|
|
un puntero a un vector de colores (de tipo <tt/gdouble/). La longitud del
|
|
|
|
|
vector depende de si est<73> activada la transparencia. La posici<63>n 0 contiene
|
|
|
|
|
la componente roja del color, la 1 contiene la verde, la 2 la azul y la
|
|
|
|
|
transparencia est<73> en la posici<63>n 3 (solamente si est<73> activada la
|
|
|
|
|
transparencia, ver <tt/gtk_color_selection_set_opacity()/). Todos los
|
|
|
|
|
valores se encuentran entre 0.0 y 1.0.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_color_selection_get_color( GtkColorSelection *colorsel,
|
|
|
|
|
gdouble *color );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Cuando necesite preguntar por el color actual, normalmente cuando haya
|
|
|
|
|
recibido una se<73>al <tt/color_changed/, utilice esta funci<63>n. <tt/color/
|
|
|
|
|
es un puntero al vector de colores que se rellenar<61>. Ver la descripci<63>n
|
|
|
|
|
de la funci<63>n <tt/gtk_color_selection_set_color()/ para conocer la
|
|
|
|
|
estructura de este vector.
|
|
|
|
|
|
|
|
|
|
<!-- Need to do a whole section on DnD - TRG
|
|
|
|
|
Drag and drop
|
|
|
|
|
-------------
|
|
|
|
|
|
|
|
|
|
The color sample areas (right under the hue-saturation wheel) supports
|
|
|
|
|
drag and drop. The type of drag and drop is "application/x-color". The
|
|
|
|
|
message data consists of an array of 4 (or 5 if opacity is enabled)
|
|
|
|
|
gdouble values, where the value at position 0 is 0.0 (opacity on) or
|
|
|
|
|
1.0 (opacity off) followed by the red, green and blue values at
|
|
|
|
|
positions 1,2 and 3 respectively. If opacity is enabled, the opacity
|
|
|
|
|
is passed in the value at position 4.
|
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> tenemos un peque<75>o ejemplo que muestra el uso de
|
|
|
|
|
<tt/GtkColorSelectionDialog/. El programa muestra una ventana con una
|
|
|
|
|
zona de dibujo. Pulsando en ella se abre un cuadro de di<64>logo de
|
|
|
|
|
selecci<EFBFBD>n del color, y cambiando el color en el cuadro de di<64>logo se
|
|
|
|
|
cambia el color de fondo de la zona de dibujo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo colorsel colorsel.c */
|
|
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
#include <gdk/gdk.h>
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
GtkWidget *colorseldlg = NULL;
|
|
|
|
|
GtkWidget *drawingarea = NULL;
|
|
|
|
|
|
|
|
|
|
/* Manejador del cambio de color */
|
|
|
|
|
|
|
|
|
|
void color_changed_cb (GtkWidget *widget, GtkColorSelection *colorsel)
|
|
|
|
|
{
|
|
|
|
|
gdouble color[3];
|
|
|
|
|
GdkColor gdk_color;
|
|
|
|
|
GdkColormap *colormap;
|
|
|
|
|
|
|
|
|
|
/* Obtener el mapa de colores de la zona de dibujo */
|
|
|
|
|
|
|
|
|
|
colormap = gdk_window_get_colormap (drawingarea->window);
|
|
|
|
|
|
|
|
|
|
/* Obtener el color actual */
|
|
|
|
|
|
|
|
|
|
gtk_color_selection_get_color (colorsel,color);
|
|
|
|
|
|
|
|
|
|
/* Meterlo en un entero sin signo de 16 bits (0..65535) e insertarlo
|
|
|
|
|
en la estructura GdkColor */
|
|
|
|
|
|
|
|
|
|
gdk_color.red = (guint16)(color[0]*65535.0);
|
|
|
|
|
gdk_color.green = (guint16)(color[1]*65535.0);
|
|
|
|
|
gdk_color.blue = (guint16)(color[2]*65535.0);
|
|
|
|
|
|
|
|
|
|
/* Pedir memoria para el color */
|
|
|
|
|
|
|
|
|
|
gdk_color_alloc (colormap, &gdk_color);
|
|
|
|
|
|
|
|
|
|
/* Poner el color de fondo de la ventana */
|
|
|
|
|
|
|
|
|
|
gdk_window_set_background (drawingarea->window, &gdk_color);
|
|
|
|
|
|
|
|
|
|
/* Limpiar la ventana */
|
|
|
|
|
|
|
|
|
|
gdk_window_clear (drawingarea->window);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Manejador del evento Drawingarea */
|
|
|
|
|
|
|
|
|
|
gint area_event (GtkWidget *widget, GdkEvent *event, gpointer client_data)
|
|
|
|
|
{
|
|
|
|
|
gint handled = FALSE;
|
|
|
|
|
GtkWidget *colorsel;
|
|
|
|
|
|
|
|
|
|
/* Comprobar si hemos recibido un evento de pulsaci<63>n de bot<6F>n */
|
|
|
|
|
|
|
|
|
|
if (event->type == GDK_BUTTON_PRESS && colorseldlg == NULL)
|
|
|
|
|
{
|
|
|
|
|
/* S<>, <20>tenemos un evento y todav<61>a no est<73> el colorseldlg! */
|
|
|
|
|
|
|
|
|
|
handled = TRUE;
|
|
|
|
|
|
|
|
|
|
/* Crear el cuadro de di<64>logo de selecci<63>n del color */
|
|
|
|
|
|
|
|
|
|
colorseldlg = gtk_color_selection_dialog_new("Select background color");
|
|
|
|
|
|
|
|
|
|
/* Obtener el widget GtkColorSelection */
|
|
|
|
|
|
|
|
|
|
colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
|
|
|
|
|
|
|
|
|
|
/* Conectar con la se<73>al <20>color_changed<65>, darle al dato del
|
|
|
|
|
cliente el valor del widget colorsel */
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
|
|
|
|
|
(GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
|
|
|
|
|
|
|
|
|
|
/* Mostrar el cuadro de di<64>logo */
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(colorseldlg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Manipulador de los eventos cerrar y salir */
|
|
|
|
|
|
|
|
|
|
void destroy_window (GtkWidget *widget, gpointer client_data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Principal */
|
|
|
|
|
|
|
|
|
|
gint main (gint argc, gchar *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
|
|
|
|
|
/* Inicializa el toolkit, y elimina las opciones relacionadas con
|
|
|
|
|
gtk incluidas en la l<>nea de <20>rdenes */
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc,&argv);
|
|
|
|
|
|
|
|
|
|
/* Crea la ventana de m<>s alto nivel, le da t<>tulo y la pol<6F>tica */
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW(ventana), "Color selection test");
|
|
|
|
|
gtk_window_set_policy (GTK_WINDOW(ventana), TRUE, TRUE, TRUE);
|
|
|
|
|
|
|
|
|
|
/* Enlaza con los eventos <20>delete<74> y <20>destroy<6F>, para que podamos
|
|
|
|
|
salir */
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(ventana), "delete_event",
|
|
|
|
|
(GtkSignalFunc)destroy_window, (gpointer)ventana);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(ventana), "destroy",
|
|
|
|
|
(GtkSignalFunc)destroy_window, (gpointer)ventana);
|
|
|
|
|
|
|
|
|
|
/* Crea la zona de dibujo, pone el tama<6D>o y caza los eventos de los
|
|
|
|
|
botones */
|
|
|
|
|
|
|
|
|
|
drawingarea = gtk_drawing_area_new ();
|
|
|
|
|
|
|
|
|
|
gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
|
|
|
|
|
|
|
|
|
|
gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(drawingarea), "event",
|
|
|
|
|
(GtkSignalFunc)area_event, (gpointer)drawingarea);
|
|
|
|
|
|
|
|
|
|
/* Add drawingarea to window, then show them both */
|
|
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(ventana), drawingarea);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (drawingarea);
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
/* Entrar en el bucle principal de gtk (nunca sale de aqu<71>) */
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
/* Para satisfacer a los compiladores pijos */
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Selecci<63>n de ficheros
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ de selecci<63>n de ficheros nos proporciona una forma
|
|
|
|
|
r<EFBFBD>pida y sencilla de mostrar un cuadro de di<64>logo para la selecci<63>n de
|
|
|
|
|
un fichero. Ya viene con los botones Aceptar, Cancelar y Ayuda. Una
|
|
|
|
|
magnifica ayuda para acortar el tiempo de programaci<63>n.
|
|
|
|
|
|
|
|
|
|
Para crear un nuevo cuadro de di<64>logo de selecci<63>n de ficheros
|
|
|
|
|
utilice:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_file_selection_new( gchar *title );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para poner el nombre del fichero en el cuadro de di<64>logo, por
|
|
|
|
|
ejemplo para poder utilizar un directorio o un fichero por defecto,
|
|
|
|
|
utilice la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_file_selection_set_filename( GtkFileSelection *filesel,
|
|
|
|
|
gchar *filename );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para obtener el texto que el usuario ha introducido, utilice la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n hay punteros a los <em/widgets/ que contiene el cuadro de
|
|
|
|
|
di<EFBFBD>logo. Son los siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>dir_list
|
|
|
|
|
<item>file_list
|
|
|
|
|
<item>selection_entry
|
|
|
|
|
<item>selection_text
|
|
|
|
|
<item>main_vbox
|
|
|
|
|
<item>ok_button
|
|
|
|
|
<item>cancel_button
|
|
|
|
|
<item>help_button
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Lo m<>s probable es que s<>lo utilice los punteros <tt/ok_button/,
|
|
|
|
|
<tt/cancel_button/, y <tt/help_button/ para controlar cuando se pulsan.
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> inclu<6C>mos un ejemplo robado de <tt/testgtk.c/, modificado
|
|
|
|
|
para que se puede ejecutar independientemente. Como puede ver, no es
|
|
|
|
|
muy complicado crear un <em/widget/ para la selecci<63>n de
|
|
|
|
|
ficheros. Aunque aparezca el bot<6F>n de ayuda en la pantalla, no hace
|
|
|
|
|
nada y no tiene ninguna se<73>al conectada.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo filesel filesel.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* Obtener el nombre del fichero e imprimirlo en la consola */
|
|
|
|
|
void file_ok_sel (GtkWidget *w, GtkFileSelection *fs)
|
|
|
|
|
{
|
|
|
|
|
g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void destroy (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *filew;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* Crear un nuevo widget de selecci<63>n de ficheros */
|
|
|
|
|
filew = gtk_file_selection_new ("File selection");
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (filew), "destroy",
|
|
|
|
|
(GtkSignalFunc) destroy, &filew);
|
|
|
|
|
/* Conectar el ok_button con la funci<63>n file_ok_sel */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
|
|
|
|
|
"clicked", (GtkSignalFunc) file_ok_sel, filew );
|
|
|
|
|
|
|
|
|
|
/* Conectar el cancel_button con la destrucci<63>n del widget */
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filew)->cancel_button),
|
|
|
|
|
"clicked", (GtkSignalFunc) gtk_widget_destroy,
|
|
|
|
|
GTK_OBJECT (filew));
|
|
|
|
|
|
|
|
|
|
/* Damos el nombre del fichero, como si fuese un cuadro de di<64>logo para
|
|
|
|
|
grabar ficheros y estuviesemos dando un nombre por defecto */
|
|
|
|
|
gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew),
|
|
|
|
|
"penguin.png");
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(filew);
|
|
|
|
|
gtk_main ();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> El <em/widget/ contenedor
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> El <em/widget/ EventBox<label id="sec_EventBox">
|
|
|
|
|
<label id="sec_The_EventBox_Widget">
|
|
|
|
|
<p>
|
|
|
|
|
Algunos <em/widget/ gtk no tienen asociada una ventana X, por lo que
|
|
|
|
|
s<EFBFBD>lo pueden dibujar en la de su padre. Debido a esto, no pueden
|
|
|
|
|
recibir ning<6E>n evento y si tienen un tama<6D>o incorrecto, no se
|
|
|
|
|
recortar<EFBFBD>n correctamente por lo que puede que se sobreescriban ciertas
|
|
|
|
|
zonas, etc... Si necesita este tipo de <em/widgets/, el EventBox es
|
|
|
|
|
para usted.
|
|
|
|
|
|
|
|
|
|
Cuando se ve por primera vez, el <em/widget/ EventBox puede parecer
|
|
|
|
|
completamente in<69>til. No dibuja nada en la pantalla y no responde
|
|
|
|
|
a ning<6E>n evento. Sin embargo, tiene una utilidad - proporciona una
|
|
|
|
|
ventana X para su <em/widget/ hijo. Esto es importante ya que
|
|
|
|
|
muchos <em/widgets/ GTK no tienen una ventana X asociada. No tener una
|
|
|
|
|
ventana X ahorra memoria y mejora el rendimiento, pero tiene sus
|
|
|
|
|
desventajas. Un <em/widget/ sin una ventana X no puede recibir
|
|
|
|
|
eventos, y no realizar<61> ning<6E>n recorte en sus contenidos. Aunque el
|
|
|
|
|
nombre <em/EventBox/ enfatiza su funci<63>n de manejador de eventos, el
|
|
|
|
|
<em/widget/ tambi<62>n puede utilizarse para hacer los recortes.
|
|
|
|
|
(Y m<>s... ver el ejemplo m<>s abajo.)
|
|
|
|
|
|
|
|
|
|
Para crear un nuevo <em/widget/ EventBox, utilice:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_event_box_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Un <em/widget/ hijo puede a<>adirse a su EventBox as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_container_add( GTK_CONTAINER(event_box), widget );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El siguiente ejemplo demuestra los dos usos de EventBox - se crea
|
|
|
|
|
una etiqueta que se recorta dentro de una peque<75>a caja, y hace
|
|
|
|
|
que una pulsaci<63>n del rat<61>n en la misma finalice el programa.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo eventbox eventbox.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *event_box;
|
|
|
|
|
GtkWidget *etiqueta;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Event Box");
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_exit), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* Crea un EventBox y lo a<>ade a nuestra ventana superior */
|
|
|
|
|
|
|
|
|
|
event_box = gtk_event_box_new ();
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(ventana), event_box);
|
|
|
|
|
gtk_widget_show (event_box);
|
|
|
|
|
|
|
|
|
|
/* Crea una larga etiqueta */
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (event_box), etiqueta);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
/* La recortamos. */
|
|
|
|
|
gtk_widget_set_usize (etiqueta, 110, 20);
|
|
|
|
|
|
|
|
|
|
/* Y enlazamos una acci<63>n con la etiqueta */
|
|
|
|
|
gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_exit), NULL);
|
|
|
|
|
|
|
|
|
|
/* Otra cosa m<>s que necesita una ventana X ... */
|
|
|
|
|
|
|
|
|
|
gtk_widget_realize (event_box);
|
|
|
|
|
gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* Final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>El <em/widget/ alineamiento <label id="sec_Alignment">
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ alineamiento (<em/alignment/) le permitir<69> colocar un
|
|
|
|
|
<em/widget/ dentro de su ventana utilizando una posici<63>n y un tama<6D>o
|
|
|
|
|
relativos al mismo <em/widget/ de alineamiento. Por ejemplo, puede ser
|
|
|
|
|
muy <20>til para centrar un <em/widget/ en la ventana.
|
|
|
|
|
|
|
|
|
|
S<EFBFBD>lo hay dos funciones asociadas con el <em/widget/ alineamiento:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_alignment_new( gfloat xalign,
|
|
|
|
|
gfloat yalign,
|
|
|
|
|
gfloat xscale,
|
|
|
|
|
gfloat yscale );
|
|
|
|
|
|
|
|
|
|
void gtk_alignment_set( GtkAlignment *alignment,
|
|
|
|
|
gfloat xalign,
|
|
|
|
|
gfloat yalign,
|
|
|
|
|
gfloat xscale,
|
|
|
|
|
gfloat yscale );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La primera funci<63>n crea un nuevo <em/widget/ alineamiento con los
|
|
|
|
|
par<EFBFBD>metros especificados. La segunda funci<63>n permite alterar los
|
|
|
|
|
par<EFBFBD>metros de un <em/widget/ alineamiento ya existente.
|
|
|
|
|
|
|
|
|
|
Los cuatro par<61>metros de alineamiento son n<>meros en coma flotante que
|
|
|
|
|
pueden tener variar entre 0.0 y 1.0. Los argumentos <tt/xalign/ e
|
|
|
|
|
<tt/yalign/ afectan a la posici<63>n del <em/widget/ colocado dentro del
|
|
|
|
|
<em/widget/ de alineamiento. Los argumentos <tt/xscale/ e <tt/yscale/
|
|
|
|
|
afectan a la cantidad de espacio que ocupa el <em/widget/.
|
|
|
|
|
|
|
|
|
|
Se le puede a<>adir un <em/widget/ hijo a un alineamiento utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_container_add( GTK_CONTAINER(alignment), child_widget );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para ver un ejemplo de utilizaci<63>n del <em/widget/ alineamiento,
|
|
|
|
|
dir<EFBFBD>jase al ejemplo del <em/widget/ <ref id="sec_ProgressBar"
|
|
|
|
|
name="Barra de progreso">.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Contenedor fijo
|
|
|
|
|
<p>
|
|
|
|
|
El contenedor fijo le permite situar <em/widgets/ en una posici<63>n fija
|
|
|
|
|
dentro de su ventana, relativa a la esquina superior izquierda. La
|
|
|
|
|
posici<EFBFBD>n de los <em/widgets/ puede cambiarse din<69>micamente.
|
|
|
|
|
|
|
|
|
|
S<EFBFBD>lo hay tres funciones asociadas al <em/widget/ contenedor fijo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_fixed_new( void );
|
|
|
|
|
|
|
|
|
|
void gtk_fixed_put( GtkFixed *fixed,
|
|
|
|
|
GtkWidget *widget,
|
|
|
|
|
gint16 x,
|
|
|
|
|
gint16 y );
|
|
|
|
|
|
|
|
|
|
void gtk_fixed_move( GtkFixed *fixed,
|
|
|
|
|
GtkWidget *widget,
|
|
|
|
|
gint16 x,
|
|
|
|
|
gint16 y );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La funci<63>n <tt/gtk_fixed_new/ permite la creaci<63>n de un nuevo
|
|
|
|
|
contenedor fijo.
|
|
|
|
|
|
|
|
|
|
<tt/gtk_fixed_put/ situa <tt/widget/ dentro del contenedor <tt/fixed/
|
|
|
|
|
en la posici<63>n especificada por <tt/x/ e <tt/y/.
|
|
|
|
|
|
|
|
|
|
<tt/gtk_fixed_move/ permite que mover hacia una nuevo posici<63>n el
|
|
|
|
|
<em/widget/ especificado.
|
|
|
|
|
|
|
|
|
|
El ejemplo siguiente muestra como utilizar el contenedor fijo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo fixed fixed.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* Voy a ser un poco torpe y utilizar algunas variables
|
|
|
|
|
* globales para almacenar la posici<63>n del widget que
|
|
|
|
|
* hay dentro del contenedor */
|
|
|
|
|
gint x=50;
|
|
|
|
|
gint y=50;
|
|
|
|
|
|
|
|
|
|
/* Esta funci<63>n de llamada mueve el bot<6F>n a una nueva
|
|
|
|
|
* posici<63>n dentro del contenedor fijo. */
|
|
|
|
|
void move_button( GtkWidget *widget,
|
|
|
|
|
GtkWidget *fixed )
|
|
|
|
|
{
|
|
|
|
|
x = (x+30)%300;
|
|
|
|
|
y = (y+50)%300;
|
|
|
|
|
gtk_fixed_move( GTK_FIXED(fixed), widget, x, y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main( int argc,
|
|
|
|
|
char *argv[] )
|
|
|
|
|
{
|
|
|
|
|
/* GtkWidget es el tipo de almacenamiento para los widgets */
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *fixed;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
/* Inicializa GTK */
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* Crear una nueva ventana */
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_title(GTK_WINDOW(ventana), "Fixed Container");
|
|
|
|
|
|
|
|
|
|
/* Aqu<71> conectamos el evento "destroy" al manejador de la se<73>al */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
|
|
|
|
|
|
|
|
|
|
/* Establecemos el ancho del borde la ventana */
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* Creamos un contenedor fijo */
|
|
|
|
|
fixed = gtk_fixed_new();
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(ventana), fixed);
|
|
|
|
|
gtk_widget_show(fixed);
|
|
|
|
|
|
|
|
|
|
for (i = 1 ; i <= 3 ; i++) {
|
|
|
|
|
/* Crea un nuevo bot<6F>n con la etiqueta "Press me" */
|
|
|
|
|
boton = gtk_button_new_with_label ("Press me");
|
|
|
|
|
|
|
|
|
|
/* Cuando el bot<6F>n reciba la se<73>al "pulsado", llamar<61> a la funci<63>n
|
|
|
|
|
* move_button() pas<61>ndole el contenedor fijo como argumento. */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (move_button), fixed);
|
|
|
|
|
|
|
|
|
|
/* Esto mete el bot<6F>n dentro de la ventana del window contenedor
|
|
|
|
|
* fijo. */
|
|
|
|
|
gtk_fixed_put (GTK_FIXED (fixed), boton, i*50, i*50);
|
|
|
|
|
|
|
|
|
|
/* El paso final es mostrar el widget recien creado */
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mostrar la ventana */
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
/* Entrar en el bucle principal */
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Contenedor capa
|
|
|
|
|
<p>
|
|
|
|
|
El contenedor capa es similar al contenedor fijo, excepto que permite
|
|
|
|
|
implementar una zona de <em/scroll/ infinita (donde infinito significa
|
|
|
|
|
menor de 2^32). Xwindows tiene una limitaci<63>n en la que las ventanas
|
|
|
|
|
pueden tener un m<>ximo de 32767 <em/pixels/ de alto o de ancho. El
|
|
|
|
|
contenedor capa sortea esta limitaci<63>n con una ex<65>tica combinaci<63>n de
|
|
|
|
|
ventanas y <em/bits/ de gravedad, <!-- Si alguien entiende que
|
|
|
|
|
significa esto: e98cuenc@criens.u-psud.fr --> para que puede tener un
|
|
|
|
|
suave <em/scroll/ a<>n cuando utilice una gran cantidad de <em/widgets/
|
|
|
|
|
hijos dentro de su zona de <em/scroll/.
|
|
|
|
|
|
|
|
|
|
Podr<EFBFBD> crear un contenedor capa utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
|
|
|
|
|
GtkAdjustment *vadjustment );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como puede observar, podr<64> especificar (de forma opcional) los objetos
|
|
|
|
|
de ajuste que utilizar<61> el <em/widget/ capa para hacer su <em/scroll/.
|
|
|
|
|
|
|
|
|
|
Puede a<>adir y mover <em/widgets/ dentro del contenedor capa
|
|
|
|
|
utilizando las dos funciones siguientes:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_layout_put( GtkLayout *layout,
|
|
|
|
|
GtkWidget *widget,
|
|
|
|
|
gint x,
|
|
|
|
|
gint y );
|
|
|
|
|
|
|
|
|
|
void gtk_layout_move( GtkLayout *layout,
|
|
|
|
|
GtkWidget *widget,
|
|
|
|
|
gint x,
|
|
|
|
|
gint y );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El tama<6D>o del contenedor capa se puede establecer utilizando la
|
|
|
|
|
siguiente funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_layout_set_size( GtkLayout *layout,
|
|
|
|
|
guint width,
|
|
|
|
|
guint height );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los contenedores capa son uno de los poqu<71>simos <em/widgets/ dentro de
|
|
|
|
|
GTK que se repintan ellos mismos en la pantalla cuando se cambian
|
|
|
|
|
utilizando las funciones anteriores (la inmensa mayoria de los
|
|
|
|
|
<em/widgets/ mandan una petici<63>n a la cola que ser<65> procesada cuando
|
|
|
|
|
se devuelva el control a la funci<63>n <tt/gtk_main()/).
|
|
|
|
|
|
|
|
|
|
Cuando quiera hacer una gran cantidad de cambios dentro del contenedor
|
|
|
|
|
capa, podr<64> utilizar las dos funciones siguientes para desactivar y
|
|
|
|
|
reactivar la caracter<65>stica de repintado:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_layout_freeze( GtkLayout *layout );
|
|
|
|
|
|
|
|
|
|
void gtk_layout_thaw( GtkLayout *layout );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Las cuatro funciones finales a utilizar con los <em/widgets/capa son
|
|
|
|
|
para la manipulaci<63>n de los <em/widgets/ de ajuste horizontal y
|
|
|
|
|
vertical:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
|
|
|
|
|
|
|
|
|
|
GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
|
|
|
|
|
|
|
|
|
|
void gtk_layout_set_hadjustment( GtkLayout *layout,
|
|
|
|
|
GtkAdjustment *adjustment );
|
|
|
|
|
|
|
|
|
|
void gtk_layout_set_vadjustment( GtkLayout *layout,
|
|
|
|
|
GtkAdjustment *adjustment);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Marcos <label id="sec_Frames">
|
|
|
|
|
<p>
|
|
|
|
|
Los marcos pueden utilizarse para meter uno o un grupo de
|
|
|
|
|
<em/widgets/dentro de una caja puede ser (de forma opcional)
|
|
|
|
|
etiquetada. La posici<63>n de la etiqueta y el estilo de la caja pueden
|
|
|
|
|
modificarse.
|
|
|
|
|
|
|
|
|
|
Se puede crear un marco con la siguiente funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_frame_new( const gchar *etiqueta );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La etiqueta se coloca por defecto en la esquina superior izquierda del
|
|
|
|
|
marco. Si el argumento <tt/etiqueta/ es NULL no se mostrar<61> ninguna
|
|
|
|
|
etiqueta. Puede cambiarse el texto de la etiqueta utilizando la
|
|
|
|
|
funci<EFBFBD>n siguiente.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_frame_set_label( GtkFrame *frame,
|
|
|
|
|
const gchar *etiqueta );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La posici<63>n de la etiqueta se puede cambiar utilizado la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_frame_set_label_align( GtkFrame *frame,
|
|
|
|
|
gfloat xalign,
|
|
|
|
|
gfloat yalign );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/xalign/ e <tt/yalign/ toman valores entre 0.0 y 1.0. <tt/yalign/
|
|
|
|
|
no se actualmente no se utiliza. El valor por defecto de <tt/xalign/
|
|
|
|
|
es 0.0, lo que coloca la etiqueta a la izquierda del marco.
|
|
|
|
|
|
|
|
|
|
La siguiente funci<63>n altera el estilo de la caja que se utiliza para
|
|
|
|
|
se<EFBFBD>alar el marco.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_frame_set_shadow_type( GtkFrame *frame,
|
|
|
|
|
GtkShadowType type);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/type/ puede tomar uno de los valores siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_SHADOW_NONE
|
|
|
|
|
<item> GTK_SHADOW_IN
|
|
|
|
|
<item> GTK_SHADOW_OUT
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_IN (the default)
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_OUT
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
El c<>digo siguiente ilustra la utilizaci<63>n del <em/widget/ marco.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo frame frame.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
int main( int argc,
|
|
|
|
|
char *argv[] )
|
|
|
|
|
{
|
|
|
|
|
/* GtkWidget es el tipo de almacenamiento para los widgets */
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *frame;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
/* Inicializa GTK */
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* Crea una nueva ventana */
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_title(GTK_WINDOW(ventana), "Frame Example");
|
|
|
|
|
|
|
|
|
|
/* Aqu<71> conectamos el evento "destroy"al manejador de se<73>al */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_widget_set_usize(ventana, 300, 300);
|
|
|
|
|
|
|
|
|
|
/* Establecemos el ancho del borde de la ventana */
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* Crea un marco */
|
|
|
|
|
frame = gtk_frame_new(NULL);
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(ventana), frame);
|
|
|
|
|
|
|
|
|
|
/* Establece la etiqueta del marco */
|
|
|
|
|
gtk_frame_set_label( GTK_FRAME(frame), "GTK Frame Widget" );
|
|
|
|
|
|
|
|
|
|
/* Alinea la etiqueta a la derecha del marco */
|
|
|
|
|
gtk_frame_set_label_align( GTK_FRAME(frame), 1.0, 0.0);
|
|
|
|
|
|
|
|
|
|
/* Establece el estilo del marco */
|
|
|
|
|
gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(frame);
|
|
|
|
|
|
|
|
|
|
/* Muestra la ventana */
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
/* Entra dentro del bucle principal */
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Marcos con proporciones fijas
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget aspect frame/ (marco proporcional) es como el <em/widget
|
|
|
|
|
frame/ (marco), excepto que conserva las proporciones (esto es, la
|
|
|
|
|
relaci<EFBFBD>n entre el ancho y el alto) del <em/widget/ hijo, a<>adiendo
|
|
|
|
|
espacio extra en caso de ser necesario. Esto es <20>til, por ejemplo, si
|
|
|
|
|
quiere hacer una vista previa de una gran imagen. El tama<6D>o de la
|
|
|
|
|
vista previa deber<65>a variar cuando el usuario redimensione la ventana,
|
|
|
|
|
pero la proporci<63>n tiene que coincidir con la de la imagen original.
|
|
|
|
|
|
|
|
|
|
Para crear un nuevo marco proporcional utilice:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_aspect_frame_new( const gchar *etiqueta,
|
|
|
|
|
gfloat xalign,
|
|
|
|
|
gfloat yalign,
|
|
|
|
|
gfloat ratio,
|
|
|
|
|
gint obey_child);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/xalign/ e <tt/yalign/ indican la alineaci<63>n exactamente igual que
|
|
|
|
|
con los <em/widgets Alignment/. Si <tt/obey_child/ es TRUE, la
|
|
|
|
|
proporci<EFBFBD>n de un <em/widget/ hijo ser<65> la misma que la proporci<63>n del
|
|
|
|
|
tama<EFBFBD>o ideal que <20>ste pida. En caso contrario, vendr<64> dada por
|
|
|
|
|
<tt/ratio/.
|
|
|
|
|
|
|
|
|
|
Para cambiar las opciones de un marco proporcional ya existente, puede
|
|
|
|
|
utilizar:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
|
|
|
|
|
gfloat xalign,
|
|
|
|
|
gfloat yalign,
|
|
|
|
|
gfloat ratio,
|
|
|
|
|
gint obey_child);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como por ejemplo, el siguiente programa utiliza un marco proporcional
|
|
|
|
|
para mostrar una zona de dibujo cuyas proporciones siempre ser<65> de
|
|
|
|
|
2:1, no importa como el usuario redimensione la ventana.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo aspectframe aspectframe.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *aspect_frame;
|
|
|
|
|
GtkWidget *drawing_area;
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Aspect Frame");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* Crear un aspect_frame y a<>adirlo a nuestra ventana superior */
|
|
|
|
|
|
|
|
|
|
aspect_frame = gtk_aspect_frame_new ("2x1", /* etiqueta */
|
|
|
|
|
0.5, /* centro x */
|
|
|
|
|
0.5, /* centro y */
|
|
|
|
|
2, /* tama<6D>ox/tama<6D>oy = 2 */
|
|
|
|
|
FALSE /* ignorar el aspecto del hijo */);
|
|
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(ventana), aspect_frame);
|
|
|
|
|
gtk_widget_show (aspect_frame);
|
|
|
|
|
|
|
|
|
|
/* A<>adir un widget hijo al marco proporcional */
|
|
|
|
|
|
|
|
|
|
drawing_area = gtk_drawing_area_new ();
|
|
|
|
|
|
|
|
|
|
/* Pediremos una ventana de 200x200, pero el marco proporcional
|
|
|
|
|
* s<>lo no dejar<61> una ventana de 200x100, ya que tenemos una
|
|
|
|
|
* relaci<63>n de 2x1 */
|
|
|
|
|
gtk_widget_set_usize (drawing_area, 200, 200);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
|
|
|
|
|
gtk_widget_show (drawing_area);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
gtk_main ();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
|
|
|
|
|
<sect1> El <em/widget/ ventana dividida (<em/Paned Window/)
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ ventana dividida es <20>til para cuando se quiere dividir
|
|
|
|
|
una zona en dos partes, con un tama<6D>o relativo controlado por el
|
|
|
|
|
usuario. Entre las dos porciones de la ventana se dibuja un separador
|
|
|
|
|
con un botoncito que el usuario puede arrastrar para cambiar el tama<6D>o
|
|
|
|
|
de cada zona. La divisi<73>n puede ser horizontal (HPaned) o vertical
|
|
|
|
|
(VPaned).
|
|
|
|
|
|
|
|
|
|
Para crear una nueva ventana dividida, utilice una de las siguientes
|
|
|
|
|
funciones:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_hpaned_new (void);
|
|
|
|
|
|
|
|
|
|
GtkWidget *gtk_vpaned_new (void);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Despu<EFBFBD>s de crear el <em/widget/ ventana dividida, tiene que a<>adirle
|
|
|
|
|
un <em/widget/ hijo a cada mitad. Para hacerlo, utilice:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_paned_add1 (GtkPaned *paned, GtkWidget *hijo);
|
|
|
|
|
|
|
|
|
|
void gtk_paned_add2 (GtkPaned *paned, GtkWidget *hijo);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/gtk_paned_add1()/ a<>ade el <em/widget/ hijo a la mitad que se
|
|
|
|
|
encuentra en la parte izquierda o superior de la ventana
|
|
|
|
|
dividida. <tt/gtk_paned_add2()/ a<>ade el <em/widget/ a la mitad que
|
|
|
|
|
hay en la parte derecha o inferior de la ventana.
|
|
|
|
|
|
|
|
|
|
Por ejemplo, si queremos crear una parte del interface de usuario de
|
|
|
|
|
un programa de correo-e imaginario. Dividiremos verticalmente una
|
|
|
|
|
ventana en dos partes, teniendo en la parte superior una lista de los
|
|
|
|
|
mensajes de correo-e y en la parte inferior el texto de uno de estos
|
|
|
|
|
mensajes. El programa es bastante f<>cil de entender. Solo un par de
|
|
|
|
|
cosillas: no se puede a<>adir texto en un <em/widget/ de texto (Text)
|
|
|
|
|
si no se ha hecho antes <tt/gtk_widget_realize()/, pero como
|
|
|
|
|
demostraci<EFBFBD>n de una t<>cnica alternativa, para a<>adir el texto
|
|
|
|
|
conectaremos un manipulador a la se<73>al <20>realize<7A>. Y tenemos que
|
|
|
|
|
a<EFBFBD>adir la opci<63>n <tt/GTK_SHRINK/ a algunos de los elementos que hay en
|
|
|
|
|
la tabla con la ventana de texto y sus barras de desplazamiento, as<61>
|
|
|
|
|
cuando la porci<63>n de abajo se haga m<>s peque<75>a, se encoger<65>
|
|
|
|
|
correctamente en lugar de desaparecer por la parte de abajo de la
|
|
|
|
|
ventana.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo paned paned.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* Crear la lista de "messages" */
|
|
|
|
|
GtkWidget *
|
|
|
|
|
create_list (void)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
GtkWidget *scrolled_window;
|
|
|
|
|
GtkWidget *list;
|
|
|
|
|
GtkWidget *list_item;
|
|
|
|
|
|
|
|
|
|
int i;
|
|
|
|
|
char buffer[16];
|
|
|
|
|
|
|
|
|
|
/* Crear una nueva ventana con barras de desplazamiento si hacen
|
|
|
|
|
falta */
|
|
|
|
|
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
|
|
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
|
|
|
|
GTK_POLICY_AUTOMATIC,
|
|
|
|
|
GTK_POLICY_AUTOMATIC);
|
|
|
|
|
|
|
|
|
|
/* Crear una nueva lista y poner en ella la ventana con barras */
|
|
|
|
|
list = gtk_list_new ();
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(scrolled_window), list);
|
|
|
|
|
gtk_widget_show (list);
|
|
|
|
|
|
|
|
|
|
/* A<>adir algunos mensajes a la ventana */
|
|
|
|
|
for (i=0; i<10; i++) {
|
|
|
|
|
|
|
|
|
|
sprintf(buffer,"Message #%d",i);
|
|
|
|
|
list_item = gtk_list_item_new_with_label (buffer);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(list), list_item);
|
|
|
|
|
gtk_widget_show (list_item);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return scrolled_window;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A<>adir alg<6C>n texto a nuestro widget de texto - esta funci<63>n se
|
|
|
|
|
invoca cada vez que se produce una se<73>al realize en la
|
|
|
|
|
ventana. Podemos forzar esta se<73>al mediante gtk_widget_realize, pero
|
|
|
|
|
primero tiene que formar parte de una jerarqu<71>a */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
realize_text (GtkWidget *text, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_text_freeze (GTK_TEXT (text));
|
|
|
|
|
gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
|
|
|
|
|
"From: pathfinder@nasa.gov\n"
|
|
|
|
|
"To: mom@nasa.gov\n"
|
|
|
|
|
"Subject: Made it!\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"We just got in this morning. The weather has been\n"
|
|
|
|
|
"great - clear but cold, and there are lots of fun sights.\n"
|
|
|
|
|
"Sojourner says hi. See you soon.\n"
|
|
|
|
|
" -Path\n", -1);
|
|
|
|
|
|
|
|
|
|
gtk_text_thaw (GTK_TEXT (text));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Creamos una zona con texto que muestra un "message" */
|
|
|
|
|
GtkWidget *
|
|
|
|
|
create_text (void)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *table;
|
|
|
|
|
GtkWidget *text;
|
|
|
|
|
GtkWidget *hscrollbar;
|
|
|
|
|
GtkWidget *vscrollbar;
|
|
|
|
|
|
|
|
|
|
/* Crea una tabla para contener el widget de texto y las barras de
|
|
|
|
|
desplazamiento */
|
|
|
|
|
table = gtk_table_new (2, 2, FALSE);
|
|
|
|
|
|
|
|
|
|
/* Pone un widget de texto en la esquina superior izquierda.
|
|
|
|
|
Observe la utilizaci<63>n de GTK_SHRINK en la direcci<63>n y */
|
|
|
|
|
text = gtk_text_new (NULL, NULL);
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
|
|
|
|
|
GTK_FILL | GTK_EXPAND,
|
|
|
|
|
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
|
|
|
|
|
gtk_widget_show (text);
|
|
|
|
|
|
|
|
|
|
/* Pone una HScrollbar en la esquina inferior izquierda */
|
|
|
|
|
hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
|
|
|
|
|
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
|
|
|
|
|
gtk_widget_show (hscrollbar);
|
|
|
|
|
|
|
|
|
|
/* Y una VScrollbar en la esquina superior derecha */
|
|
|
|
|
vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
|
|
|
|
|
GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
|
|
|
|
|
gtk_widget_show (vscrollbar);
|
|
|
|
|
|
|
|
|
|
/* Y un manejador para poner un mensaje en el widget de texto
|
|
|
|
|
cuando reciba realize */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (text), "realize",
|
|
|
|
|
GTK_SIGNAL_FUNC (realize_text), NULL);
|
|
|
|
|
|
|
|
|
|
return table;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *vpaned;
|
|
|
|
|
GtkWidget *list;
|
|
|
|
|
GtkWidget *text;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Paned Windows");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* crea un widget vpaned y lo a<>ade a nuestra ventana superior */
|
|
|
|
|
|
|
|
|
|
vpaned = gtk_vpaned_new ();
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(ventana), vpaned);
|
|
|
|
|
gtk_widget_show (vpaned);
|
|
|
|
|
|
|
|
|
|
/* Ahora crea los contenidos de las dos mitades de la ventana */
|
|
|
|
|
|
|
|
|
|
list = create_list ();
|
|
|
|
|
gtk_paned_add1 (GTK_PANED(vpaned), list);
|
|
|
|
|
gtk_widget_show (list);
|
|
|
|
|
|
|
|
|
|
text = create_text ();
|
|
|
|
|
gtk_paned_add2 (GTK_PANED(vpaned), text);
|
|
|
|
|
gtk_widget_show (text);
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
gtk_main ();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- XXX -->
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> <em/Viewports/ <label id="sec_Viewports">
|
|
|
|
|
<p>
|
|
|
|
|
Probablemente nunca le llegue a hacer falta utilizar el <em/widget/
|
|
|
|
|
Viewport directamente. Ser<65> mucho m<>s probable que tenga que utilizar
|
|
|
|
|
el <em/widget/ <ref id="sec_ScrolledWindows" name="Ventanas con barras
|
|
|
|
|
de desplazamiento"> que a su vez hace uso de <em/viewport/.
|
|
|
|
|
|
|
|
|
|
Un <em/widget viewport/ le permite meter dentro un gran <em/widget/,
|
|
|
|
|
de forma que s<>lo ver<65> una parte del mismo. Utiliza
|
|
|
|
|
<ref id="sec_Adjustment" name="ajustes"> para definir la zona que se
|
|
|
|
|
est<EFBFBD> viendo actualmente.
|
|
|
|
|
|
|
|
|
|
Para crear un <em/viewport/ hay que utilizar la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
|
|
|
|
|
GtkAdjustment *vadjustment );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como puede observar, se pueden especificar los ajustes horizontal y
|
|
|
|
|
vertical que el <em/widget/ va a utilizar en el mismo momento de su
|
|
|
|
|
creaci<EFBFBD>n. El <em/widget/ crear<61> sus propios ajustes en caso de que
|
|
|
|
|
reciba como argumento un valor NULL.
|
|
|
|
|
|
|
|
|
|
Puede obtener y establecer los ajustes despu<70>s de que se haya
|
|
|
|
|
creado el <em/widget/ utilizado las cuatro funciones siguientes:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );
|
|
|
|
|
|
|
|
|
|
GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );
|
|
|
|
|
|
|
|
|
|
void gtk_viewport_set_hadjustment( GtkViewport *viewport,
|
|
|
|
|
GtkAdjustment *adjustment );
|
|
|
|
|
|
|
|
|
|
void gtk_viewport_set_vadjustment( GtkViewport *viewport,
|
|
|
|
|
GtkAdjustment *adjustment );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La <20>nica funci<63>n relativa al <em/viewport/ que queda que altera su
|
|
|
|
|
apariencia es:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_viewport_set_shadow_type( GtkViewport *viewport,
|
|
|
|
|
GtkShadowType type );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los valores posibles para el argumento <tt/type/ son:
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_SHADOW_NONE,
|
|
|
|
|
<item> GTK_SHADOW_IN,
|
|
|
|
|
<item> GTK_SHADOW_OUT,
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_IN,
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_OUT
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Ventanas con barras de desplazamiento <label id="sec_ScrolledWindows">
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
Las ventanas con barras de desplazamiento se utilizan para crear una zona
|
|
|
|
|
con barras de desplazamiento dentro de una ventana real. Puede insertar
|
|
|
|
|
cualquier tipo de <em/widget/ en una ventana con barras de
|
|
|
|
|
desplazamiento, y podr<64> utilizarlo sin importar su tama<6D>o gracias a
|
|
|
|
|
las barras de desplazamiento.
|
|
|
|
|
|
|
|
|
|
La funci<63>n siguiente se utiliza para crear una nueva ventana con
|
|
|
|
|
barras de desplazamiento.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
|
|
|
|
|
GtkAdjustment *vadjustment );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Donde el primer argumento es el ajuste para la direcci<63>n horizontal, y
|
|
|
|
|
el segundo es el ajuste para la direcci<63>n vertical. Casi siempre valen
|
|
|
|
|
NULL.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
|
|
|
|
|
GtkPolicyType hscrollbar_policy,
|
|
|
|
|
GtkPolicyType vscrollbar_policy );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n establece la pol<6F>tica que se utilizar<61> con respecto a las
|
|
|
|
|
barras de desplazamiento. El primer argumento es la ventana con barras
|
|
|
|
|
de desplazamiento sobre la que queremos actuar. El segundo establece
|
|
|
|
|
la pol<6F>tica para la barra de desplazamiento horizontal, y el tercero
|
|
|
|
|
la pol<6F>tica para la barra de desplazamiento vertical.
|
|
|
|
|
|
|
|
|
|
La pol<6F>tica puede ser GTK_POLICY_AUTOMATIC, o
|
|
|
|
|
GTK_POLICY_ALWAYS. GTK_POLICY_AUTOMATIC decidir<69> autom<6F>ticamente si
|
|
|
|
|
necesita barras de desplazamiento, mientras que GTK_POLICY_ALWAYS pondr<64>
|
|
|
|
|
siempre las barras de desplazamiento.
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> tenemos un ejemplo sencillo que empaqueta 100 botones de
|
|
|
|
|
selecci<EFBFBD>n en una ventana con barras de desplazamiento. Solamente he
|
|
|
|
|
comentado las partes que deber<65>a ser nuevas para usted.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo scrolledwin scrolledwin.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
void destroy(GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
static GtkWidget *ventana;
|
|
|
|
|
GtkWidget *scrolled_window;
|
|
|
|
|
GtkWidget *table;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
char buffer[32];
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* Crea un nuevo cuadro de di<64>logo para que la ventana con barras de
|
|
|
|
|
* desplazamiento se meta dentro. Un cuadro de di<64>logo es como una
|
|
|
|
|
* ventana normal excepto que tiene dentro una vbox y un separador
|
|
|
|
|
* horizontal. Es s<>lo un atajo para crear cuadros de di<64>logo */
|
|
|
|
|
ventana = gtk_dialog_new ();
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
(GtkSignalFunc) destroy, NULL);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "dialog");
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 0);
|
|
|
|
|
gtk_widget_set_usize(ventana, 300, 300);
|
|
|
|
|
|
|
|
|
|
/* crea una nueva ventana con barras de desplazamiento. */
|
|
|
|
|
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
|
|
|
|
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
|
|
|
|
|
|
|
|
|
|
/* la pol<6F>tica es GTK_POLICY_AUTOMATIC, o GTK_POLICY_ALWAYS.
|
|
|
|
|
* GTK_POLICY_AUTOMATIC decidir<69> autom<6F>ticamente si necesita
|
|
|
|
|
* barras de desplazamiento, mientras que GTK_POLICY_ALWAYS pondr<64>
|
|
|
|
|
* siempre las barras de desplazamiento. El primer argumento se
|
|
|
|
|
* refiere a la barra horizontal, el segundo a la vertical. */
|
|
|
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
|
|
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
|
|
|
|
|
/* El cuadro de di<64>logo se crea con una vbox dentro de <20>l. */
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG(ventana)->vbox), scrolled_window,
|
|
|
|
|
TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (scrolled_window);
|
|
|
|
|
|
|
|
|
|
/* crea una tabla de 10 por 10 casillas. */
|
|
|
|
|
table = gtk_table_new (10, 10, FALSE);
|
|
|
|
|
|
|
|
|
|
/* pone el espacio en x y en y a 10 */
|
|
|
|
|
gtk_table_set_row_spacings (GTK_TABLE (table), 10);
|
|
|
|
|
gtk_table_set_col_spacings (GTK_TABLE (table), 10);
|
|
|
|
|
|
|
|
|
|
/* empaqueta la tabla en la ventana con barras de desplazamiento */
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (scrolled_window), table);
|
|
|
|
|
gtk_widget_show (table);
|
|
|
|
|
|
|
|
|
|
/* crea una rejilla de botones de selecci<63>n en la tabla para
|
|
|
|
|
* demostrar la ventana con barras de desplazamiento. */
|
|
|
|
|
for (i = 0; i < 10; i++)
|
|
|
|
|
for (j = 0; j < 10; j++) {
|
|
|
|
|
sprintf (buffer, "bot<6F>n (%d,%d)\n", i, j);
|
|
|
|
|
boton = gtk_toggle_button_new_with_label (buffer);
|
|
|
|
|
gtk_table_attach_defaults (GTK_TABLE (table), boton,
|
|
|
|
|
i, i+1, j, j+1);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A<>ade un bot<6F>n "close" en la parte de abajo del cuadro de
|
|
|
|
|
* di<64>logo */
|
|
|
|
|
boton = gtk_button_new_with_label ("close");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
(GtkSignalFunc) gtk_widget_destroy,
|
|
|
|
|
GTK_OBJECT (ventana));
|
|
|
|
|
|
|
|
|
|
/* hace que el bot<6F>n puede ser elegido por defecto. */
|
|
|
|
|
|
|
|
|
|
GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (ventana)->action_area), boton, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
/* Hace que el bot<6F>n sea el elegido por defecto. Con pulsar la
|
|
|
|
|
* tecla "Enter" se activar<61> este bot<6F>n. */
|
|
|
|
|
gtk_widget_grab_default (boton);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Juegue un poco redimensionando la ventana. Vea como actuan las barras
|
|
|
|
|
de desplazamiento. Tambi<62>n puede utilizar la funci<63>n
|
|
|
|
|
<tt/gtk_widget_set_usize()/ para poner el tama<6D>o por defecto de la
|
|
|
|
|
ventana o de cualquier otro <em/widget/.
|
|
|
|
|
|
|
|
|
|
<!-- XXX -->
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Cajas de botones
|
|
|
|
|
<p>
|
|
|
|
|
Las cajas de botones son <20>tiles para crear grupos de botones. Hay
|
|
|
|
|
cajas horizontales y verticales. Puede crear una nueva caja de botones
|
|
|
|
|
utilizando alguna de las funciones siguientes, que crean
|
|
|
|
|
respectivamente una caja horizontal y otra vertical:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_hbutton_box_new( void );
|
|
|
|
|
|
|
|
|
|
GtkWidget *gtk_vbutton_box_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los <20>nicos atributos pertenecientes a las cajas de botones son los
|
|
|
|
|
que definen como se distribuyen los botones. Puede cambiar el
|
|
|
|
|
espaciado que hay entre los botones con:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_hbutton_box_set_spacing_default( gint spacing );
|
|
|
|
|
|
|
|
|
|
void gtk_vbutton_box_set_spacing_default( gint spacing );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Igualmente, se pueden obtener los actuales valores para el espaciado
|
|
|
|
|
utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_hbutton_box_get_spacing_default( void );
|
|
|
|
|
|
|
|
|
|
gint gtk_vbutton_box_get_spacing_default( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El segundo atributo al que podemos acceder afecta al esquema de los
|
|
|
|
|
botones dentro de la caja. Se establece utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_hbutton_box_set_layout_default( GtkButtonBoxStyle layout );
|
|
|
|
|
|
|
|
|
|
void gtk_vbutton_box_set_layout_default( GtkButtonBoxStyle layout );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/layout/ puede tomar uno de los siguientes valores:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_BUTTONBOX_DEFAULT_STYLE
|
|
|
|
|
<item> GTK_BUTTONBOX_SPREAD
|
|
|
|
|
<item> GTK_BUTTONBOX_EDGE
|
|
|
|
|
<item> GTK_BUTTONBOX_START
|
|
|
|
|
<item> GTK_BUTTONBOX_END
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Puede obtenerse el esquema actual utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkButtonBoxStyle gtk_hbutton_box_get_layout_default( void );
|
|
|
|
|
|
|
|
|
|
GtkButtonBoxStyle gtk_vbutton_box_get_layout_default( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Podemos a<>adir botones a una caja de botones utilizando (como
|
|
|
|
|
siempre) la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_container_add( GTK_CONTAINER(button_box), child_widget );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> hay un ejemplo que ilustra todos los diferentes esquemas que
|
|
|
|
|
podemos utilizar con las cajas de botones.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo buttonbox buttonbox.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* Crear una Caja de Botones con los par<61>metros
|
|
|
|
|
* especificados */
|
|
|
|
|
GtkWidget *create_bbox (gint horizontal,
|
|
|
|
|
char* title,
|
|
|
|
|
gint spacing,
|
|
|
|
|
gint child_w,
|
|
|
|
|
gint child_h,
|
|
|
|
|
gint layout)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *frame;
|
|
|
|
|
GtkWidget *bbox;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new (title);
|
|
|
|
|
|
|
|
|
|
if (horizontal)
|
|
|
|
|
bbox = gtk_hbutton_box_new ();
|
|
|
|
|
else
|
|
|
|
|
bbox = gtk_vbutton_box_new ();
|
|
|
|
|
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), bbox);
|
|
|
|
|
|
|
|
|
|
/* Establece la apariencia de la Caja de Botones */
|
|
|
|
|
gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
|
|
|
|
|
gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing);
|
|
|
|
|
gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("OK");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (bbox), boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("Cancel");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (bbox), boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("Help");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (bbox), boton);
|
|
|
|
|
|
|
|
|
|
return(frame);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main( int argc,
|
|
|
|
|
char *argv[] )
|
|
|
|
|
{
|
|
|
|
|
static GtkWidget* ventana = NULL;
|
|
|
|
|
GtkWidget *main_vbox;
|
|
|
|
|
GtkWidget *vbox;
|
|
|
|
|
GtkWidget *hbox;
|
|
|
|
|
GtkWidget *frame_horz;
|
|
|
|
|
GtkWidget *frame_vert;
|
|
|
|
|
|
|
|
|
|
/* Inicializa GTK */
|
|
|
|
|
gtk_init( &argc, &argv );
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Button Boxes");
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC(gtk_main_quit),
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
main_vbox = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), main_vbox);
|
|
|
|
|
|
|
|
|
|
frame_horz = gtk_frame_new ("Horizontal Button Boxes");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
|
|
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox),
|
|
|
|
|
create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
|
|
|
|
|
TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox),
|
|
|
|
|
create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
|
|
|
|
|
TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox),
|
|
|
|
|
create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
|
|
|
|
|
TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox),
|
|
|
|
|
create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
|
|
|
|
|
TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
frame_vert = gtk_frame_new ("Vertical Button Boxes");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
|
|
|
|
|
|
|
|
|
|
hbox = gtk_hbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox),
|
|
|
|
|
create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
|
|
|
|
|
TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox),
|
|
|
|
|
create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
|
|
|
|
|
TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox),
|
|
|
|
|
create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
|
|
|
|
|
TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox),
|
|
|
|
|
create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
|
|
|
|
|
TRUE, TRUE, 5);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show_all (ventana);
|
|
|
|
|
|
|
|
|
|
/* Entra dentro del bucle de eventos */
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Barras de herramientas
|
|
|
|
|
<p>
|
|
|
|
|
Las barras de herramientas acostumbran a agrupar un conjunto de
|
|
|
|
|
<em>widgets</em> para hacer m<>s sencilla la personalizaci<63>n
|
|
|
|
|
de su aspecto y composici<63>n. T<>picamente una barra de herramientas
|
|
|
|
|
consiste en botones con iconos, etiquetas y <em/tips/ para los iconos
|
|
|
|
|
(peque<75>o texto descriptivo que aparece cuando se mantiene el rat<61>n
|
|
|
|
|
sobre el icono), pero en realidad en una barra se puede poner
|
|
|
|
|
cualquier tipo de <em>widget</em>. Finalmente, los elementos se pueden
|
|
|
|
|
disponer de forma horizontal o vertical, y los botones pueden mostrar
|
|
|
|
|
iconos, etiquetas o ambos.
|
|
|
|
|
|
|
|
|
|
La creaci<63>n de una barra de herramientas se hace (como puede que ya
|
|
|
|
|
haya sospechado) mediante la funci<63>n siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
|
|
|
|
|
GtkToolbarStyle style );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
donde <tt/orientation/ puede ser:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GTK_ORIENTATION_HORIZONTAL
|
|
|
|
|
GTK_ORIENTATION_VERTICAL
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
y <tt/style/:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GTK_TOOLBAR_TEXT
|
|
|
|
|
GTK_TOOLBAR_ICONS
|
|
|
|
|
GTK_TOOLBAR_BOTH
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La variable <tt/style/ se aplica a todos los botones que se crean con las
|
|
|
|
|
funciones `item' (pero no a los botones insertados en la barra de
|
|
|
|
|
herramientas como <em>widgets</em> separados).
|
|
|
|
|
|
|
|
|
|
Despu<EFBFBD>s de crear una barra de herramientas, se pueden a<>adir,
|
|
|
|
|
prea<EFBFBD>adir e insertar elementos (o sea, botones) en la misma. Los
|
|
|
|
|
campos que describen un elemento son el texto de la etiqueta, el texto
|
|
|
|
|
del <em/tip/, un texto para el <em/tip/ privado, un icono para el
|
|
|
|
|
bot<EFBFBD>n y una funci<63>n de llamada para el mismo. Por ejemplo, para a<>adir
|
|
|
|
|
un elemento puede utilizar la siguiente funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_toolbar_append_item( GtkToolbar *toolbar,
|
|
|
|
|
const char *text,
|
|
|
|
|
const char *tooltip_text,
|
|
|
|
|
const char *tooltip_private_text,
|
|
|
|
|
GtkWidget *icon,
|
|
|
|
|
GtkSignalFunc callback,
|
|
|
|
|
gpointer user_data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Si quiere utilizar <tt/gtk_toolbar_insert_item/, el <20>nico par<61>metro
|
|
|
|
|
adicional que deber<65>a especificar es la posici<63>n en la que quiere que
|
|
|
|
|
se introduzca el elemento.
|
|
|
|
|
|
|
|
|
|
Para a<>adir un espacio en blanco entre los elementos de la barra de
|
|
|
|
|
herramientas, puede utilizar la funci<63>n siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_toolbar_append_space( GtkToolbar *toolbar );
|
|
|
|
|
|
|
|
|
|
void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
|
|
|
|
|
|
|
|
|
|
void gtk_toolbar_insert_space( GtkToolbar *toolbar,
|
|
|
|
|
gint posicion );
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Y el tama<6D>o del espacio en blanco puede establecerse globalmente
|
|
|
|
|
para toda una barra de herramientas con la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
|
|
|
|
|
gint space_size) ;
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Si tiene que establecer la orientaci<63>n de una barra de herramientas y
|
|
|
|
|
su estilo, puede hacerlo `al vuelo' con las funciones siguientes:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_toolbar_set_orientation( GtkToolbar *toolbar,
|
|
|
|
|
GtkOrientation orientation );
|
|
|
|
|
|
|
|
|
|
void gtk_toolbar_set_style( GtkToolbar *toolbar,
|
|
|
|
|
GtkToolbarStyle style );
|
|
|
|
|
|
|
|
|
|
void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
|
|
|
|
|
gint enable );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para mostrar algunas otras cosas que pueden hacerse con una barra de
|
|
|
|
|
herramientas, vamos a ver el siguiente programa (interrumpiremos el
|
|
|
|
|
listado con alguna explicaci<63>n adicional):
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
#include "gtk.xpm"
|
|
|
|
|
|
|
|
|
|
/* Esta funci<63>n est<73> conectada al bot<6F>n Close o a la acci<63>n de cerrar
|
|
|
|
|
* la ventana desde el WM */
|
|
|
|
|
void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Este principio ya deber<65>a de sonarle familiar, a no ser que <20>ste sea
|
|
|
|
|
su primer programa GTK. En nuestro programa no habr<62> ninguna novedad,
|
|
|
|
|
salvo un bonito dibujo XPM que utilizaremos como icono para todos los
|
|
|
|
|
botones.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* close_button; // este bot<6F>n emitir<69> la se<73>al de cerrar el programa
|
|
|
|
|
GtkWidget* tooltips_button; // para activar/desactivar los tooltips
|
|
|
|
|
GtkWidget* text_button,
|
|
|
|
|
* icon_button,
|
|
|
|
|
* both_button; // botones circulares para el estilo de la barra
|
|
|
|
|
GtkWidget* entry; // un widget para meter texto para mostrar como
|
|
|
|
|
// empaquetar widgets en la barra de herramientas
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
En realidad no necesitamos todos los <em>widgets</em> que acabo de
|
|
|
|
|
poner, pero para aclarar las cosas un poco m<>s los he puesto todos.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* Esto es f<>cil... cuando uno de los botones cambia, s<>lo
|
|
|
|
|
* tenemos que comprobar quien est<73> activo y hacer que el estilo
|
|
|
|
|
* de la barra de herramientas est<73> acorde con la elecci<63>n
|
|
|
|
|
* ATENCI<43>N: <20>nuestra barra de herramientas es data !
|
|
|
|
|
void radio_event (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
if (GTK_TOGGLE_BUTTON (text_button)->active)
|
|
|
|
|
gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
|
|
|
|
|
else if (GTK_TOGGLE_BUTTON (icon_button)->active)
|
|
|
|
|
gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
|
|
|
|
|
else if (GTK_TOGGLE_BUTTON (both_button)->active)
|
|
|
|
|
gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* todav<61>a m<>s f<>cil, s<>lo hay que comprobar el bot<6F>n de selecci<63>n
|
|
|
|
|
* y activar/desactivar los tooltips */
|
|
|
|
|
void toggle_event (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
|
|
|
|
|
GTK_TOGGLE_BUTTON (widget)->active );
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Lo de arriba son s<>lo dos funciones de llamada que se invocar<61>n cuando
|
|
|
|
|
se presione uno de los botones de la barra de herramientas. Todo esto
|
|
|
|
|
ya deber<65>a resultarle familiar si ha utilizado alguna vez los botones
|
|
|
|
|
de selecci<63>n (o los botones circulares)
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
/* Aqu<71> est<73> nuestra ventana principal (un cuadro de di<64>logo) y una
|
|
|
|
|
* caja flotante */
|
|
|
|
|
GtkWidget* dialog;
|
|
|
|
|
GtkWidget* handlebox;
|
|
|
|
|
|
|
|
|
|
/* De acuerdo, necesitamos una barra de herramientas, un icono con
|
|
|
|
|
* una m<>scara (una para todos los botones) y un widget icono donde
|
|
|
|
|
* meter el icono (crearemos un widget diferente para cada bot<6F>n) */
|
|
|
|
|
GtkWidget * toolbar;
|
|
|
|
|
GdkPixmap * icon;
|
|
|
|
|
GdkBitmap * mask;
|
|
|
|
|
GtkWidget * iconw;
|
|
|
|
|
|
|
|
|
|
/* a esta funci<63>n se le llama en todas las aplicaci<63>n GTK */
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* crear una ventana nueva con un t<>tulo y el tama<6D>o adecuado */
|
|
|
|
|
dialog = gtk_dialog_new ();
|
|
|
|
|
gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
|
|
|
|
|
gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
|
|
|
|
|
GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;
|
|
|
|
|
|
|
|
|
|
/* salimos si alguien intenta cerrarnos */
|
|
|
|
|
gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC ( delete_event ), NULL);
|
|
|
|
|
|
|
|
|
|
/* tenemos que mandar la se<73>alo realize porque utilizamos pixmaps
|
|
|
|
|
* para los elementos que hay en la barra de herramientas */
|
|
|
|
|
gtk_widget_realize ( dialog );
|
|
|
|
|
|
|
|
|
|
/* para hacerlo m<>s bonito ponemos la barra de herramientas en la
|
|
|
|
|
* caja flotante, para que as<61> se pueda desatar de la ventana
|
|
|
|
|
* principal */
|
|
|
|
|
handlebox = gtk_handle_box_new ();
|
|
|
|
|
gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
|
|
|
|
|
handlebox, FALSE, FALSE, 5 );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Lo de arriba deber<65>a ser parecido en cualquier aplicaci<63>n GTK. S<>lo
|
|
|
|
|
est<EFBFBD> la inicializaci<63>n de GTK, la creaci<63>n de la ventana, etc...
|
|
|
|
|
Solamente hay una cosa que probablemente necesite una explicaci<63>n:
|
|
|
|
|
una barra de herramientas flotante. Una barra de herramientas flotante
|
|
|
|
|
s<EFBFBD>lo es otra barra donde pueden empaquetarse <em>widgets</em>. La
|
|
|
|
|
diferencia que tiene con una barra t<>pica es que puede desatarse de la
|
|
|
|
|
ventana padre (o, de hecho, la barra de herramientas flotante permanece
|
|
|
|
|
en el padre, pero reducida a un rect<63>ngulo muy peque<75>o, mientras que
|
|
|
|
|
todos sus contenidos se pasan a una nueva ventana flotante). Es bonito
|
|
|
|
|
tener una barra de herramientas flotante, por lo que estos dos
|
|
|
|
|
<em>widgets</em> suelen aparecer juntos.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* la barra de herramientas ser<65> horizontal, con iconos y texto, y
|
|
|
|
|
* con un espacio de 5pxl entre elementos y finalmente, la ponemos en
|
|
|
|
|
* nuestra caja flotante */
|
|
|
|
|
toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
|
|
|
|
|
GTK_TOOLBAR_BOTH );
|
|
|
|
|
gtk_container_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
|
|
|
|
|
gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
|
|
|
|
|
gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );
|
|
|
|
|
|
|
|
|
|
/* ahora creamos el icono con la m<>scara: utilizaremos el widget
|
|
|
|
|
* icon con todos los elementos de la barra de herramientas */
|
|
|
|
|
icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &mask,
|
|
|
|
|
&dialog->style->white, gtk_xpm );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Bien, lo que acabamos de escribir es la inicializaci<63>n del
|
|
|
|
|
<em>widget</em> de la barra de herramientas y la creaci<63>n de un
|
|
|
|
|
<em>pixmap</em> GDK con su m<>scara. Si quiere saber algo m<>s sobre la
|
|
|
|
|
utilizaci<EFBFBD>n de <em>pixmaps</em>, vea la documentaci<63>n de GDK o la
|
|
|
|
|
secci<EFBFBD>n <ref id="sec_Pixmaps" name="Pixmaps"> en este tutorial.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* nuestro primer elemento es el bot<6F>n <close> */
|
|
|
|
|
iconw = gtk_pixmap_new ( icon, mask ); // icon widget
|
|
|
|
|
close_button =
|
|
|
|
|
gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), // nuestra barra
|
|
|
|
|
"Close", // etiqueta del bot<6F>n
|
|
|
|
|
"Closes this app", // tooltip para el bot<6F>n
|
|
|
|
|
"Private", // cadena privada del tooltip
|
|
|
|
|
iconw, // widget del icono
|
|
|
|
|
GTK_SIGNAL_FUNC (delete_event), // una se<73>al
|
|
|
|
|
NULL );
|
|
|
|
|
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); // espacio despu<70>s del elemento
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
En el trozo de c<>digo de arriba puede ver como se hace la acci<63>n m<>s
|
|
|
|
|
simple: a<>adir un bot<6F>n a la barra de herramientas. Justo antes de
|
|
|
|
|
a<EFBFBD>adir un nuevo elemento, tenemos que construir un <em>widget
|
|
|
|
|
pixmap</em> para que sirva como icono para este elemento; este paso
|
|
|
|
|
tendr<EFBFBD> que repetirse para cada nuevo elemento. Despu<70>s del elemento
|
|
|
|
|
a<EFBFBD>adiremos un espacio en blanco en la barra de herramientas, para que
|
|
|
|
|
los elementos que a<>adamos a continuaci<63>n no se toquen los unos a los
|
|
|
|
|
otros. Como puede ver, <tt/gtk_toolbar_append_item/ devuelve un
|
|
|
|
|
puntero al <em>widget</em> de nuestro nuevo bot<6F>n recien creado, por
|
|
|
|
|
lo que podremos trabajar con <20>l como siempre.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* ahora, vamos a hacer nuestro grupo de botones circulares... */
|
|
|
|
|
iconw = gtk_pixmap_new ( icon, mask );
|
|
|
|
|
icon_button =
|
|
|
|
|
gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
|
|
|
|
|
GTK_TOOLBAR_CHILD_RADIOBUTTON, // un tipo de elemento
|
|
|
|
|
NULL, // puntero al widget
|
|
|
|
|
"Icon", // etiqueta
|
|
|
|
|
"Only icons in toolbar", // tooltip
|
|
|
|
|
"Private", // cadena privada del tooltip
|
|
|
|
|
iconw, // icono
|
|
|
|
|
GTK_SIGNAL_FUNC (radio_event), // se<73>al
|
|
|
|
|
toolbar); // dato para la se<73>al
|
|
|
|
|
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> empezamos creando un grupo de botones circulares. Para hacerlo
|
|
|
|
|
hemos utilizado <tt/gtk_toolbar_append_element/. De hecho, utilizando
|
|
|
|
|
esta funci<63>n se pueden a<>adir tanto elementos simples como espacios en
|
|
|
|
|
blanco (tipo = GTK_TOOLBAR_CHILD_SPACE o GTK_TOOLBAR_CHILD_BUTTON). En
|
|
|
|
|
el caso de arriba, hemos empezado creando un grupo de botones circulares.
|
|
|
|
|
Para crear m<>s botones circulares para este grupo
|
|
|
|
|
necesitaremos un puntero al bot<6F>n anterior del grupo, mediante el que
|
|
|
|
|
podremos construir f<>cilmente una lista de botones (ver la secci<63>n
|
|
|
|
|
<ref id="sec_Radio_Buttons" name="Botones circulares"> que se encuentra
|
|
|
|
|
m<EFBFBD>s adelante en este tutorial).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* los botones circulares que vienen a continuaci<63>n est<73>n
|
|
|
|
|
relacionados con los anteriores */
|
|
|
|
|
iconw = gtk_pixmap_new ( icon, mask );
|
|
|
|
|
text_button =
|
|
|
|
|
gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
|
|
|
|
|
GTK_TOOLBAR_CHILD_RADIOBUTTON,
|
|
|
|
|
icon_button,
|
|
|
|
|
"Text",
|
|
|
|
|
"Only texts in toolbar",
|
|
|
|
|
"Private",
|
|
|
|
|
iconw,
|
|
|
|
|
GTK_SIGNAL_FUNC (radio_event),
|
|
|
|
|
toolbar);
|
|
|
|
|
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
|
|
|
|
|
|
|
|
|
|
iconw = gtk_pixmap_new ( icon, mask );
|
|
|
|
|
both_button =
|
|
|
|
|
gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
|
|
|
|
|
GTK_TOOLBAR_CHILD_RADIOBUTTON,
|
|
|
|
|
text_button,
|
|
|
|
|
"Both",
|
|
|
|
|
"Icons and text in toolbar",
|
|
|
|
|
"Private",
|
|
|
|
|
iconw,
|
|
|
|
|
GTK_SIGNAL_FUNC (radio_event),
|
|
|
|
|
toolbar);
|
|
|
|
|
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
|
|
|
|
|
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(both_button),TRUE);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Al final hemos activado manualmente uno de los botones (en caso
|
|
|
|
|
contrario los botones permanecer<65>an todos en estado activo,
|
|
|
|
|
impidi<EFBFBD>ndonos poder cambiar de uno a otro).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* aqu<71> tenemos un sencillo bot<6F>n de selecci<63>n */
|
|
|
|
|
iconw = gtk_pixmap_new ( icon, mask );
|
|
|
|
|
tooltips_button =
|
|
|
|
|
gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
|
|
|
|
|
GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
|
|
|
|
|
NULL,
|
|
|
|
|
"Tooltips",
|
|
|
|
|
"Toolbar with or without tips",
|
|
|
|
|
"Private",
|
|
|
|
|
iconw,
|
|
|
|
|
GTK_SIGNAL_FUNC (toggle_event),
|
|
|
|
|
toolbar);
|
|
|
|
|
gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
|
|
|
|
|
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Un bot<6F>n de selecci<63>n puede crearse de una forma obvia (si ya sabe como
|
|
|
|
|
crear botones circulares).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* para empaquetar un widget en la barra de herramientas, s<>lo
|
|
|
|
|
* tenemos que crearlo y a<>adirlo en la barra con el tooltip
|
|
|
|
|
* apropiado */
|
|
|
|
|
entry = gtk_entry_new ();
|
|
|
|
|
gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar),
|
|
|
|
|
entry,
|
|
|
|
|
"This is just an entry",
|
|
|
|
|
"Private" );
|
|
|
|
|
|
|
|
|
|
/* bien, no se ha creado con la barra, as<61> que debemos mostrarlo
|
|
|
|
|
* explicitamente */
|
|
|
|
|
gtk_widget_show ( entry );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como puede ver, a<>adir cualquier tipo de <em>widget</em> a la barra
|
|
|
|
|
de herramientas es f<>cil. Lo <20>nico que debe recordar es que este
|
|
|
|
|
<em>widget</em> debe mostrarse manualmente (al contrario que los dem<65>s
|
|
|
|
|
elementos que se mostrar<61>n junto con la barra de herramientas).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* <20> Eso es ! mostremos algo. */
|
|
|
|
|
gtk_widget_show ( toolbar );
|
|
|
|
|
gtk_widget_show (handlebox);
|
|
|
|
|
gtk_widget_show ( dialog );
|
|
|
|
|
|
|
|
|
|
/* qued<65>monos en gtk_main y <20>esperemos a que empiece la diversi<73>n! */
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Y ya estamos en el final del tutorial sobre la barra de herramientas.
|
|
|
|
|
Por supuesto, para apreciar completamente el ejemplo, necesita adem<65>s
|
|
|
|
|
del c<>digo este precioso icono XPM que le mostramos a continuaci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* XPM */
|
|
|
|
|
static char * gtk_xpm[] = {
|
|
|
|
|
"32 39 5 1",
|
|
|
|
|
". c none",
|
|
|
|
|
"+ c black",
|
|
|
|
|
"@ c #3070E0",
|
|
|
|
|
"# c #F05050",
|
|
|
|
|
"$ c #35E035",
|
|
|
|
|
"................+...............",
|
|
|
|
|
"..............+++++.............",
|
|
|
|
|
"............+++++@@++...........",
|
|
|
|
|
"..........+++++@@@@@@++.........",
|
|
|
|
|
"........++++@@@@@@@@@@++........",
|
|
|
|
|
"......++++@@++++++++@@@++.......",
|
|
|
|
|
".....+++@@@+++++++++++@@@++.....",
|
|
|
|
|
"...+++@@@@+++@@@@@@++++@@@@+....",
|
|
|
|
|
"..+++@@@@+++@@@@@@@@+++@@@@@++..",
|
|
|
|
|
".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
|
|
|
|
|
".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
|
|
|
|
|
".+##++@@@@+++@@@+++++@@@@@@@@$@.",
|
|
|
|
|
".+###++@@@@+++@@@+++@@@@@++$$$@.",
|
|
|
|
|
".+####+++@@@+++++++@@@@@+@$$$$@.",
|
|
|
|
|
".+#####+++@@@@+++@@@@++@$$$$$$+.",
|
|
|
|
|
".+######++++@@@@@@@++@$$$$$$$$+.",
|
|
|
|
|
".+#######+##+@@@@+++$$$$$$@@$$+.",
|
|
|
|
|
".+###+++##+##+@@++@$$$$$$++$$$+.",
|
|
|
|
|
".+###++++##+##+@@$$$$$$$@+@$$@+.",
|
|
|
|
|
".+###++++++#+++@$$@+@$$@++$$$@+.",
|
|
|
|
|
".+####+++++++#++$$@+@$$++$$$$+..",
|
|
|
|
|
".++####++++++#++$$@+@$++@$$$$+..",
|
|
|
|
|
".+#####+++++##++$$++@+++$$$$$+..",
|
|
|
|
|
".++####+++##+#++$$+++++@$$$$$+..",
|
|
|
|
|
".++####+++####++$$++++++@$$$@+..",
|
|
|
|
|
".+#####++#####++$$+++@++++@$@+..",
|
|
|
|
|
".+#####++#####++$$++@$$@+++$@@..",
|
|
|
|
|
".++####++#####++$$++$$$$$+@$@++.",
|
|
|
|
|
".++####++#####++$$++$$$$$$$$+++.",
|
|
|
|
|
".+++####+#####++$$++$$$$$$$@+++.",
|
|
|
|
|
"..+++#########+@$$+@$$$$$$+++...",
|
|
|
|
|
"...+++########+@$$$$$$$$@+++....",
|
|
|
|
|
".....+++######+@$$$$$$$+++......",
|
|
|
|
|
"......+++#####+@$$$$$@++........",
|
|
|
|
|
".......+++####+@$$$$+++.........",
|
|
|
|
|
".........++###+$$$@++...........",
|
|
|
|
|
"..........++##+$@+++............",
|
|
|
|
|
"...........+++++++..............",
|
|
|
|
|
".............++++..............."};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Libros de notas (<em/Notebooks/)
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ Notebook es una colecci<63>n de `p<>ginas' que se solapan
|
|
|
|
|
las unas a las otras, cada una con un contenido diferente. Este
|
|
|
|
|
<em/widget/ se ha vuelto cada vez m<>s com<6F>n <20>ltimamente en la
|
|
|
|
|
programaci<EFBFBD>n de interfaces gr<67>ficos de usuario (GUI en ingl<67>s), y es
|
|
|
|
|
una buena forma de mostrar bloques de informaci<63>n similar que
|
|
|
|
|
necesitan aparecer de forma separada.
|
|
|
|
|
|
|
|
|
|
La primera funci<63>n que necesita conocer, como probablemente ya habr<62>
|
|
|
|
|
adivinado, se utiliza para crear un nuevo <em/widget/ notebook.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_notebook_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Una vez haya crear el libro de notas, hay 12 funciones que se pueden
|
|
|
|
|
utilizar para trabajar con <20>l. Ech<63>mosles un vistazo una a una.
|
|
|
|
|
|
|
|
|
|
La primera que estudiaremos ser<65> la que nos permita establecer la
|
|
|
|
|
posici<EFBFBD>n de los indicadores de la p<>gina. Estos indicadores se pueden
|
|
|
|
|
poner en cuatro lugares diferentes: arriba, abajo, a la derecha o a la
|
|
|
|
|
izquierda.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_notebook_set_tab_pos( GtkNotebook *notebook,
|
|
|
|
|
GtkPositionType pos );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/GtkPositionType/ debe tener uno de los valores siguientes (su significado
|
|
|
|
|
est<EFBFBD> bastante claro):
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_POS_LEFT
|
|
|
|
|
<item> GTK_POS_RIGHT
|
|
|
|
|
<item> GTK_POS_TOP
|
|
|
|
|
<item> GTK_POS_BOTTOM
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
GTK_POS_TOP es el valor por defecto.
|
|
|
|
|
|
|
|
|
|
Lo siguiente que estudiaremos es como a<>adir p<>ginas al libro de notas.
|
|
|
|
|
Hay tres formas de a<>adirle p<>ginas al <em/widget/. Veamos las dos primeras
|
|
|
|
|
formas (son muy parecidas).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_notebook_append_page( GtkNotebook *notebook,
|
|
|
|
|
GtkWidget *hijo,
|
|
|
|
|
GtkWidget *tab_label );
|
|
|
|
|
|
|
|
|
|
void gtk_notebook_prepend_page( GtkNotebook *notebook,
|
|
|
|
|
GtkWidget *hijo,
|
|
|
|
|
GtkWidget *tab_label );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Estas funciones le a<>aden p<>ginas al libro de notas insert<72>ndolas desde
|
|
|
|
|
el fondo del libro (a<>adi<64>ndolas), o desde parte superior del libro
|
|
|
|
|
(prea<65>adi<64>ndolas). <tt/hijo/ es el <em/widget/ que se mete en la p<>gina
|
|
|
|
|
del libro de notas, y <tt/tab_label/ es la etiqueta para la p<>gina que
|
|
|
|
|
estamos a<>adiendo.
|
|
|
|
|
|
|
|
|
|
La funci<63>n que queda que sirve para a<>adir una p<>gina contiene todas las
|
|
|
|
|
propiedades de las anteriores, pero adem<65>s permite especificar en que
|
|
|
|
|
posici<EFBFBD>n quiere que est<73> la p<>gina dentro del libro de notas.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_notebook_insert_page( GtkNotebook *notebook,
|
|
|
|
|
GtkWidget *hijo,
|
|
|
|
|
GtkWidget *tab_label,
|
|
|
|
|
gint posicion );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los par<61>metros son los mismos que hab<61>an en las funciones _append_ y
|
|
|
|
|
_prepend_ excepto que hay uno m<>s que antes, <tt/posicion/. Este
|
|
|
|
|
par<EFBFBD>metro se utiliza para especificar en que lugar debe introducirse
|
|
|
|
|
la p<>gina.
|
|
|
|
|
|
|
|
|
|
Ahora que sabemos como a<>adir un p<>gina, veamos como podemos eliminar
|
|
|
|
|
una p<>gina del libro de notas.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_notebook_remove_page( GtkNotebook *notebook,
|
|
|
|
|
gint page_num );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n coge la p<>gina especificada por <tt/page_num/ y la
|
|
|
|
|
elimina del <em/widget/ al que apunta <tt/notebook/.
|
|
|
|
|
|
|
|
|
|
Para saber cual es la p<>gina actual del libro de notas utilice la
|
|
|
|
|
funci<EFBFBD>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_notebook_current_page( GtkNotebook *notebook );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Las dos funciones siguientes sirven para ir a la p<>gina siguiente o a
|
|
|
|
|
la anterior del libro de notas. Para utilizarlas s<>lo hay que
|
|
|
|
|
proporcionar el <em/widget/ notebook que queremos manipular. Nota:
|
|
|
|
|
cuando el libro de notas est<73> en la <20>ltima p<>gina y se llama a
|
|
|
|
|
<tt/gtk_notebook_next_page/, se pasar<61> a la primera p<>gina. Sin
|
|
|
|
|
embargo, si el libro de notas est<73> en la primera p<>gina, y se llama a
|
|
|
|
|
<tt/gtk_notebook_prev_page/, no se pasar<61> a la <20>ltima p<>gina.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_notebook_next_page( GtkNoteBook *notebook );
|
|
|
|
|
|
|
|
|
|
void gtk_notebook_prev_page( GtkNoteBook *notebook );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La siguiente funci<63>n establece la p<>gina `activa'. Si quiere que se
|
|
|
|
|
abra el libro de notas por la p<>gina 5, por ejemplo, debe utilizar
|
|
|
|
|
esta funci<63>n. Si no utiliza esta funci<63>n el libro de notas empezar<61>
|
|
|
|
|
por defecto en la primera p<>gina.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_notebook_set_page( GtkNotebook *notebook,
|
|
|
|
|
gint page_num );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Las dos funciones siguientes a<>aden o eliminan los indicadores de las
|
|
|
|
|
p<EFBFBD>ginas o el borde del libro, respectivamente.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
|
|
|
|
|
gint show_tabs);
|
|
|
|
|
|
|
|
|
|
void gtk_notebook_set_show_border( GtkNotebook *notebook,
|
|
|
|
|
gint show_border );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/show_tabs/ y <tt/show_border/ puede ser TRUE o FALSE.
|
|
|
|
|
|
|
|
|
|
Ahora ech<63>mosle un vistaza a un ejemplo, sacado del c<>digo de
|
|
|
|
|
<tt/testgtk.c/ que viene con la distribuci<63>n de GTK, y que muestra
|
|
|
|
|
la utilizaci<63>n de las 13 funciones. Este peque<75>o programa crea una
|
|
|
|
|
ventana con un libro de notas y seis botones. El libro de notas
|
|
|
|
|
contiene 11 p<>ginas, incluidas de tres formas diferentes, a<>adidas,
|
|
|
|
|
insertadas, y prea<65>adidas. Los botones le permiten rotar las
|
|
|
|
|
posiciones de los indicadores, a<>adir y eliminar los indicadores y el
|
|
|
|
|
borde, eliminar una p<>gina, cambiar p<>ginas hacia delante y hacia
|
|
|
|
|
detr<EFBFBD>s, y salir del programa.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo notebook notebook.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* Esta funci<63>n rota la posici<63>n de los indicadores */
|
|
|
|
|
void rotate_book (GtkButton *boton, GtkNotebook *notebook)
|
|
|
|
|
{
|
|
|
|
|
gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A<>ade/Elimina los indicadores de la p<>gina y los bordes */
|
|
|
|
|
void tabsborder_book (GtkButton *boton, GtkNotebook *notebook)
|
|
|
|
|
{
|
|
|
|
|
gint tval = FALSE;
|
|
|
|
|
gint bval = FALSE;
|
|
|
|
|
if (notebook->show_tabs == 0)
|
|
|
|
|
tval = TRUE;
|
|
|
|
|
if (notebook->show_border == 0)
|
|
|
|
|
bval = TRUE;
|
|
|
|
|
|
|
|
|
|
gtk_notebook_set_show_tabs (notebook, tval);
|
|
|
|
|
gtk_notebook_set_show_border (notebook, bval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Elimina una p<>gina del libro de notas */
|
|
|
|
|
void remove_book (GtkButton *boton, GtkNotebook *notebook)
|
|
|
|
|
{
|
|
|
|
|
gint page;
|
|
|
|
|
|
|
|
|
|
page = gtk_notebook_current_page(notebook);
|
|
|
|
|
gtk_notebook_remove_page (notebook, page);
|
|
|
|
|
/* Hay que redibujar el widget --
|
|
|
|
|
Esto fuerza que el widget se autoredibuje */
|
|
|
|
|
gtk_widget_draw(GTK_WIDGET(notebook), NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void delete (GtkWidget *widget, GtkWidget *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *table;
|
|
|
|
|
GtkWidget *notebook;
|
|
|
|
|
GtkWidget *frame;
|
|
|
|
|
GtkWidget *etiqueta;
|
|
|
|
|
GtkWidget *checkbutton;
|
|
|
|
|
int i;
|
|
|
|
|
char bufferf[32];
|
|
|
|
|
char bufferl[32];
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (delete), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
table = gtk_table_new(2,6,TRUE);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), table);
|
|
|
|
|
|
|
|
|
|
/* Crea un nuevo libro de notas, indicando la posici<63>n de los
|
|
|
|
|
indicadores */
|
|
|
|
|
notebook = gtk_notebook_new ();
|
|
|
|
|
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
|
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
|
|
|
|
|
gtk_widget_show(notebook);
|
|
|
|
|
|
|
|
|
|
/* le a<>adimos un mont<6E>n de p<>ginas al libro de notas */
|
|
|
|
|
for (i=0; i < 5; i++) {
|
|
|
|
|
sprintf(bufferf, "Append Frame %d", i+1);
|
|
|
|
|
sprintf(bufferl, "Page %d", i+1);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new (bufferf);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (frame), 10);
|
|
|
|
|
gtk_widget_set_usize (frame, 100, 75);
|
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new (bufferf);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), etiqueta);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new (bufferl);
|
|
|
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, etiqueta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Ahora a<>adimos una p<>gina en punto espec<65>fico */
|
|
|
|
|
checkbutton = gtk_check_button_new_with_label ("Check me please!");
|
|
|
|
|
gtk_widget_set_usize(checkbutton, 100, 75);
|
|
|
|
|
gtk_widget_show (checkbutton);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new ("Add spot");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (checkbutton), etiqueta);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
etiqueta = gtk_label_new ("Add page");
|
|
|
|
|
gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, etiqueta, 2);
|
|
|
|
|
|
|
|
|
|
/* Y finalmente prea<65>adimos p<>ginas en el libro de notas */
|
|
|
|
|
for (i=0; i < 5; i++) {
|
|
|
|
|
sprintf(bufferf, "Prepend Frame %d", i+1);
|
|
|
|
|
sprintf(bufferl, "PPage %d", i+1);
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new (bufferf);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (frame), 10);
|
|
|
|
|
gtk_widget_set_usize (frame, 100, 75);
|
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new (bufferf);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (frame), etiqueta);
|
|
|
|
|
gtk_widget_show (etiqueta);
|
|
|
|
|
|
|
|
|
|
etiqueta = gtk_label_new (bufferl);
|
|
|
|
|
gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, etiqueta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Decimos en que p<>gina empezar (p<>gina 4) */
|
|
|
|
|
gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* creamos un mont<6E>n de botones */
|
|
|
|
|
boton = gtk_button_new_with_label ("close");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (delete), NULL);
|
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(table), boton, 0,1,1,2);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("next page");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
(GtkSignalFunc) gtk_notebook_next_page,
|
|
|
|
|
GTK_OBJECT (notebook));
|
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(table), boton, 1,2,1,2);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("prev page");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
(GtkSignalFunc) gtk_notebook_prev_page,
|
|
|
|
|
GTK_OBJECT (notebook));
|
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(table), boton, 2,3,1,2);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("tab position");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
(GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
|
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(table), boton, 3,4,1,2);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("tabs/border on/off");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
(GtkSignalFunc) tabsborder_book,
|
|
|
|
|
GTK_OBJECT (notebook));
|
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(table), boton, 4,5,1,2);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("remove page");
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
(GtkSignalFunc) remove_book,
|
|
|
|
|
GTK_OBJECT(notebook));
|
|
|
|
|
gtk_table_attach_defaults(GTK_TABLE(table), boton, 5,6,1,2);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(table);
|
|
|
|
|
gtk_widget_show(ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Espero que la explicaci<63>n le ayude de alguna manera a crear libros de
|
|
|
|
|
notas en sus aplicaciones GTK.
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> El <em/widget/ GtkCList
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
El <em>widget</em> GtkCList ha reemplazado al <em>widget</em> GtkList
|
|
|
|
|
(que sigue estando disponible).
|
|
|
|
|
|
|
|
|
|
El <em>widget</em> GtkCList es un <em>widget</em> de una lista
|
|
|
|
|
multicolumna que es capaz de manejar, literalmente, miles de filas de
|
|
|
|
|
informaci<EFBFBD>n. Cada columna puede tener (opcionalmente) un t<>tulo, que
|
|
|
|
|
puede estar activado (opcionalmente), permiti<74>ndonos enlazar una
|
|
|
|
|
funci<EFBFBD>n con la selecci<63>n.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Creando un <em>widget</em> GtkCList
|
|
|
|
|
<p>
|
|
|
|
|
Crear un GtkCList es algo bastante sencillo, una vez que sabe como
|
|
|
|
|
crear un <em>widget</em> en general. Se proporcionan al menos dos
|
|
|
|
|
formas est<73>ndar de crearlo, la forma f<>cil y la forma dif<69>cil. Pero
|
|
|
|
|
antes de crear una GtkCList, hay una cosa que debemos saber: <20>Cu<43>ntas
|
|
|
|
|
columnas va a tener?
|
|
|
|
|
|
|
|
|
|
No todas las columnas tienen que ser visibles y pueden utilizarse para
|
|
|
|
|
almacenar datos que est<73>n relacionados con una cierta celda de la
|
|
|
|
|
lista.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_clist_new ( gint columns );
|
|
|
|
|
|
|
|
|
|
GtkWidget *gtk_clist_new_with_titles( gint columns,
|
|
|
|
|
gchar *titles[] );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta primera aproximaci<63>n al problema es muy sencilla, pero la segunda
|
|
|
|
|
requerir<EFBFBD> alguna explicaci<63>n adicional. Cada columna puede tener un
|
|
|
|
|
t<EFBFBD>tulo asociado. Si utilizamos la segunda forma, deberemos proporcionar
|
|
|
|
|
punteros al texto del t<>tulo, y el n<>mero de punteros debe ser igual
|
|
|
|
|
al n<>mero de columnas especificadas. Por supuesto, siempre podemos
|
|
|
|
|
utilizar la primera forma de creaci<63>n y a<>adir m<>s tarde los t<>tulos
|
|
|
|
|
de forma manual.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Modos de operaci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
Hay varios atributos que pueden utilizarse para alterar el aspecto
|
|
|
|
|
de un GtkCList. Primero tenemos
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_selection_mode( GtkCList *clist,
|
|
|
|
|
GtkSelectionMode mode );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
que, como el propio nombre indica, establece el modo de selecci<63>n de la
|
|
|
|
|
lista GtkCList. El primer argumento es el <em>widget</em> GtkCList, y el
|
|
|
|
|
segundo especifica el modo de selecci<63>n de la celda (est<73>n definidos
|
|
|
|
|
en <tt/gtkenums.h/). En el momento de escribir esto, estaban
|
|
|
|
|
disponibles los siguientes modos:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_SELECTION_SINGLE - La selecci<63>n o es NULL o contiene un
|
|
|
|
|
puntero GList a un elemento seleccionado.
|
|
|
|
|
|
|
|
|
|
<item> GTK_SELECTION_BROWSE - La selecci<63>n es NULL si la lista no
|
|
|
|
|
contiene <em>widgets</em> o si los que contiene son insensibles, en
|
|
|
|
|
caso contrario contendr<64> un puntero GList hacia una estructura GList,
|
|
|
|
|
y por tanto con exactamente un elemento.
|
|
|
|
|
|
|
|
|
|
<item> GTK_SELECTION_MULTIPLE - La selecci<63>n es NULL si no hay
|
|
|
|
|
seleccionados una lista de elementos o un puntero GList para el primer
|
|
|
|
|
elemento seleccionado.<!-- FIXME: Todo esto no se si tiene sentido -->
|
|
|
|
|
<EFBFBD>ste apunta de nuevo a una estructura GList para el segundo elemento
|
|
|
|
|
seleccionado y continua as<61>. <20>ste es, actualmente, el modo por
|
|
|
|
|
<bf>defecto</bf> para el <em>widget</em> GtkCList.
|
|
|
|
|
|
|
|
|
|
<item> GTK_SELECTION_EXTENDED - La selecci<63>n siempre es NULL.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Puede que se a<>adan otros modos en versiones posteriores de GTK.
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n tenemos
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_policy (GtkCList *clist,
|
|
|
|
|
GtkPolicyType vscrollbar_policy,
|
|
|
|
|
GtkPolicyType hscrollbar_policy);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
que define que es lo que ocurre con las barras de desplazamiento. Los
|
|
|
|
|
siguientes valores son los posibles para las barras de desplazamiento
|
|
|
|
|
horizontal y vertical:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_POLICY_ALWAYS - La barra de desplazamiento siempre est<73> ah<61>.
|
|
|
|
|
|
|
|
|
|
<item> GTK_POLICY_AUTOMATIC - La barra de desplazamiento estar<61> ah<61> s<>lo
|
|
|
|
|
cuando el n<>mero de elementos en la GtkCList supere el n<>mero que puede
|
|
|
|
|
mostrarse en el <em>widget</em>.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n podemos definir como deber<65>a ser el aspecto del borde del
|
|
|
|
|
<em>widget</em> GtkCList. Esto lo podemos hacer mediante
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_border( GtkCList *clist,
|
|
|
|
|
GtkShadowType border );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Y los posibles valores para el segundo argumento son
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_SHADOW_NONE
|
|
|
|
|
|
|
|
|
|
<item> GTK_SHADOW_IN
|
|
|
|
|
|
|
|
|
|
<item> GTK_SHADOW_OUT
|
|
|
|
|
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_IN
|
|
|
|
|
|
|
|
|
|
<item> GTK_SHADOW_ETCHED_OUT
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Trabajando con los t<>tulos
|
|
|
|
|
<p>
|
|
|
|
|
Cuando cree un <em>widget</em> GtkCList, tambi<62>n obtendr<64>
|
|
|
|
|
autom<EFBFBD>ticamente un conjunto de botones t<>tulo. Vivir<69>n en lo alto de
|
|
|
|
|
una ventana CList, y pueden actuar como botones normales que responden
|
|
|
|
|
cuando se pulsa sobre ellos, o bien pueden ser pasivos, en cuyo caso
|
|
|
|
|
no ser<65>n nada m<>s que un t<>tulo. Hay cuatro llamadas diferentes que
|
|
|
|
|
nos ayudar<61>n a establecer el estado de los botones t<>tulo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_column_title_active( GtkCList *clist,
|
|
|
|
|
gint column );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_column_title_passive( GtkCList *clist,
|
|
|
|
|
gint column );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_column_titles_active( GtkCList *clist );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_column_titles_passive( GtkCList *clist );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Un t<>tulo activo es aquel que actua como un bot<6F>n normal, y uno pasivo
|
|
|
|
|
es s<>lo una etiqueta. Las primeras dos llamadas de arriba
|
|
|
|
|
activar<EFBFBD>n/desactivar<61>n el bot<6F>n t<>tulo correspondiente a la columna
|
|
|
|
|
<tt/column/, mientras que las dos llamadas siguientes
|
|
|
|
|
activar<EFBFBD>n/desactivar<61>n todos los botones t<>tulo que hayan en el
|
|
|
|
|
<em>widget</em> <tt/clist/ que se le proporcione a la funci<63>n.
|
|
|
|
|
|
|
|
|
|
Pero, por supuesto, habr<62> casos en el que no querremos utilizar los
|
|
|
|
|
botones t<>tulo, as<61> que tambi<62>n tenemos la posibilidad de ocultarlos y
|
|
|
|
|
de volverlos a mostrar utilizando las dos llamadas siguientes:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_column_titles_show( GtkCList *clist );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_column_titles_hide( GtkCList *clist );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para que los t<>tulos sean realmente <20>tiles necesitamos un mecanismo
|
|
|
|
|
que nos permita darles el valor que nosotros queramos y cambiar ese
|
|
|
|
|
valor, y podremos hacerlo mediante
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_column_title( GtkCList *clist,
|
|
|
|
|
gint column,
|
|
|
|
|
gchar *title );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Debe llevar cuidado, ya que s<>lo se puede especificar el t<>tulo de una
|
|
|
|
|
columna a la vez, por lo que si conoce todos los t<>tulos desde el
|
|
|
|
|
principio, le sugiero que utilice <tt/gtk_clist_new_with_titles/ (como
|
|
|
|
|
se describe arriba) para establecerlos adecuadamente. Le ahorrar<61>
|
|
|
|
|
tiempo de programaci<63>n, y har<61> su programa m<>s peque<75>o. Hay algunos
|
|
|
|
|
casos donde es mejor utilizar la forma manual, y uno de ellos es
|
|
|
|
|
cuando no todos los t<>tulos son texto. GtkCList nos proporciona
|
|
|
|
|
botones t<>tulo que pueden, de hecho, incorporar un <em>widget</em>
|
|
|
|
|
entero, por ejemplo un <em>pixmap</em>. Todo esto se hace mediante
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_column_widget( GtkCList *clist,
|
|
|
|
|
gint column,
|
|
|
|
|
GtkWidget *widget );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
que no deber<65>a necesitar de explicaciones adicionales.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Manipulando la lista en s<>.
|
|
|
|
|
<p>
|
|
|
|
|
Es posible cambiar la justificaci<63>n de una columna, y esto se hace
|
|
|
|
|
mediante
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_column_justification( GtkCList *clist,
|
|
|
|
|
gint column,
|
|
|
|
|
GtkJustification justification );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El tipo GtkJustification puede tomar los valores siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>GTK_JUSTIFY_LEFT - El texto en la columna empezar<61> desde el lado
|
|
|
|
|
izquierdo.
|
|
|
|
|
|
|
|
|
|
<item>GTK_JUSTIFY_RIGHT - El texto en la columna empezar<61> desde el
|
|
|
|
|
lado derecho.
|
|
|
|
|
|
|
|
|
|
<item>GTK_JUSTIFY_CENTER - El texto se colocar<61> en el centro de la
|
|
|
|
|
columna.
|
|
|
|
|
|
|
|
|
|
<item>GTK_JUSTIFY_FILL - El texto utilizar<61> todo el espacio disponible
|
|
|
|
|
en la columna. Normalmente se hace a<>adiendo espacios en blanco entre
|
|
|
|
|
las palabras (o entre letras por separado, si se trata de una sola
|
|
|
|
|
palabra). M<>s o menos de la misma forma en la que lo hace un
|
|
|
|
|
procesador de textos WYSIWYG.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
La siguiente funci<63>n es muy importante, y deber<65>a ser un est<73>ndar
|
|
|
|
|
para inicializar todos los <em>widgets</em> GtkCList. Cuando se crea
|
|
|
|
|
la lista, los anchos de las distintas columnas se eligen para que
|
|
|
|
|
coincidan con sus t<>tulos, y <20>ste es el ancho adecuado que tenemos que
|
|
|
|
|
poner, utilizando
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_column_width( GtkCList *clist,
|
|
|
|
|
gint column,
|
|
|
|
|
gint width );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Observe que el ancho viene dado en pixeles y no en letras. Lo mismo
|
|
|
|
|
vale para el alto de la celda en las columnas, pero como el valor por
|
|
|
|
|
defecto es la altura del tipo de letra actual, no es algo tan cr<63>tico
|
|
|
|
|
para la aplicaci<63>n. De todas formas, la altura se cambia mediante
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_row_height( GtkCList *clist,
|
|
|
|
|
gint height );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
De nuevo, hay que advertir que el ancho viene dado en pixeles.
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n podemos ir hacia un elemento sin la intervenci<63>n del usuario,
|
|
|
|
|
sin embargo hace falta que sepamos hacia donde queremos ir. O en otras
|
|
|
|
|
palabras, necesitamos la fila y la columna del elemento al que queremos
|
|
|
|
|
pasar.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_moveto( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column,
|
|
|
|
|
gfloat row_align,
|
|
|
|
|
gfloat col_align );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Es importante comprender bien el significado de <tt/gfloat
|
|
|
|
|
row_align/. Tiene un valor entre 0.0 y 1.0, donde 0.0 significa que
|
|
|
|
|
debemos hacer que la fila seleccionada aparezca en la alto de la
|
|
|
|
|
lista, mientras que 1.0 significa que la fila aparecer<65> en la parte de
|
|
|
|
|
abajo. El resto de valores entre 0.0 y 1.0 son v<>lidos y har<61>n que la
|
|
|
|
|
fila aparezca entre la parte superior y la inferior. El <20>ltimo
|
|
|
|
|
argumento, <tt/gfloat col_align/ funciona igual, siendo 0.0 la
|
|
|
|
|
izquierda y 1.0 la derecha.
|
|
|
|
|
|
|
|
|
|
Dependiendo de las necesidades de la aplicaci<63>n, puede que no tengamos
|
|
|
|
|
que hacer un desplazamiento hacia un elemento que ya sea visible. Por
|
|
|
|
|
tanto, <20>c<EFBFBD>mo podemos saber si ya es visible? Como siempre, hay una funci<63>n
|
|
|
|
|
que sirve para averiguarlo
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
|
|
|
|
|
gint row );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El valor devuelto es uno de los siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>GTK_VISIBILITY_NONE
|
|
|
|
|
|
|
|
|
|
<item>GTK_VISIBILITY_PARTIAL
|
|
|
|
|
|
|
|
|
|
<item>GTK_VISIBILITY_FULL
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Como puede ver, s<>lo nos dice si una fila es visible. Actualmente no hay
|
|
|
|
|
ninguna forma de obtener el mismo dato para una columna. Sin embargo
|
|
|
|
|
podemos obtener informaci<63>n parcial, porque si el valor devuelto es
|
|
|
|
|
GTK_VISIBILITY_PARTIAL, entonces es que alguna parte est<73> oculta,
|
|
|
|
|
pero no sabemos si es la fila que est<73> cortada por la parte de abajo
|
|
|
|
|
de la lista, o si la fila tiene columnas que est<73>n fuera.
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n podemos cambiar el color del primer y del segundo plano de una
|
|
|
|
|
fila en particular. Esto es <20>til para marcar la fila seleccionada por
|
|
|
|
|
el usuario, y las dos funciones que hay que utilizar son
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_foreground( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
GdkColor *color );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_set_background( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
GdkColor *color );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Cuidado, ya que los colores deben estar asignados previamente en la
|
|
|
|
|
memoria.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>A<>adiendo filas a la lista
|
|
|
|
|
<p>
|
|
|
|
|
Podemos a<>adir filas de dos formas. Se pueden a<>adir al final de la lista
|
|
|
|
|
utilizando
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_clist_append( GtkCList *clist,
|
|
|
|
|
gchar *text[] );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
o podemos insertar una fila en un lugar determinado utilizando
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_insert( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gchar *text[] );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
En ambas llamadas podemos proporcionar un conjunto de punteros que
|
|
|
|
|
ser<EFBFBD>n los textos que queremos poner en las columnas. El n<>mero de
|
|
|
|
|
punteros debe ser igual al n<>mero de columnas en la lista. Si el
|
|
|
|
|
argumento <tt/text[]/ es NULL, entonces no habr<62> texto en las columnas
|
|
|
|
|
de la fila. Esto ser<65>a <20>til, por ejemplo, si queremos a<>adir
|
|
|
|
|
<em>pixmaps</em> en lugar de texto (en general para cualquier cosa que
|
|
|
|
|
haya que hacer manualmente).
|
|
|
|
|
|
|
|
|
|
De nuevo, cuidado ya que el n<>mero de filas y de columnas comienza en
|
|
|
|
|
0.
|
|
|
|
|
|
|
|
|
|
Para eliminar una fila individual podemos utilizar
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_remove( GtkCList *clist,
|
|
|
|
|
gint row );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Hay tambi<62>n una llamada que elimina todas las filas en la lista.
|
|
|
|
|
Es mucho m<>s r<>pido que llamar a <tt/gtk_clist_remove/ una vez por
|
|
|
|
|
cada fila, que ser<65>a la <20>nica alternativa.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_clear( GtkCList *clist );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n hay dos funciones que es conveniente utilizarlas cuando hay
|
|
|
|
|
que hacerle muchos cambios a una lista. Son para evitar que la lista
|
|
|
|
|
parpadee mientras es actualizada repetidamente, que puede ser muy
|
|
|
|
|
molesto para el usuario. Por tanto es una buena idea congelar la
|
|
|
|
|
lista, hacer los cambios, y descongelarla, que har<61> que la lista se
|
|
|
|
|
actualice en la pantalla.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_freeze( GtkCList * clist );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_thaw( GtkCList * clist );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Poniendo texto y <em>pixmaps</em> en las celdas
|
|
|
|
|
<p>
|
|
|
|
|
Una celda puede contener un <em>pixmap</em>, texto o ambos. Para ponerlos
|
|
|
|
|
en las celdas, podemos utilizar las siguientes funciones.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_text( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column,
|
|
|
|
|
gchar *text );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_set_pixmap( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column,
|
|
|
|
|
GdkPixmap *pixmap,
|
|
|
|
|
GdkBitmap *mask );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_set_pixtext( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column,
|
|
|
|
|
gchar *text,
|
|
|
|
|
guint8 spacing,
|
|
|
|
|
GdkPixmap *pixmap,
|
|
|
|
|
GdkBitmap *mask );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Son bastante sencillas de entender. Todas las llamadas tienen la
|
|
|
|
|
GtkCList como primer argumento, seguidas por la fila y la columna
|
|
|
|
|
de la celda, y seguidas por el dato que debe ponerse en la celda. El
|
|
|
|
|
argumento <tt/gint8 spacing/ en <tt/gtk_clist_set_pixtext/ es el
|
|
|
|
|
n<EFBFBD>mero de <em>pixels</em> entre el <em>pixmap</em> y el principio del
|
|
|
|
|
texto.
|
|
|
|
|
|
|
|
|
|
Para leer los datos que hay en una celda, podemos utilizar
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_clist_get_text( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column,
|
|
|
|
|
gchar **text );
|
|
|
|
|
|
|
|
|
|
gint gtk_clist_get_pixmap( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column,
|
|
|
|
|
GdkPixmap **pixmap,
|
|
|
|
|
GdkBitmap **mask );
|
|
|
|
|
|
|
|
|
|
gint gtk_clist_get_pixtext( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column,
|
|
|
|
|
gchar **text,
|
|
|
|
|
guint8 *spacing,
|
|
|
|
|
GdkPixmap **pixmap,
|
|
|
|
|
GdkBitmap **mask );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
No es necesario leer todos los datos en caso de que no estemos
|
|
|
|
|
interesados. Cualquiera de los punteros que se supone contendr<64>n los
|
|
|
|
|
valores a devolver (cualquiera excepto el <tt/clist/) pueden ser
|
|
|
|
|
NULL. Por lo que si s<>lo queremos leer el texto de una celda que es de
|
|
|
|
|
tipo <tt/pixtext/, deber<65>amos hacer lo siguiente, suponiendo que
|
|
|
|
|
<tt/clist/, <tt/row/ y <tt/column/ ya existan:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gchar *mytext;
|
|
|
|
|
|
|
|
|
|
gtk_clist_get_pixtext(clist, row, column, &mytext, NULL, NULL, NULL);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Hay una rutina m<>s que est<73> relacionada con lo que est<73> dentro
|
|
|
|
|
de una celda de una <tt/clist/, y es
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
que devuelve el tipo de datos que hay en la celda. El valor devuelto es
|
|
|
|
|
uno de los siguientes
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>GTK_CELL_EMPTY
|
|
|
|
|
|
|
|
|
|
<item>GTK_CELL_TEXT
|
|
|
|
|
|
|
|
|
|
<item>GTK_CELL_PIXMAP
|
|
|
|
|
|
|
|
|
|
<item>GTK_CELL_PIXTEXT
|
|
|
|
|
|
|
|
|
|
<item>GTK_CELL_WIDGET
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n hay una funci<63>n que nos permite especificar la indentaci<63>n de
|
|
|
|
|
un celda (horizontal o vertical). El valor de la indentaci<63>n es del
|
|
|
|
|
tipo <tt/gint/, viene dado en <em>pixeles</em>, y puede ser positivo o
|
|
|
|
|
negativo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_shift( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column,
|
|
|
|
|
gint vertical,
|
|
|
|
|
gint horizontal );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Almacenando punteros a datos
|
|
|
|
|
<p>
|
|
|
|
|
Con una GtkCList es posible poner un puntero a datos en una
|
|
|
|
|
fila. Este puntero no ser<65> visible al usuario, pero puede serle <20>til
|
|
|
|
|
al programador.
|
|
|
|
|
|
|
|
|
|
De nuevo, las funciones son lo suficientemente autoexplicativas
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_set_row_data( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_set_row_data_full( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gpointer data,
|
|
|
|
|
GtkDestroyNotify destroy );
|
|
|
|
|
|
|
|
|
|
gpointer gtk_clist_get_row_data( GtkCList *clist,
|
|
|
|
|
gint row );
|
|
|
|
|
|
|
|
|
|
gint gtk_clist_find_row_from_data( GtkCList *clist,
|
|
|
|
|
gpointer data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Trabajando con la selecci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
Tambi<EFBFBD>n hay funciones que nos permiten forzar la (de)selecci<63>n de una
|
|
|
|
|
fila. Son
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_clist_select_row( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column );
|
|
|
|
|
|
|
|
|
|
void gtk_clist_unselect_row( GtkCList *clist,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Y tambi<62>n una funci<63>n que tomar<61> las coordenadas x e y (por ejemplo,
|
|
|
|
|
recibidas del rat<61>n), mirar<61> en la lista y devolver<65> la fila y la
|
|
|
|
|
columna que les corresponden.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_clist_get_selection_info( GtkCList *clist,
|
|
|
|
|
gint x,
|
|
|
|
|
gint y,
|
|
|
|
|
gint *row,
|
|
|
|
|
gint *column );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Cuando detectemos algo interesante, como por ejemplo el movimiento del
|
|
|
|
|
rat<EFBFBD>n, o una pulsaci<63>n en cualquier lugar de la lista, podemos leer
|
|
|
|
|
las coordenadas del rat<61>n y encontrar en que elemento de la lista se
|
|
|
|
|
encuentra. <20>Engorroso? Afortunadamente, hay una forma m<>s sencilla de
|
|
|
|
|
hacer las cosas...
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Las se<73>ales que lo hacen todo
|
|
|
|
|
<p>
|
|
|
|
|
Como con el resto de <em>widgets</em>, hay unas cuantas se<73>ales que
|
|
|
|
|
podemos utilizar. El <em>widget</em> GtkCList est<73> derivado del
|
|
|
|
|
<em>widget</em> GtkContainer, y por tanto tiene las mismas
|
|
|
|
|
se<EFBFBD>ales que <20>ste, pero adem<65>s a<>ade las siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item><tt/select_row/ - Esta se<73>al enviar<61> la siguiente informaci<63>n,
|
|
|
|
|
en este orden: GtkCList *clist, gint row, gint column, GtkEventButton
|
|
|
|
|
*event
|
|
|
|
|
|
|
|
|
|
<item><tt/unselect_row/ - Cuando el usuario deselecciona una fila, se
|
|
|
|
|
activar<EFBFBD> esta se<73>al. Envia la misma informaci<63>n que <tt/select_row/
|
|
|
|
|
|
|
|
|
|
<item><tt/click_column/ - Envia GtkCList *clist, gint column
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Por tanto si queremos conectar una llamada a <tt/select_row/, la
|
|
|
|
|
llamada se deber<65> declarar como
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void select_row_callback(GtkWidget *widget,
|
|
|
|
|
gint row,
|
|
|
|
|
gint column,
|
|
|
|
|
GdkEventButton *event,
|
|
|
|
|
gpointer data);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La llamada se conectar<61>, como siempre, con
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT( clist),
|
|
|
|
|
"select_row"
|
|
|
|
|
GTK_SIGNAL_FUNC(select_row_callback),
|
|
|
|
|
NULL);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Un ejemplo GtkCList
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo clist clist.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
|
|
/* Aqu<71> tenemos algunos prototipos de las funciones de llamada */
|
|
|
|
|
void button_add_clicked( GtkWidget *boton, gpointer data);
|
|
|
|
|
void button_clear_clicked( GtkWidget *boton, gpointer data);
|
|
|
|
|
void button_hide_show_clicked( GtkWidget *boton, gpointer data);
|
|
|
|
|
void selection_made( GtkWidget *clist, gint row, gint column,
|
|
|
|
|
GdkEventButton *event, gpointer data);
|
|
|
|
|
|
|
|
|
|
gint main (int argc, gchar *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *vbox, *hbox;
|
|
|
|
|
GtkWidget *clist;
|
|
|
|
|
GtkWidget *button_add, *button_clear, *button_hide_show;
|
|
|
|
|
gchar *titles[2] = {"Ingredients","Amount"};
|
|
|
|
|
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ventana=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_widget_set_usize(GTK_WIDGET(ventana), 300, 150);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title(GTK_WINDOW(ventana), "GtkCList Example");
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(ventana),
|
|
|
|
|
"destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC(gtk_main_quit),
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
vbox=gtk_vbox_new(FALSE, 5);
|
|
|
|
|
gtk_container_border_width(GTK_CONTAINER(vbox), 5);
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(ventana), vbox);
|
|
|
|
|
gtk_widget_show(vbox);
|
|
|
|
|
|
|
|
|
|
/* Crear el GtkCList. Para este ejemplo utilizaremos 2 columnas */
|
|
|
|
|
clist = gtk_clist_new_with_titles( 2, titles);
|
|
|
|
|
|
|
|
|
|
/* Cuando se hace una selecci<63>n, queremos saber algo acerca de
|
|
|
|
|
* ella. La funci<63>n de llamada utilizada es selection_made, y su
|
|
|
|
|
* c<>digo lo podemos encontrar m<>s abajo */
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(clist), "select_row",
|
|
|
|
|
GTK_SIGNAL_FUNC(selection_made),
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* No es necesario ponerle sombra al borde, pero es bonito :) */
|
|
|
|
|
gtk_clist_set_border(GTK_CLIST(clist), GTK_SHADOW_OUT);
|
|
|
|
|
|
|
|
|
|
/* Lo que s<> que es importante, es poner el ancho de las columnas
|
|
|
|
|
* ya no tendr<64>n el valor correcto en caso contrario. Recuerde que
|
|
|
|
|
* las columnas se numeran desde el 0 en adelante (hasta el 1 en
|
|
|
|
|
* este caso).
|
|
|
|
|
*/
|
|
|
|
|
gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
|
|
|
|
|
|
|
|
|
|
/* Scollbars _only when needed_ */
|
|
|
|
|
gtk_clist_set_policy(GTK_CLIST(clist), GTK_POLICY_AUTOMATIC,
|
|
|
|
|
GTK_POLICY_AUTOMATIC);
|
|
|
|
|
|
|
|
|
|
/* A<>ade el widget GtkCList a la caja vertical y lo muestra. */
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), clist, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show(clist);
|
|
|
|
|
|
|
|
|
|
/* Crea los botones y los a<>ade a la ventana. Ver la parte del
|
|
|
|
|
* tutorial sobre botones para ver m<>s ejemplos y comentarios
|
|
|
|
|
* acerca de todo esto.
|
|
|
|
|
*/
|
|
|
|
|
hbox = gtk_hbox_new(FALSE, 0);
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
|
|
|
|
|
gtk_widget_show(hbox);
|
|
|
|
|
|
|
|
|
|
button_add = gtk_button_new_with_label("Add List");
|
|
|
|
|
button_clear = gtk_button_new_with_label("Clear List");
|
|
|
|
|
button_hide_show = gtk_button_new_with_label("Hide/Show titles");
|
|
|
|
|
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
/* Conectar nuestras funciones de llamada a los tres botones */
|
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(button_add_clicked),
|
|
|
|
|
(gpointer) clist);
|
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(button_clear_clicked),
|
|
|
|
|
(gpointer) clist);
|
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(button_hide_show_clicked),
|
|
|
|
|
(gpointer) clist);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(button_add);
|
|
|
|
|
gtk_widget_show(button_clear);
|
|
|
|
|
gtk_widget_show(button_hide_show);
|
|
|
|
|
|
|
|
|
|
/* Ahora hemos terminado el interface y s<>lo nos queda mostrar la
|
|
|
|
|
* ventana y entrar en el bucle gtk_main.
|
|
|
|
|
*/
|
|
|
|
|
gtk_widget_show(ventana);
|
|
|
|
|
gtk_main();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* El usuario puls<6C> el bot<6F>n "Add List". */
|
|
|
|
|
void button_add_clicked( GtkWidget *boton, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
int indx;
|
|
|
|
|
|
|
|
|
|
/* Algo tonto que a<>adir a la lista. 4 filas con 2 columnas cada
|
|
|
|
|
* una
|
|
|
|
|
*/
|
|
|
|
|
gchar *drink[4][2] = {{"Milk", "3 Oz"},
|
|
|
|
|
{"Water", "6 l"},
|
|
|
|
|
{"Carrots", "2"},
|
|
|
|
|
{"Snakes", "55"}};
|
|
|
|
|
|
|
|
|
|
/* Aqu<71> hacemos la adici<63>n del texto. Se hace una vez por cada
|
|
|
|
|
* fila.
|
|
|
|
|
*/
|
|
|
|
|
for( indx=0; indx < 4; indx++)
|
|
|
|
|
gtk_clist_append( (GtkCList*) data, drink[indx]);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* El usuario puls<6C> el bot<6F>n "Clear List" */
|
|
|
|
|
void button_clear_clicked( GtkWidget *boton, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
/* Borrar la lista utilizando gtk_clist_clear. Esto es mucho m<>s
|
|
|
|
|
* r<>pido que llamar a gtk_clist_remove una vez por cada fila.
|
|
|
|
|
*/
|
|
|
|
|
gtk_clist_clear((GtkCList*) data);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* El usuario puls<6C> el bot<6F>n "Hide/Show titles". */
|
|
|
|
|
void button_hide_show_clicked( GtkWidget *boton, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
/* Una bandera para recordar el estado. 0 = actualmente visible */
|
|
|
|
|
static short int flag = 0;
|
|
|
|
|
|
|
|
|
|
if (flag == 0)
|
|
|
|
|
{
|
|
|
|
|
/* Oculta los t<>tulos y pone la bandera a 1 */
|
|
|
|
|
gtk_clist_column_titles_hide((GtkCList*) data);
|
|
|
|
|
flag++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Muestra los t<>tulos y pone la bandera a 0 */
|
|
|
|
|
gtk_clist_column_titles_show((GtkCList*) data);
|
|
|
|
|
flag--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Se llegamos aqu<71>, entonces el usuario ha seleccionado una fila de
|
|
|
|
|
* la lista.
|
|
|
|
|
*/
|
|
|
|
|
void selection_made( GtkWidget *clist, gint row, gint column,
|
|
|
|
|
GdkEventButton *event, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gchar *text;
|
|
|
|
|
|
|
|
|
|
/* Obtiene el texto que se ha almacenado en la fila y columna
|
|
|
|
|
* sobre las que se ha pulsado. Lo recibiremos como un puntero en
|
|
|
|
|
* el argumento text.
|
|
|
|
|
*/
|
|
|
|
|
gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
|
|
|
|
|
|
|
|
|
|
/* Imprime alguna informaci<63>n sobre la fila seleccionada */
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> El <em>widget</em> <20>rbol<label id="sec_Tree_Widgets">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
El prop<6F>sito del <em>widget</em> GtkTree es mostrar datos organizados
|
|
|
|
|
de forma jer<65>rquica. El <em>widget</em> GtkTree en s<> es un contenedor
|
|
|
|
|
vertical para los <em>widgets</em> del tipo GtkTreeItem. GtkTree en
|
|
|
|
|
s<EFBFBD> mismo no es muy diferente de GtkList - ambos est<73>n derivados
|
|
|
|
|
directamente de GtkContainer, y los m<>todos GtkContainer funcionan
|
|
|
|
|
igual en los <em>widgets</em> GtkTree que en los GtkList. La
|
|
|
|
|
diferencia es que los <em>widgets</em> GtkTree pueden anidarse
|
|
|
|
|
dentro de otros <em>widgets</em> GtkTree. Vamos a verlo de forma
|
|
|
|
|
resumida.
|
|
|
|
|
|
|
|
|
|
El <em>widget</em> GtkTree tiene su propia ventana, y tiene por
|
|
|
|
|
defecto un fondo de color blanco, como GtkList. La mayor<6F>a de los
|
|
|
|
|
m<EFBFBD>todos de GtkTree funcionan igual que sus correspondientes de
|
|
|
|
|
GtkList. Sin embargo, GtkTree no est<73> derivado de GtkList, por lo que
|
|
|
|
|
no puede intercambiarlos.
|
|
|
|
|
|
|
|
|
|
<sect1> Creando un <20>rbol
|
|
|
|
|
<p>
|
|
|
|
|
Puede crear un GtkTree de la forma usual, utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_tree_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como el <em>widget</em> GtkList, un GtkTree crecer<65> cuando le a<>adan
|
|
|
|
|
elementos o cuando crezca alguno de sus sub<75>rboles. Por esta raz<61>n,
|
|
|
|
|
suelen venir dentro de una GtkScrolledWindow. Puede que quiera
|
|
|
|
|
utilizar <tt/gtk_widget_set_usize()/ con la ventana para asegurarse de
|
|
|
|
|
que es lo suficientemente grande como para poder ver todos los
|
|
|
|
|
elementos del <20>rbol, ya que el valor por defecto de GtkScrolledWindow
|
|
|
|
|
es bastante peque<75>o.
|
|
|
|
|
|
|
|
|
|
Ahora que ya sabemos como crear un <20>rbol, probablemente quiera
|
|
|
|
|
a<EFBFBD>adirle algunos elementos. <ref id="sec_Tree_Item_Widget" name="El
|
|
|
|
|
widget elemento de <20>rbol"> m<>s adelante explica todos los
|
|
|
|
|
detalles de GtkTreeItem. Por ahora, es suficiente con saber como crear
|
|
|
|
|
uno, utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_tree_item_new_with_label( gchar *etiqueta );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Puede a<>adirlo al <20>rbol utilizando una de las siguientes funciones
|
|
|
|
|
(ver <ref id="sec_GtkTree_Functions" name="Funciones y macros">
|
|
|
|
|
m<EFBFBD>s adelante para leer m<>s opciones):
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_append( GtkTree *arbol,
|
|
|
|
|
GtkWidget *elemento_arbol );
|
|
|
|
|
|
|
|
|
|
void gtk_tree_prepend( GtkTree *arbol,
|
|
|
|
|
GtkWidget *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Observe que debe a<>adir elementos a un GtkTree de uno en uno - no
|
|
|
|
|
hay un equivalente a <tt/gtk_list_*_items()/.
|
|
|
|
|
|
|
|
|
|
<sect1> A<>adiendo un Sub<75>rbol
|
|
|
|
|
<p>
|
|
|
|
|
Un sub<75>rbol se crea como cualquier otro <em>widget</em> GtkTree. Un
|
|
|
|
|
sub<EFBFBD>rbol se a<>ade a otro <20>rbol bajo un elemento del mismo, utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_item_set_subtree( GtkTreeItem *elemento_arbol,
|
|
|
|
|
GtkWidget *subarbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
No necesita llamar a <tt/gtk_widget_show()/ en un sub<75>rbol ni antes ni
|
|
|
|
|
despu<EFBFBD>s de a<>adirlo a GtkTreeItem. Sin embargo, <em>deber<65></em> haber
|
|
|
|
|
a<EFBFBD>adido el GtkTreeItem en cuesti<74>n a un <20>rbol padre antes de llamar a
|
|
|
|
|
<em/gtk_tree_item_set_subtree()/. Esto se debe a que, t<>cnicamente,
|
|
|
|
|
el padre del sub<75>rbol <em>no</em> es el GtkTreeItem <20>propietario<69>,
|
|
|
|
|
sino el GtkTree que contiene al GtkTreeItem.
|
|
|
|
|
|
|
|
|
|
Cuando le a<>ade un sub<75>rbol a un GtkTreeItem, aparece el signo de un
|
|
|
|
|
m<EFBFBD>s o de un menos a su lado, donde puede pinchar el usuario para
|
|
|
|
|
<EFBFBD>expandirlo<EFBFBD> u <20>contraerlo<6C>, o sea, para mostrar u ocultar su
|
|
|
|
|
sub<EFBFBD>rbol. Los GtkTreeItems est<73>n contra<72>dos por defecto. Observe que
|
|
|
|
|
cuando contrae un GtkTreeItem, cualquier elemento seleccionado en el
|
|
|
|
|
sub<EFBFBD>rbol permanece seleccionado, que puede no coincidir con lo que el
|
|
|
|
|
usuario espera.
|
|
|
|
|
|
|
|
|
|
<sect1> Manejando la lista de selecci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
Como con GtkList, GtkTree tiene un campo <tt>selection</tt>, y
|
|
|
|
|
es posible controlar el comportamiento del <20>rbol (de alguna manera)
|
|
|
|
|
estableciendo el tipo de selecci<63>n, utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_set_selection_mode( GtkTree *arbol,
|
|
|
|
|
GtkSelectionMode mode );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La sem<65>ntica asociada con los distintos modos de selecci<63>n est<73>
|
|
|
|
|
descrita en la secci<63>n del <em>widget</em> GtkList. Como ocurr<72>a con
|
|
|
|
|
el <em>widget</em> GtkList, se enviar<61>n las se<73>ales <tt/select_child/,
|
|
|
|
|
<tt/unselect_child/ (realmente no - ver <ref id="sec_GtkTree_Signals"
|
|
|
|
|
name="Se<53>ales"> m<>s adelante para una explicaci<63>n), y
|
|
|
|
|
<tt/selection_changed/ cuando los elementos de la lista sean
|
|
|
|
|
seleccionados o deseleccionados. Sin embargo, para aprovechar estas
|
|
|
|
|
se<EFBFBD>ales, necesita conocer por medio <em>de que</em> <em>widget</em>
|
|
|
|
|
GtkTree ser<65>n emitidas, y donde encontrar una lista con los elementos
|
|
|
|
|
seleccionados.
|
|
|
|
|
|
|
|
|
|
Todo esto es una potencial fuente de confusi<73>n. La mejor manera de
|
|
|
|
|
entenderlo es imaginarse que aunque todos los <em>widgets</em> GtkTree
|
|
|
|
|
son creados iguales, algunos son m<>s iguales que otros. Todos los
|
|
|
|
|
<em>widgets</em> GtkTree tienen su propia ventana X, y por tanto
|
|
|
|
|
pueden recibir eventos como pulsaciones de rat<61>n (<28>si sus hijos o
|
|
|
|
|
GtkTreeItems no las capturan primero!). Sin embargo, para hacer
|
|
|
|
|
que GTK_SELECTION_SINGLE y GTK_SELECTION_BROWSE funcionen bien, la
|
|
|
|
|
lista de elementos seleccionados debe ser espec<65>fica al <em>widget</em>
|
|
|
|
|
GtkTree superior de la jerarquia, conocido como el <20><>rbol ra<72>z<EFBFBD>.
|
|
|
|
|
|
|
|
|
|
Por tanto no es una buena idea acceder al campo <tt>selection</tt>
|
|
|
|
|
directamente en un <em>widget</em> GtkTree arbitrario, a menos que
|
|
|
|
|
<em>sepa</em> que es el <20>rbol ra<72>z. En vez de eso, utilice la
|
|
|
|
|
macro GTK_TREE_SELECTION (arbol), que da la lista selecci<63>n del <20>rbol
|
|
|
|
|
ra<EFBFBD>z como un puntero <tt/GList/. Por supuesto, esta lista puede
|
|
|
|
|
incluir elementos que no est<73>n en el sub<75>rbol en cuesti<74>n si el tipo
|
|
|
|
|
de selecci<63>n es GTK_SELECTION_MULTIPLE.
|
|
|
|
|
|
|
|
|
|
Para terminar, las se<73>ales <tt/select_child/ (y tt/unselect_child/, en
|
|
|
|
|
teor<EFBFBD>a) son emitidas por todos los <20>rboles, pero la se<73>al
|
|
|
|
|
<em/selection_changed/ es emitida s<>lo por el <20>rbol ra<72>z. En
|
|
|
|
|
consecuencia, si quiere manipular la se<73>al <tt/select_child/ de un
|
|
|
|
|
<EFBFBD>rbol y todos sus sub<75>rboles, tendr<64> que llamar a
|
|
|
|
|
<tt/gtk_signal_connect()/ una vez por cada sub<75>rbol.
|
|
|
|
|
|
|
|
|
|
<sect1> Estructura interna del <em>widget</em> <20>rbol
|
|
|
|
|
<p>
|
|
|
|
|
La definici<63>n de la estructura GtkTree es ls siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GtkTree
|
|
|
|
|
{
|
|
|
|
|
GtkContainer container;
|
|
|
|
|
|
|
|
|
|
GList *child;
|
|
|
|
|
|
|
|
|
|
GtkTree* root_tree; /* propietario de la lista de selecci<63>n */
|
|
|
|
|
GtkWidget* tree_owner;
|
|
|
|
|
GList *selection;
|
|
|
|
|
guint level;
|
|
|
|
|
guint indent_value;
|
|
|
|
|
guint current_indent;
|
|
|
|
|
guint selection_mode : 2;
|
|
|
|
|
guint view_mode : 1;
|
|
|
|
|
guint view_line : 1;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Ya se han mencionado los peligros asociados con el acceso directo al
|
|
|
|
|
campo <tt>selection</tt>. Se puede acceder a los otros campos
|
|
|
|
|
importantes de la estructura mediante macros manipuladoras o
|
|
|
|
|
funciones de clase. GTK_TREE_IS_ROOT_TREE (arbol) devuelve un valor
|
|
|
|
|
booleano que indica si un <20>rbol es <20>rbol ra<72>z de una jerarquia
|
|
|
|
|
GtkTree, mientras que GTK_TREE_ROOT_TREE (arbol) devuelve el <20>rbol
|
|
|
|
|
ra<EFBFBD>z, un objeto de tipo GtkTree (recuerde transformarlo utilizando
|
|
|
|
|
GTK_WIDGET (arbol) si quiere utilizar con <20>l alguna de la funciones
|
|
|
|
|
<tt/gtk_widget_*()/).
|
|
|
|
|
|
|
|
|
|
En lugar de acceder directamente al campo hijo de un <em>widget</em>
|
|
|
|
|
GtkTree, probablemente sea mejor transformarlo utilizando
|
|
|
|
|
GTK_CONTAINER (arbol), y pas<61>rselo a la funci<63>n
|
|
|
|
|
<tt/gtk_container_children()/. Con esto crearemos un duplicado de la
|
|
|
|
|
lista original, por lo que deber<65> eliminarlo de la memoria utilizando
|
|
|
|
|
<tt/g_list_free()/ despu<70>s haber hecho con <20>l lo que tenga que hacer,
|
|
|
|
|
o bien crear un bucle que lo vaya destruyendo de elemento en elemento,
|
|
|
|
|
como por ejemplo as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
hijo = gtk_container_children (GTK_CONTAINER (arbol));
|
|
|
|
|
while (hijo) {
|
|
|
|
|
do_something_nice (GTK_TREE_ITEM (hijo->data));
|
|
|
|
|
hijo = g_list_remove_link (hijo, hijo);
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El campo <tt>tree_owner</tt> s<>lo est<73> definido en sub<75>rboles, donde
|
|
|
|
|
apunta al <em>widget</em> GtkTreeItem que contiene al <20>rbol en
|
|
|
|
|
cuesti<EFBFBD>n. El campo <tt>level</tt> indica el nivel de profundidad de un
|
|
|
|
|
<EFBFBD>rbol en particular; los <20>rboles ra<72>z tienen un nivel 0, y cada nivel
|
|
|
|
|
sucesivo de sub<75>rboles tiene un nivel superior al del padre. S<>lo se
|
|
|
|
|
puede asegurar que este campo contiene un valor correcto despu<70>s de
|
|
|
|
|
que el <em>widget</em> GtkTree se dibuje en la pantalla.
|
|
|
|
|
|
|
|
|
|
<sect2> Se<53>ales<label id="sec_GtkTree_Signals">
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void selection_changed( GtkTree *arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta se<73>al se emitir<69> cuando cambie el campo <tt>selection</tt> de
|
|
|
|
|
un GtkTree. Esto ocurre cuando se selecciona o deselecciona un hijo del
|
|
|
|
|
GtkTree.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void select_child( GtkTree *arbol,
|
|
|
|
|
GtkWidget *hijo );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta se<73>al se emite cuando se est<73> seleccionando un hijo del GtkTree.
|
|
|
|
|
Esto ocurre en las llamadas a <tt/gtk_tree_select_item()/,
|
|
|
|
|
<tt/gtk_tree_select_child()/, en <em>todas</em> las pulsaciones de
|
|
|
|
|
bot<EFBFBD>n y llamadas a <tt/gtk_tree_item_toggle()/ y
|
|
|
|
|
<tt/gtk_item_toggle()/. Puede que a veces se invoque indirectamente en
|
|
|
|
|
otras ocasiones, cuando el hijo se a<>ada o elimine del GtkTree.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void unselect_child (GtkTree *arbol,
|
|
|
|
|
GtkWidget *hijo);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta se<73>al se emite cuando se deselecciona un hijo del GtkTree. Con
|
|
|
|
|
GTK+ 1.0.4, esto s<>lo parece ocurrir en las llamadas a
|
|
|
|
|
<tt/gtk_tree_unselect_item()/ o a <tt/gtk_tree_unselect_child()/, y quiz<69>s
|
|
|
|
|
en otras ocasiones, pero <em>no</em> cuando la pulsaci<63>n de un bot<6F>n
|
|
|
|
|
deselecciona un hijo, y tampoco por la emisi<73>n de la se<73>al <20>toggle<6C>
|
|
|
|
|
por <tt/gtk_item_toggle()/.
|
|
|
|
|
|
|
|
|
|
<sect2> Funciones y macros<label id="sec_GtkTree_Functions">
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_tree_get_type( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Devuelve el identificador de tipo de `GtkTree'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_tree_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Crea un nuevo objeto GtkTree. El nuevo <em>widget</em> se devuelve como
|
|
|
|
|
un puntero a un objeto GtkWidget. Se devolver<65> NULL si se produce alg<6C>n
|
|
|
|
|
error.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_append( GtkTree *arbol,
|
|
|
|
|
GtkWidget *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
A<EFBFBD>ade un <20>rbol a un GtkTree.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_prepend( GtkTree *arbol,
|
|
|
|
|
GtkWidget *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Prea<EFBFBD>ade un <20>rbol a un GtkTree.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_insert( GtkTree *arbol,
|
|
|
|
|
GtkWidget *elemento_arbol,
|
|
|
|
|
gint posicion );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Inserta un <20>rbol en un GtkTree en la posici<63>n de la lista especificada
|
|
|
|
|
por <tt>posicion.</tt>
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_remove_items( GtkTree *arbol,
|
|
|
|
|
GList *items );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Elimina una lista de elementos (en forma de una <tt/GList */) de un
|
|
|
|
|
GtkTree. Eliminar un elemento de un <20>rbol lo dereferencia (y por tanto
|
|
|
|
|
normalmente) lo destruye (""), a <20>l <em>y</em> a su sub<75>rbol, de
|
|
|
|
|
haberlo, <em>y</em> a todos los sub<75>rboles que contenga ese
|
|
|
|
|
sub<EFBFBD>rbol. Si quiere eliminar s<>lo un elemento, deber<65> utilizar
|
|
|
|
|
<tt/gtk_container_remove()/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_clear_items( GtkTree *arbol,
|
|
|
|
|
gint start,
|
|
|
|
|
gint end );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Elimina los elementos de un GtkTree desde la posici<63>n <tt>start</tt>
|
|
|
|
|
hasta la posici<63>n <tt>end</tt>. De nuevo hay que llevarse cuidado
|
|
|
|
|
con donde se aplica la dereferencia, ya que <tt/gtk_tree_clear_items()/
|
|
|
|
|
simplemente construye una lista y se la pasa a
|
|
|
|
|
<tt/gtk_tree_remove_items()/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_select_item( GtkTree *arbol,
|
|
|
|
|
gint item );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Emite la se<73>al <tt/select_item/ para el hijo que se encuentra en la
|
|
|
|
|
posici<EFBFBD>n <tt>item</tt>, y por tanto selecciona a ese hijo (a menos que
|
|
|
|
|
lo deseleccione en un manejador de se<73>al...)
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_unselect_item( GtkTree *arbol,
|
|
|
|
|
gint item );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Emite la se<73>al <tt/unselect_item/ para el hijo en la posici<63>n
|
|
|
|
|
<tt>item</tt>, y por tanto deselecciona al hijo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_select_child( GtkTree *arbol,
|
|
|
|
|
GtkWidget *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Emite la se<73>al <tt/select_item/ para el hijo <tt>elemento_arbol</tt>, y por tanto
|
|
|
|
|
lo selecciona.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_unselect_child( GtkTree *arbol,
|
|
|
|
|
GtkWidget *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Emite la se<73>al <tt/unselect_item/ para el hijo <tt>elemento_arbol</tt>, y por
|
|
|
|
|
tanto lo deselecciona.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_tree_child_position( GtkTree *arbol,
|
|
|
|
|
GtkWidget *hijo );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Devuelve la posici<63>n en el <20>rbol de <tt>child</tt>, a menos que
|
|
|
|
|
<tt>child</tt> no est<73> en el <20>rbol, en cuya caso devuelve -1.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_set_selection_mode( GtkTree *arbol,
|
|
|
|
|
GtkSelectionMode mode );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Establece el modo de selecci<63>n, que puede ser uno de los siguientes
|
|
|
|
|
GTK_SELECTION_SINGLE (por defecto), GTK_SELECTION_BROWSE,
|
|
|
|
|
GTK_SELECTION_MULTIPLE, o GTK_SELECTION_EXTENDED. Esto s<>lo est<73>
|
|
|
|
|
definido para los <20>rboles ra<72>z, que es donde tiene sentido, ya que el
|
|
|
|
|
<EFBFBD>rbol ra<72>z es el <20>propietario<69> de la selecci<63>n. Establecer este
|
|
|
|
|
valor en un sub<75>rbol no tiene ning<6E>n efecto en absoluto; el valor
|
|
|
|
|
simplemente ser<65> ignorado.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_set_view_mode( GtkTree *arbol,
|
|
|
|
|
GtkTreeViewMode mode );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Establece el <20>modo de visi<73>n<EFBFBD>, que puede ser o GTK_TREE_VIEW_LINE
|
|
|
|
|
(por defecto) o GTK_TREE_VIEW_ITEM. El modo de visi<73>n se propaga
|
|
|
|
|
de un <20>rbol a sus sub<75>rboles, y no puede establecerse en exclusiva
|
|
|
|
|
para un sub<75>rbol (esto no es exacto del todo - vea los comentarios en el
|
|
|
|
|
c<EFBFBD>digo de ejemplo).
|
|
|
|
|
|
|
|
|
|
El termino <20>modo de visi<73>n<EFBFBD> es algo ambiguo - b<>sicamente, controla
|
|
|
|
|
la forma en que se resalta a uno de los hijos del <20>rbol cuando es
|
|
|
|
|
seleccionado. Si es GTK_TREE_VIEW_LINE, se resaltar<61> el
|
|
|
|
|
<em>widget</em> GtkTreeItem completo, mientras que si es
|
|
|
|
|
GTK_TREE_VIEW_ITEM, s<>lo se resaltar<61> el <em>widget</em> hijo (es
|
|
|
|
|
decir, lo que normalmente es la etiqueta).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_set_view_lines( GtkTree *arbol,
|
|
|
|
|
guint flag );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Controla si se dibujar<61>n las l<>neas de conexi<78>n entre los elementos
|
|
|
|
|
del <20>rbol. <tt>flag</tt> es o TRUE, en cuyo caso se dibujar<61>n, o
|
|
|
|
|
FALSE, en cuyo caso no se dibujar<61>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkTree *GTK_TREE (gpointer obj);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Convierte un puntero gen<65>rico a `GtkTree *'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkTreeClass *GTK_TREE_CLASS (gpointer class);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Convierte un puntero gen<65>rico a `GtkTreeClass *'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint GTK_IS_TREE (gpointer obj);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Determina si un puntero gen<65>rico se refiere a un objeto `GtkTree'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint GTK_IS_ROOT_TREE (gpointer obj)
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Determina si un puntero gen<65>rico se refiere a un objeto `GtkTree'
|
|
|
|
|
<em>y</em> es un <20>rbol ra<72>z. Aunque la funci<63>n acepta cualquier
|
|
|
|
|
puntero, los resultados de pasarle un puntero que no se refiera
|
|
|
|
|
a un GtkTree no est<73>n definidos y probablemente no tengan ning<6E>n
|
|
|
|
|
sentido.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Devuelve el <20>rbol ra<72>z de un puntero a un objeto `GtkTree'. Seguimos
|
|
|
|
|
con el mismo problema que en el caso anterior.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GList *GTK_TREE_SELECTION(gpointer obj)
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Devuelve la lista de selecci<63>n del <20>rbol ra<72>z de un objeto
|
|
|
|
|
`GtkTree'. Seguimos con el mismo problema que antes.
|
|
|
|
|
|
|
|
|
|
<sect1> El <em>widget</em> elemento de <20>rbol<label id="sec_Tree_Item_Widget">
|
|
|
|
|
<p>
|
|
|
|
|
El <em>widget</em> GtkTreeItem, c<>mo el GtkListItem, est<73> derivado
|
|
|
|
|
de GtkItem, que de nuevo, est<73> derivado de GtkBin. Sin embargo, el
|
|
|
|
|
elemento en s<> mismo es un contenedor gen<65>rico que contiene un
|
|
|
|
|
<em>widget</em> hijo, que puede ser de cualquier tipo. El <em>widget</em>
|
|
|
|
|
GtkTreeItem tiene ciertos campos extra, pero el <20>nico que nos
|
|
|
|
|
interesa ahora es el campo <em>sub<75>rbol</em>.
|
|
|
|
|
|
|
|
|
|
La definici<63>n de la estructura GtkTreeItem es as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GtkTreeItem
|
|
|
|
|
{
|
|
|
|
|
GtkItem item;
|
|
|
|
|
|
|
|
|
|
GtkWidget *subtree;
|
|
|
|
|
GtkWidget *pixmaps_box;
|
|
|
|
|
GtkWidget *plus_pix_widget, *minus_pix_widget;
|
|
|
|
|
|
|
|
|
|
GList *pixmaps /* nodo pixmap para esta profundidad de color */
|
|
|
|
|
|
|
|
|
|
guint expanded : 1;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El campo <tt>pixmaps_box</tt> es un GtkEventBox que caza las pulsaciones
|
|
|
|
|
en el s<>mbolo m<>s/menos que controla la expansi<73>n y contracci<63>n. El
|
|
|
|
|
campo <tt>pixmaps</tt> apunta a una estructura de datos interna. Ya que
|
|
|
|
|
siempre puede obtener el sub<75>rbol de un GtkTreeItem de una forma
|
|
|
|
|
(relativamente) segura mediante la macro GTK_TREE_ITEM_SUBTREE (Item),
|
|
|
|
|
es aconsejable no tocar las tripas de un GtkTreeItem a menos que
|
|
|
|
|
<em>realmente</em> sepa que es lo que est<73> haciendo.
|
|
|
|
|
|
|
|
|
|
Ya que est<73> derivado directamente de un GtkItem, puede tratarse como
|
|
|
|
|
tal utilizando la macro GTK_ITEM (ElementoArbol). Un GtkTreeItem normalmente
|
|
|
|
|
tiene una etiqueta, por lo que tenemos a nuestra disposici<63>n la
|
|
|
|
|
funci<EFBFBD>n gtk_list_item_new_with_label(). Podemos conseguir el mismo
|
|
|
|
|
efecto utilizando c<>digo como el siguiente, que por ahora es s<>lo
|
|
|
|
|
una copia de la funci<63>n gtk_tree_item_new_with_label():
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
elemento_arbol = gtk_tree_item_new ();
|
|
|
|
|
etiqueta_widget = gtk_label_new (etiqueta);
|
|
|
|
|
gtk_misc_set_alignment (GTK_MISC (etiqueta_widget), 0.0, 0.5);
|
|
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (elemento_arbol), etiqueta_widget);
|
|
|
|
|
gtk_widget_show (etiqueta_widget);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
C<EFBFBD>mo no es obligatorio a<>adir una GtkLabel a un GtkTreeItem, puede
|
|
|
|
|
tambi<EFBFBD>n a<>adirle un GtkHBox o una GtkArrow, o hasta un GtkNotebook
|
|
|
|
|
(aunque en esos casos su aplicaci<63>n no ser<65> muy popular).
|
|
|
|
|
|
|
|
|
|
Si elimina todos los elementos de un sub<75>rbol, ser<65> destruido
|
|
|
|
|
y se eliminar<61> la informaci<63>n sobre su padre, a menos que lo
|
|
|
|
|
referencie de antemano, adem<65>s el GtkTreeItem que sea su propietario
|
|
|
|
|
se colapsar<61>. Por lo tanto, si quiere que se mantenga el sub<75>rbol
|
|
|
|
|
tendr<EFBFBD> que hacer algo as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_widget_ref (arbol);
|
|
|
|
|
propietario = GTK_TREE(arbol)->tree_owner;
|
|
|
|
|
gtk_container_remove (GTK_CONTAINER(arbol), item);
|
|
|
|
|
if (arbol->parent == NULL){
|
|
|
|
|
gtk_tree_item_expand (GTK_TREE_ITEM(propietario));
|
|
|
|
|
gtk_tree_item_set_subtree (GTK_TREE_ITEM(propietario), arbol);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
gtk_widget_unref (arbol);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Finalmente, hay que mencionar que la opci<63>n de drag-n-drop (arrastar y
|
|
|
|
|
soltar) <em>funciona</em> con los GtkTreeItems. S<>lo tiene que
|
|
|
|
|
asegurarse de que el GtkTreeItem que quiere convertir en un elemento
|
|
|
|
|
de arrastre o en un lugar en el que, adem<65>s de haber sido a<>adido a
|
|
|
|
|
GtkTree, sino que adem<65>s cada su <em>widget</em> padre tiene a su vez
|
|
|
|
|
un padre, y as<61> hasta llegar al nivel m<>s alto o ventana de di<64>logo,
|
|
|
|
|
cuando llamamos a <tt/gtk_widget_dnd_drag_set()/ o
|
|
|
|
|
<tt/gtk_widget_dnd_drop_set()/. En caso contrario, podr<64>an ocurrir
|
|
|
|
|
cosas extra<72>as.
|
|
|
|
|
|
|
|
|
|
<sect2> Se<53>ales
|
|
|
|
|
<p>
|
|
|
|
|
GtkTreeItem hereda las se<73>ales <tt/select/, <tt/deselect/, y
|
|
|
|
|
<tt/toggle/ de GtkItem. Adem<65>s, a<>ade dos se<73>ales propias, <tt/expand/
|
|
|
|
|
y <tt/collapse/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void select( GtkItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta se<73>al se emite cuando un elemento est<73> siendo seleccionado,
|
|
|
|
|
o bien despu<70>s de que el usuario pinche en <20>l, o bien cuando
|
|
|
|
|
el programa llame a <tt/gtk_tree_item_select()/,
|
|
|
|
|
<tt/gtk_item_select()/, o a <tt/gtk_tree_select_child()/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void deselect( GtkItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta se<73>al se emite cuando un elemento est<73> siendo deseleccionado,
|
|
|
|
|
o bien despu<70>s de que el usuario pinche en <20>l, o bien cuando
|
|
|
|
|
el programa llame a <tt/gtk_tree_item_deselect()/ o a
|
|
|
|
|
<tt/gtk_item_deselect()/. En el caso de GtkTreeItems, tambi<62>n se
|
|
|
|
|
emitir<EFBFBD> por <tt/gtk_tree_unselect_child()/, y a veces por
|
|
|
|
|
<tt/gtk_tree_select_child()/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void toggle( GtkItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta se<73>al se emite cuando el programa llama a <tt/gtk_item_toggle()/. El
|
|
|
|
|
efecto que tiene cuando se emite en un GtkTreeItem es llamar a
|
|
|
|
|
<tt/gtk_tree_select_child()/ (y nunca a
|
|
|
|
|
<tt/gtk_tree_unselect_child()/) en el <20>rbol padre del elemento, si el
|
|
|
|
|
elemento tiene un <20>rbol padre. Si no lo tiene, entonces se cambiar<61> el
|
|
|
|
|
resaltado del elemento.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void expand( GtkTreeItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta se<73>al se emite cuando se est<73> expandiendo el sub<75>rbol del
|
|
|
|
|
elemento, esto es, cuando el usuario pincha en el signo m<>s que
|
|
|
|
|
hay al lado del elemento, o cuando el programa llama a
|
|
|
|
|
<tt/gtk_tree_item_expand()/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void collapse( GtkTreeItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta se<73>al se emite cuando se est<73> contrayendo el sub<75>rbol del
|
|
|
|
|
elemento, esto es, cuando el usuario pincha en el signo menos que hay
|
|
|
|
|
al lado del elemento, o cuando el programa llama a
|
|
|
|
|
<tt/gtk_tree_item_collapse()/.
|
|
|
|
|
|
|
|
|
|
<sect2> Funciones y Macros
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_tree_item_get_type( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Devuelve el identificador de tipo de `GtkTreeItem'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_tree_item_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Crea un nuevo objeto GtkTreeItem. El nuevo <em>widget</em> se devuelve
|
|
|
|
|
como un puntero a un objeto GtkWidget. Se devolver<65> NULL si hay alg<6C>n
|
|
|
|
|
fallo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_tree_item_new_with_label (gchar *etiqueta);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Crea un nuevo objeto GtkTreeItem, teniendo una simple GtkLabel
|
|
|
|
|
como <20>nico hijo. El nuevo <em>widget</em> se devolver<65> como
|
|
|
|
|
un puntero a un objeto GtkWidget. Se devolver<65> NULL en caso
|
|
|
|
|
de haber alg<6C>n fallo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_item_select( GtkTreeItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n es b<>sicamente un recubrimiento de una llamada a
|
|
|
|
|
gtk_item_select (GTK_ITEM (elemento_arbol)) que emitir<69> la
|
|
|
|
|
se<EFBFBD>al select.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_item_deselect( GtkTreeItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n es b<>sicamente un recubrimiento de una llamada a
|
|
|
|
|
gtk_item_deselect (GTK_ITEM (elemento_arbol)) que emitir<69> la
|
|
|
|
|
se<EFBFBD>al deselect.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_item_set_subtree( GtkTreeItem *elemento_arbol,
|
|
|
|
|
GtkWidget *subarbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n a<>ade <tt/subarbol/ a <tt/elemento_arbol/, mostr<74>ndolo si
|
|
|
|
|
<tt/elemento_arbol/ est<73> expandido, u ocult<6C>ndolo si <tt/elemento_arbol/ est<73>
|
|
|
|
|
contra<EFBFBD>do. De nuevo, recuerde que el <tt/elemento_arbol/ ya debe de haber
|
|
|
|
|
sido a<>adido a un <20>rbol para que esto funcione.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_item_remove_subtree( GtkTreeItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esto elimina todos los hijos de los sub<75>rboles del <tt/elemento_arbol/
|
|
|
|
|
(esto es, dereferencia y destruye a los sub<75>rboles hijos, y a los
|
|
|
|
|
hijos de los hijos y...), entonces elimina el sub<75>rbol en si mismo, y
|
|
|
|
|
oculta el signo m<>s/menos.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_item_expand( GtkTreeItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esto emite la se<73>al <20>expand<6E> para el <tt/elemento_arbol/, que lo
|
|
|
|
|
expande.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_tree_item_collapse( GtkTreeItem *elemento_arbol );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esto emite la se<73>al <20>collapse<73> en el <tt/elemento_arbol/, que lo
|
|
|
|
|
contrae.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Convierte un puntero gen<65>rico en un `GtkTreeItem *'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Convierte un puntero gen<65>rico en un `GtkTreeItemClass'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint GTK_IS_TREE_ITEM (gpointer obj)
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Determina si un puntero gen<65>rico se refiere a un objeto `GtkTreeItem'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Devuelve un sub<75>rbol del elemento (<tt/obj/ deber<65>a apuntar a un
|
|
|
|
|
objeto `GtkTreeItem').
|
|
|
|
|
|
|
|
|
|
<sect1> <20>rbol ejemplo
|
|
|
|
|
<p>
|
|
|
|
|
Este ejemplo es muy parecido al <20>rbol ejemplo que hay en
|
|
|
|
|
<tt/testgtk.c/, pero mucho menos completo (aunque mucho mejor
|
|
|
|
|
comentado). Pone una ventana con un <20>rbol, y conecta todas las se<73>ales
|
|
|
|
|
de los objetos relevantes, con lo que podr<64> ver cuando se emiten.
|
|
|
|
|
|
|
|
|
|
<!-- Hay un comentario en el c<>digo que no se traducir -->
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo tree tree.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* para todas las se<73>ales GtkItem:: y GtkTreeItem:: */
|
|
|
|
|
static void cb_itemsignal (GtkWidget *item, gchar *signame)
|
|
|
|
|
{
|
|
|
|
|
gchar *name;
|
|
|
|
|
GtkLabel *etiqueta;
|
|
|
|
|
|
|
|
|
|
/* Es un GtkBin, por lo que tiene un hijo, que sabemos que es una
|
|
|
|
|
* etiqueta, por lo que la cogemos */
|
|
|
|
|
etiqueta = GTK_LABEL (GTK_BIN (item)->child);
|
|
|
|
|
/* Conseguimos el texto de la etiqueta */
|
|
|
|
|
gtk_label_get (etiqueta, &name);
|
|
|
|
|
/* Conseguimos el nivel del <20>rbol en el que se encuentra el elemento */
|
|
|
|
|
g_print ("%s called for item %s->%p, level %d\n", signame, name,
|
|
|
|
|
item, GTK_TREE (item->parent)->level);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* nunca se llamar<61> a esta funci<63>n */
|
|
|
|
|
static void cb_unselect_child (GtkWidget *arbol_raiz, GtkWidget *hijo,
|
|
|
|
|
GtkWidget *subarbol)
|
|
|
|
|
{
|
|
|
|
|
g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
|
|
|
|
|
arbol_raiz, subarbol, hijo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Se llamar<61> a esta funci<63>n cada vez que el usuario pulse en un
|
|
|
|
|
* elemento, est<73> o no seleccionado. */
|
|
|
|
|
whether it is already selected or not. */
|
|
|
|
|
static void cb_select_child (GtkWidget *arbol_raiz, GtkWidget *hijo,
|
|
|
|
|
GtkWidget *subarbol)
|
|
|
|
|
{
|
|
|
|
|
g_print ("select_child called for root tree %p, subtree %p, child %p\n",
|
|
|
|
|
arbol_raiz, subarbol, hijo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void cb_selection_changed (GtkWidget *arbol)
|
|
|
|
|
{
|
|
|
|
|
GList *i;
|
|
|
|
|
|
|
|
|
|
g_print ("selection_change called for tree %p\n", arbol);
|
|
|
|
|
g_print ("selected objects are:\n");
|
|
|
|
|
|
|
|
|
|
i = GTK_TREE_SELECTION(arbol);
|
|
|
|
|
while (i){
|
|
|
|
|
gchar *name;
|
|
|
|
|
GtkLabel *etiqueta;
|
|
|
|
|
GtkWidget *item;
|
|
|
|
|
|
|
|
|
|
/* Get a GtkWidget pointer from the list node */
|
|
|
|
|
item = GTK_WIDGET (i->data);
|
|
|
|
|
etiqueta = GTK_LABEL (GTK_BIN (item)->child);
|
|
|
|
|
gtk_label_get (etiqueta, &name);
|
|
|
|
|
g_print ("\t%s on level %d\n", name, GTK_TREE
|
|
|
|
|
(item->parent)->level);
|
|
|
|
|
i = i->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana, *scrolled_win, *arbol;
|
|
|
|
|
static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
|
|
|
|
|
"Maurice"};
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* una ventana general */
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(ventana), "delete_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER(ventana), 5);
|
|
|
|
|
|
|
|
|
|
/* una ventana con barras de desplazamiento */
|
|
|
|
|
scrolled_win = gtk_scrolled_window_new (NULL, NULL);
|
|
|
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
|
|
|
|
|
GTK_POLICY_AUTOMATIC,
|
|
|
|
|
GTK_POLICY_AUTOMATIC);
|
|
|
|
|
gtk_widget_set_usize (scrolled_win, 150, 200);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(ventana), scrolled_win);
|
|
|
|
|
gtk_widget_show (scrolled_win);
|
|
|
|
|
|
|
|
|
|
/* Crear el <20>rbol ra<72>z */
|
|
|
|
|
arbol = gtk_tree_new();
|
|
|
|
|
g_print ("root tree is %p\n", arbol);
|
|
|
|
|
/* connect all GtkTree:: signals */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(arbol), "select_child",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_select_child), arbol);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(arbol), "unselect_child",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_unselect_child), arbol);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(arbol), "selection_changed",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_selection_changed), arbol);
|
|
|
|
|
/* A<>adirlo a la ventana con barras de desplazamiento */
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(scrolled_win), arbol);
|
|
|
|
|
/* Poner el modo de selecci<63>n */
|
|
|
|
|
gtk_tree_set_selection_mode (GTK_TREE(arbol),
|
|
|
|
|
GTK_SELECTION_MULTIPLE);
|
|
|
|
|
/* mostrar el <20>rbol */
|
|
|
|
|
gtk_widget_show (arbol);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 5; i++){
|
|
|
|
|
GtkWidget *subarbol, *item;
|
|
|
|
|
gint j;
|
|
|
|
|
|
|
|
|
|
/* Crear un elemento del <20>rbol */
|
|
|
|
|
item = gtk_tree_item_new_with_label (itemnames[i]);
|
|
|
|
|
/* Conectar todas las se<73>ales GtkItem:: y GtkTreeItem:: */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(item), "select",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "select");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(item), "deselect",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(item), "toggle",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(item), "expand",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(item), "collapse",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
|
|
|
|
|
/* A<>adirlo al <20>rbol padre */
|
|
|
|
|
gtk_tree_append (GTK_TREE(arbol), item);
|
|
|
|
|
/* Mostrarlo - esto se puede hacer en cualquier momento */
|
|
|
|
|
gtk_widget_show (item);
|
|
|
|
|
/* Crear el sub<75>rbol de este elemento */
|
|
|
|
|
subarbol = gtk_tree_new();
|
|
|
|
|
g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
|
|
|
|
|
subarbol);
|
|
|
|
|
|
|
|
|
|
/* Esto todav<61>a es necesario si quiere que se llamen a est<73>n
|
|
|
|
|
* se<73>ales en el sub<75>rbol hijo. Note that selection_change will
|
|
|
|
|
* be signalled for the root tree regardless. */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(subarbol), "select_child",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_select_child), subarbol);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(subarbol), "unselect_child",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_unselect_child), subarbol);
|
|
|
|
|
/* Esto no tiene absolutamente ning<6E>n efecto, ya que se ignora
|
|
|
|
|
* completamente en los sub<75>rboles */
|
|
|
|
|
gtk_tree_set_selection_mode (GTK_TREE(subarbol),
|
|
|
|
|
GTK_SELECTION_SINGLE);
|
|
|
|
|
/* Esto tampoco hace nada, pero por una raz<61>n diferente - los
|
|
|
|
|
* valores view_mode y view_line de un <20>rbol se propagan a los
|
|
|
|
|
* sub<75>rboles cuando son mapeados. Por tanto, establecer los
|
|
|
|
|
* valores despu<70>s actualmente tendr<64>a (alg<6C>n impredecible) efecto
|
|
|
|
|
*/
|
|
|
|
|
gtk_tree_set_view_mode (GTK_TREE(subarbol), GTK_TREE_VIEW_ITEM);
|
|
|
|
|
/* Establecer este sub<75>rbol del elemento - <20>Recuerde que no puede
|
|
|
|
|
* hacerlo hasta que se haya a<>adido a su <20>rbol padre! */
|
|
|
|
|
gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subarbol);
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < 5; j++){
|
|
|
|
|
GtkWidget *subitem;
|
|
|
|
|
|
|
|
|
|
/* Crea un elemento sub<75>rbol, m<>s o menos lo mismo de antes */
|
|
|
|
|
subitem = gtk_tree_item_new_with_label (itemnames[j]);
|
|
|
|
|
/* Conectar todas las se<73>ales GtkItem:: y GtkTreeItem:: */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(subitem), "select",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "select");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(subitem), "expand",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
|
|
|
|
|
GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
|
|
|
|
|
g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
|
|
|
|
|
/* A<>adirlo a su <20>rbol padre */
|
|
|
|
|
gtk_tree_append (GTK_TREE(subarbol), subitem);
|
|
|
|
|
/* Mostrarlo */
|
|
|
|
|
gtk_widget_show (subitem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Mostrar la ventana y entrar en el bucle final */
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
gtk_main();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> El <em>widget</em> men<65>
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
Hay dos formas de crear men<65>s, la f<>cil, y la dif<69>cil. Ambas tienen su
|
|
|
|
|
utilidad, aunque lo m<>s probable es que normalmente utilice la
|
|
|
|
|
menufactory (la forma f<>cil). La forma <20>dif<69>cil<69> consiste en crear
|
|
|
|
|
todos los men<65>s utilizando las llamadas directamente. La forma f<>cil
|
|
|
|
|
consiste en utilizar las llamadas de <tt/gtk_item_factory/. Es mucho
|
|
|
|
|
m<EFBFBD>s f<>cil, pero aun as<61> cada aproximaci<63>n tiene sus ventajas y sus
|
|
|
|
|
inconvenientes.
|
|
|
|
|
|
|
|
|
|
La menufactory es mucho m<>s f<>cil de utilizar, y tamb<6D>en es m<>s f<>cil
|
|
|
|
|
a<EFBFBD>adir nuevos men<65>s, aunque a larga, escribiendo unas cu<63>ntas
|
|
|
|
|
funciones de recubrimiento para crear men<65>s utilizando el m<>todo
|
|
|
|
|
manual puede acabar siendo m<>s <20>til. Con la itemfactory, no es posible
|
|
|
|
|
a<EFBFBD>adir im<69>genes o el car<61>cter `/' a los men<65>s.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Creaci<63>n manual de men<65>s
|
|
|
|
|
<p>
|
|
|
|
|
Siguiendo la aut<75>ntica tradici<63>n de la ense<73>anza, vamos a ense<73>arle
|
|
|
|
|
primero la forma dif<69>cil. <tt>:)</tt>
|
|
|
|
|
|
|
|
|
|
Se utilizan tres <em>widgets</em> para hacer una barra de men<65>s y
|
|
|
|
|
submen<EFBFBD>s:
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>un elemento del men<65>, que es lo que el usuario quiere seleccionar,
|
|
|
|
|
p.e. 'Guardar'
|
|
|
|
|
<item>un men<65>, que actua como un contenedor para los elementos del men<65>, y
|
|
|
|
|
<item>una barra de men<65>, que es un contenedor para cada uno de los men<65>s,
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Todo esto se complica ligeramente por el hecho de que los
|
|
|
|
|
<em>widgets</em> de los elementos del men<65> se utilizan para dos cosas
|
|
|
|
|
diferentes. Est<73>n los <em>widgets</em> que se empaquetan en el men<65>, y
|
|
|
|
|
los que se empaquetan en una barra de men<65>s, que cuando se selecciona,
|
|
|
|
|
activa el men<65>.
|
|
|
|
|
|
|
|
|
|
Vamos a ver las funciones que se utilizan para crear men<65>s y barras
|
|
|
|
|
de men<65>s. <20>sta primera funci<63>n se utiliza para crear una barra de men<65>s.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_menu_bar_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como el propio nombre indica, esta funci<63>n crea una nueva barra de
|
|
|
|
|
men<EFBFBD>s. Utilice <tt/gtk_container_add/ para empaquetarla en una
|
|
|
|
|
ventana, o las funciones <tt/box_pack/ para empaquetarla en una caja -
|
|
|
|
|
exactamente igual que si fuesen botones.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_menu_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n devuelve un puntero a un nuevo men<65>, que no se debe
|
|
|
|
|
mostrar nunca (no hace falta utilizar <tt/gtk_widget_show/), es s<>lo
|
|
|
|
|
un contenedor para los elementos del men<65>. Espero que todo esto se
|
|
|
|
|
aclare un poco cuando vea en el ejemplo que hay m<>s abajo.
|
|
|
|
|
|
|
|
|
|
Las siguientes dos llamadas se utilizan para crear elementos de men<65>
|
|
|
|
|
que se empaquetar<61>n en el men<65> (y en la barra de men<65>).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_menu_item_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
y
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_menu_item_new_with_label( const char *etiqueta );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Estas llamadas se utilizan para crear los elementos del men<65> que
|
|
|
|
|
van a mostrarse. Recuerde que hay que distinguir entre un <20>men<65><6E>
|
|
|
|
|
creado con <tt/gtk_menu_new/ y un <20>elemento del men<65><6E> creado con las
|
|
|
|
|
funciones <tt/gtk_menu_item_new/. El elemento de men<65> ser<65> un bot<6F>n
|
|
|
|
|
con una acci<63>n asociada, y un men<65> ser<65> un contenedor con los
|
|
|
|
|
elementos del men<65>.
|
|
|
|
|
|
|
|
|
|
Las funciones <tt/gtk_menu_new_with_label/ y <tt/gtk_menu_new/ son
|
|
|
|
|
s<EFBFBD>lo lo que espera que sean despu<70>s de leer lo de los botones. Una
|
|
|
|
|
crea un nuevo elemento del men<65> con una etiqueta ya dentro, y la otra
|
|
|
|
|
crea un elemento del men<65> en blanco.
|
|
|
|
|
|
|
|
|
|
Una vez ha creado un elemento del men<65> tiene que ponerlo en un men<65>.
|
|
|
|
|
Esto se hace utilizando la funci<63>n <tt/gtk_menu_append/. Para capturar
|
|
|
|
|
el momento en el que el elemento se selecciona por el usuario,
|
|
|
|
|
necesitamos conectar con la se<73>al <tt/activate/ de la forma usual. Por
|
|
|
|
|
tanto, si quiere crear un men<65> est<73>ndar <tt/File/, con las opciones
|
|
|
|
|
<tt/Open/, <tt/Save/ y <tt/Quit/ el c<>digo deber<65>a ser algo como
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
file_menu = gtk_menu_new(); /* No hay que mostrar men<65>s */
|
|
|
|
|
|
|
|
|
|
/* Crear los elementos del men<65> */
|
|
|
|
|
open_item = gtk_menu_item_new_with_label("Open");
|
|
|
|
|
save_item = gtk_menu_item_new_with_label("Save");
|
|
|
|
|
quit_item = gtk_menu_item_new_with_label("Quit");
|
|
|
|
|
|
|
|
|
|
/* A<>adirlos al men<65> */
|
|
|
|
|
gtk_menu_append( GTK_MENU(file_menu), open_item);
|
|
|
|
|
gtk_menu_append( GTK_MENU(file_menu), save_item);
|
|
|
|
|
gtk_menu_append( GTK_MENU(file_menu), quit_item);
|
|
|
|
|
|
|
|
|
|
/* Enlazar las funci<63>n de llamada a la se<73>al "activate" */
|
|
|
|
|
gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
|
|
|
|
|
GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
|
|
|
|
|
gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
|
|
|
|
|
GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
|
|
|
|
|
|
|
|
|
|
/* Podemos enlazar el elemento de men<65> Quit con nuestra funci<63>n de
|
|
|
|
|
* salida */
|
|
|
|
|
gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
|
|
|
|
|
GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
|
|
|
|
|
|
|
|
|
|
/* Tenemos que mostrar los elementos del men<65> */We do need to show menu items */
|
|
|
|
|
gtk_widget_show( open_item );
|
|
|
|
|
gtk_widget_show( save_item );
|
|
|
|
|
gtk_widget_show( quit_item );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
En este momento tendremos nuestro men<65>. Ahora necesitamos crear una
|
|
|
|
|
barra de men<65>s y un elemento de men<65> para el elemento <tt/File/, que
|
|
|
|
|
vamos a a<>adir a nuestro men<65>. El c<>digo es el siguiente
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
menu_bar = gtk_menu_bar_new();
|
|
|
|
|
gtk_container_add( GTK_CONTAINER(ventana), menu_bar);
|
|
|
|
|
gtk_widget_show( menu_bar );
|
|
|
|
|
|
|
|
|
|
file_item = gtk_menu_item_new_with_label("File");
|
|
|
|
|
gtk_widget_show(file_item);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Ahora necesitamos asociar el men<65> con <tt/file_item/. Esto se hace con
|
|
|
|
|
la funci<63>n
|
|
|
|
|
|
|
|
|
|
<tscreen>
|
|
|
|
|
void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
|
|
|
|
|
GtkWidget *submenu );
|
|
|
|
|
</tscreen>
|
|
|
|
|
|
|
|
|
|
Por lo que nuestro ejemplo continua con
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Todo lo que queda por hacer es a<>adir el men<65> a la barra de men<65>s, que
|
|
|
|
|
se hace mediante la funci<63>n
|
|
|
|
|
|
|
|
|
|
<tscreen>
|
|
|
|
|
void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
|
|
|
|
|
</tscreen>
|
|
|
|
|
|
|
|
|
|
que en nuestro caso habr<62> que utilizar as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Si queremos que el men<65> est<73> alineado a la derecha en la barra de
|
|
|
|
|
men<EFBFBD>s, como suele estar la opci<63>n de ayuda, podemos utilizar la
|
|
|
|
|
funci<EFBFBD>n siguiente (otra vez en <tt/file_item/ en el ejemplo actual)
|
|
|
|
|
antes de enlazarla en la barra de men<65>.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> hay un resumen de los pasos que son necesarios para crear una
|
|
|
|
|
barra de men<65>s con los men<65>s correspondientes ya enlazados:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> Crear un nuevo men<65> utilizando <tt/gtk_menu_new()/
|
|
|
|
|
<item> Utilizar multiples llamadas a <tt/gtk_menu_item_new()/ para
|
|
|
|
|
cada elemento que desee tener en su men<65>. Y utilizar
|
|
|
|
|
<tt/gtk_menu_append()/ para poner cada uno de esos nuevos elementos en
|
|
|
|
|
el men<65>.
|
|
|
|
|
<item> Crear un elemento de men<65> utilizando
|
|
|
|
|
<tt/gtk_menu_item_new()/. <20>sta ser<65> la ra<72>z del men<65>, el texto que
|
|
|
|
|
aparezca aqu<71> estar<61> en la barra de men<65>s.
|
|
|
|
|
<item> Utilizar <tt/gtk_menu_item_set_submenu()/ para enlazar el men<65>
|
|
|
|
|
al elemento del men<65> ra<72>z (el creado en el paso anterior).
|
|
|
|
|
<item> Crear una nueva barra de men<65>s utilizando
|
|
|
|
|
<tt/gtk_menu_bar_new/. Este paso solo necesita hacerse una vez cuando
|
|
|
|
|
se crea una serie de men<65>s en una barra de men<65>s.
|
|
|
|
|
<item> Utilizar <tt/gtk_menu_bar_append/ para poner el men<65> ra<72>z en la
|
|
|
|
|
barra de men<65>s.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Para hacer un men<65> desplegable hay que seguir pr<70>cticamente los mismos
|
|
|
|
|
pasos. La <20>nica diferencia es que el men<65> no estar<61> conectado
|
|
|
|
|
`autom<6F>ticamente' a una barra de men<65>, sino que para que aparezca
|
|
|
|
|
deber<EFBFBD> llamarse expl<70>citamente a la funci<63>n <tt/gtk_menu_popup()/
|
|
|
|
|
utilizando, por ejemplo, un evento de pulsaci<63>n de bot<6F>n. Siga los
|
|
|
|
|
pasos siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>Cree una funci<63>n manejadora de eventos. Tiene que tener el
|
|
|
|
|
siguiente prototipo
|
|
|
|
|
<tscreen>
|
|
|
|
|
static gint handler( GtkWidget *widget,
|
|
|
|
|
GdkEvent *event );
|
|
|
|
|
</tscreen>
|
|
|
|
|
|
|
|
|
|
y utilice el evento para encontrar donde debe aparecer el men<65>.
|
|
|
|
|
|
|
|
|
|
<item>En el manejador de eventos, si el evento es una pulsaci<63>n de un
|
|
|
|
|
bot<EFBFBD>n del rat<61>n, tratar <tt>event</tt> como un evento de bot<6F>n
|
|
|
|
|
(que lo es) y utilizarlo como se indica en el c<>digo ejemplo para
|
|
|
|
|
pasarle informaci<63>n a <tt/gtk_menu_popup()/.
|
|
|
|
|
<item>Enlazar este manejador de eventos con el <em>widget</em> con
|
|
|
|
|
<tscreen>
|
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(widget), "event",
|
|
|
|
|
GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
|
|
|
|
|
</tscreen>
|
|
|
|
|
donde <tt>widget</tt> es el <em>widget</em> con el que esta conectando,
|
|
|
|
|
<tt>handler</tt> es la funci<63>n manejadora, y <tt>menu</tt> es un men<65>
|
|
|
|
|
creado con <tt/gtk_menu_new()/. <20>ste puede ser un men<65> que est<73>
|
|
|
|
|
contenido en una barra de men<65>s, como se puede ver en el c<>digo de
|
|
|
|
|
ejemplo.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Ejemplo de la creaci<63>n manual de un men<65>
|
|
|
|
|
<p>
|
|
|
|
|
Esto deber<65>a funcionar. <20>chele un vistazo al ejemplo para aclarar los
|
|
|
|
|
conceptos.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo menu menu.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
static gint button_press (GtkWidget *, GdkEvent *);
|
|
|
|
|
static void menuitem_response (gchar *);
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *menu;
|
|
|
|
|
GtkWidget *menu_bar;
|
|
|
|
|
GtkWidget *root_menu;
|
|
|
|
|
GtkWidget *menu_items;
|
|
|
|
|
GtkWidget *vbox;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
char buf[128];
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* crear una nueva ventana */
|
|
|
|
|
ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_widget_set_usize( GTK_WIDGET (ventana), 200, 100);
|
|
|
|
|
gtk_window_set_title(GTK_WINDOW (ventana), "GTK Menu Test");
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT (ventana), "delete_event",
|
|
|
|
|
(GtkSignalFunc) gtk_main_quit, NULL);
|
|
|
|
|
|
|
|
|
|
/* Inicializar el widget-menu, y recuerde -- <20><>Nunca haga
|
|
|
|
|
* gtk_show_widget() con el widget menu!!
|
|
|
|
|
* <20>ste es el men<65> que contiene todos los elementos del men<65>, el
|
|
|
|
|
* que se desplegar<61> cuando pulse en el "Root Menu" en la
|
|
|
|
|
* aplicaci<63>n
|
|
|
|
|
*/
|
|
|
|
|
menu = gtk_menu_new();
|
|
|
|
|
|
|
|
|
|
/* Ahora hacemos un peque<75>o bucle que crea tres elementos de men<65>
|
|
|
|
|
* para "test-menu". Recuerde llamar a gtk_menu_append. Aqu<71>
|
|
|
|
|
* estamos a<>adiendo una lista de elementos de men<65> a nuestro
|
|
|
|
|
* men<65>. Normalmente tendr<64>amos que cazar aqu<71> la se<73>al "clicked"
|
|
|
|
|
* de cada uno de los elementos del men<65> y le deber<65>amos dar una
|
|
|
|
|
* funci<63>n de llamada a cada uno, pero lo vamos a omitimos para
|
|
|
|
|
* ahorrar espacio. */
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < 3; i++)
|
|
|
|
|
{
|
|
|
|
|
/* Copia los nombres al b<>fer. */
|
|
|
|
|
sprintf(buf, "Test-undermenu - %d", i);
|
|
|
|
|
|
|
|
|
|
/* Crea un nuevo elemento de men<65> con un nombre... */
|
|
|
|
|
menu_items = gtk_menu_item_new_with_label(buf);
|
|
|
|
|
|
|
|
|
|
/* ...y lo a<>ade al men<65>. */
|
|
|
|
|
gtk_menu_append(GTK_MENU (menu), menu_items);
|
|
|
|
|
|
|
|
|
|
/* Hace algo interesante cuando se selecciona el menuitem */
|
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
|
|
|
|
|
GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
|
|
|
|
|
|
|
|
|
|
/* Muestra el widget */
|
|
|
|
|
gtk_widget_show(menu_items);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* <20>sta es el men<65> ra<72>z, y ser<65> la etiqueta mostrada en la
|
|
|
|
|
* barra de men<65>s. No habr<62> ning<6E>n manejador de se<73>al conectado, ya que
|
|
|
|
|
* lo <20>nico que hace es desplegar el resto del men<65>. */
|
|
|
|
|
root_menu = gtk_menu_item_new_with_label("Root Menu");
|
|
|
|
|
|
|
|
|
|
gtk_widget_show(root_menu);
|
|
|
|
|
|
|
|
|
|
/* Ahora especificamos que queremos que el recien creado "menu"
|
|
|
|
|
* sea el men<65> para el "root menu" */
|
|
|
|
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
|
|
|
|
|
|
|
|
|
|
/* Un vbox para poner dentro un men<65> y un bot<6F>n */
|
|
|
|
|
vbox = gtk_vbox_new(FALSE, 0);
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(ventana), vbox);
|
|
|
|
|
gtk_widget_show(vbox);
|
|
|
|
|
|
|
|
|
|
/* Crear una barra de men<65> para que contenga al men<65> y la a<>adamos
|
|
|
|
|
* a nuestra ventana principal */
|
|
|
|
|
menu_bar = gtk_menu_bar_new();
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
|
|
|
|
|
gtk_widget_show(menu_bar);
|
|
|
|
|
|
|
|
|
|
/* Crear un bot<6F>n al que atar los men<65>s como un popup */
|
|
|
|
|
boton = gtk_button_new_with_label("press me");
|
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(boton), "event",
|
|
|
|
|
GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
|
|
|
|
|
gtk_box_pack_end(GTK_BOX(vbox), boton, TRUE, TRUE, 2);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
|
|
|
|
|
/* Y finalmente a<>adimos el elemento de men<65> y la barra de men<65> --
|
|
|
|
|
* <20>ste es el elemento de men<65> "ra<72>z" sobre el que he estado
|
|
|
|
|
* delirando =) */
|
|
|
|
|
gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
|
|
|
|
|
|
|
|
|
|
/* siempre mostramos la ventana como <20>ltimo paso para que todo se
|
|
|
|
|
* pongo en pantalla a la vez. */
|
|
|
|
|
gtk_widget_show(ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Responde a una pulsaci<63>n del bot<6F>n enviando un men<65> como un widget
|
|
|
|
|
* Recuerde que el argumento "widget" es el men<65> que se est<73> enviando,
|
|
|
|
|
* NO el bot<6F>n que se ha pulsado.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static gint button_press (GtkWidget *widget, GdkEvent *event)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (event->type == GDK_BUTTON_PRESS) {
|
|
|
|
|
GdkEventButton *bevent = (GdkEventButton *) event;
|
|
|
|
|
gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
|
|
|
|
|
bevent->button, bevent->time);
|
|
|
|
|
/* Le dice al que llam<61> a la rutina que hemos manejado el
|
|
|
|
|
* evento; la historia termina aqu<71>. */
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Le dice al que llam<61> a la rutina que no hemos manejado el
|
|
|
|
|
* evento. */
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Imprime una cadena cuando se selecciona un elemento del men<65> */
|
|
|
|
|
|
|
|
|
|
static void menuitem_response (gchar *string)
|
|
|
|
|
{
|
|
|
|
|
printf("%s\n", string);
|
|
|
|
|
}
|
|
|
|
|
/* final del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n puede hacer que un elemento del men<65> sea insensible y, utilizando
|
|
|
|
|
una tabla de teclas aceleradoras, conectar las teclas con las funciones
|
|
|
|
|
del men<65>.
|
|
|
|
|
|
|
|
|
|
<!-- XXX Las dos sect1 que vienen han cambiado -->
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Utilizando GtkItemFactory
|
|
|
|
|
<p>
|
|
|
|
|
Ahora que le hemos ense<73>ado la forma dif<69>cil, le mostraremos como
|
|
|
|
|
utilizar las llamadas <tt/gtk_item_factory/.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Ejemplo de la f<>brica de elementos
|
|
|
|
|
<p>
|
|
|
|
|
Aqu<EFBFBD> hay un ejemplo de c<>mo utilizar la f<>brica de elementos
|
|
|
|
|
GTK.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo menu itemfactory.h */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
#include <strings.h>
|
|
|
|
|
|
|
|
|
|
/* La obligatoria funci<63>n de llamada */
|
|
|
|
|
static void print_hello( GtkWidget *w,
|
|
|
|
|
gpointer data )
|
|
|
|
|
{
|
|
|
|
|
g_message ("Hello, World!\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Esta es la estructura GtkItemFactoryEntry utilizada para crear
|
|
|
|
|
nuevos men<65>es.
|
|
|
|
|
|
|
|
|
|
This is the GtkItemFactoryEntry structure used to generate new menus.
|
|
|
|
|
Elemento 1: La direcci<63>n del men<65>. La letra que hay
|
|
|
|
|
despu<70>s del subrayado indica una tecla aceleradora
|
|
|
|
|
una vez que el men<65> est<73> abierto.
|
|
|
|
|
Elemento 2: La tecla aceleradora para la entrada del men<65>.
|
|
|
|
|
Elemento 3: La funci<63>n de llamada.
|
|
|
|
|
Elemento 4: La acci<63>n de llamada. Cambia los par<61>metros que
|
|
|
|
|
se le pasan a la funci<63>n de llamada. El valor por
|
|
|
|
|
defecto es 0.
|
|
|
|
|
Elemento 5: El tipo de elemento, se utiliza para definir de que
|
|
|
|
|
tipo de elemento se trata. Los valores posibles son:
|
|
|
|
|
|
|
|
|
|
NULL -> "<Item>"
|
|
|
|
|
"" -> "<Item>"
|
|
|
|
|
"<Title>" -> crea un elemento t<>tulo
|
|
|
|
|
"<Item>" -> crea un simple elemento
|
|
|
|
|
"<CheckItem>" -> crea un elemento de comprobaci<63>n
|
|
|
|
|
"<ToggleItem>" -> crea un elemento de selecci<63>n
|
|
|
|
|
"<RadioItem>" -> crea un elemento circular
|
|
|
|
|
<path> -> direcci<63>n de un elemento circular
|
|
|
|
|
con el que enlazar
|
|
|
|
|
"<Separator>" -> crea un separador
|
|
|
|
|
"<Branch>" -> crea un elemento para contener
|
|
|
|
|
subelementos (de forma opcional)
|
|
|
|
|
"<LastBranch>" -> crea una rama justificada a la
|
|
|
|
|
derecha
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static GtkItemFactoryEntry menu_items[] = {
|
|
|
|
|
{ "/_File", NULL, NULL, 0, "<Branch>" },
|
|
|
|
|
{ "/File/_New", "<control>N", print_hello, 0, NULL },
|
|
|
|
|
{ "/File/_Open", "<control>O", print_hello, 0, NULL },
|
|
|
|
|
{ "/File/_Save", "<control>S", print_hello, 0, NULL },
|
|
|
|
|
{ "/File/Save _As", NULL, NULL, 0, NULL },
|
|
|
|
|
{ "/File/sep1", NULL, NULL, 0, "<Separator>" },
|
|
|
|
|
{ "/File/Quit", "<control>Q", gtk_main_quit, 0, NULL },
|
|
|
|
|
{ "/_Options", NULL, NULL, 0, "<Branch>" },
|
|
|
|
|
{ "/Options/Test", NULL, NULL, 0, NULL },
|
|
|
|
|
{ "/_Help", NULL, NULL, 0, "<LastBranch>" },
|
|
|
|
|
{ "/_Help/About", NULL, NULL, 0, NULL },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void get_main_menu( GtkWidget *ventana,
|
|
|
|
|
GtkWidget **menubar )
|
|
|
|
|
{
|
|
|
|
|
GtkItemFactory *item_factory;
|
|
|
|
|
GtkAccelGroup *accel_group;
|
|
|
|
|
gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
|
|
|
|
|
|
|
|
|
|
accel_group = gtk_accel_group_new ();
|
|
|
|
|
|
|
|
|
|
/* Esta funci<63>n inicializa la f<>brica de elementos
|
|
|
|
|
Param 1: El tipo de men<65> - puede ser GTK_TYPE_MENU_BAR,
|
|
|
|
|
GTK_TYPE_MENU, o GTK_TYPE_OPTION_MENU.
|
|
|
|
|
Param 2: La direcci<63>n del men<65>.
|
|
|
|
|
Param 3: Un puntero a un gtk_accel_group. La f<>brica de
|
|
|
|
|
elementos actualiza la tabla de teclas aceleradoras
|
|
|
|
|
mientras genera los men<65>es.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>",
|
|
|
|
|
accel_group);
|
|
|
|
|
|
|
|
|
|
/* Esta funci<63>n genera los elementos de men<65>. Pasa la
|
|
|
|
|
f<>brica de elementos (item_factory), el n<>mero de elementos
|
|
|
|
|
del vector, el vector en s<>, y cualquier dato de llamada para
|
|
|
|
|
los elementos de men<65>. */
|
|
|
|
|
gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
|
|
|
|
|
|
|
|
|
|
/* Enlaza el nuevo grupo acelerador a la ventana. */
|
|
|
|
|
gtk_accel_group_attach (accel_group, GTK_OBJECT (ventana));
|
|
|
|
|
|
|
|
|
|
if (menubar)
|
|
|
|
|
/* Finalmente, devuelve la barra de men<65> creada por la
|
|
|
|
|
* f<>brica de elementos. */
|
|
|
|
|
*menubar = gtk_item_factory_get_widget (item_factory, "<main>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main( int argc,
|
|
|
|
|
char *argv[] )
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *main_vbox;
|
|
|
|
|
GtkWidget *menubar;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit),
|
|
|
|
|
"WM destroy");
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW(ventana), "Item Factory");
|
|
|
|
|
gtk_widget_set_usize (GTK_WIDGET(ventana), 300, 200);
|
|
|
|
|
|
|
|
|
|
main_vbox = gtk_vbox_new (FALSE, 1);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), main_vbox);
|
|
|
|
|
gtk_widget_show (main_vbox);
|
|
|
|
|
|
|
|
|
|
get_main_menu (ventana, &menubar);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (menubar);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Por ahora, s<>lo est<73> este ejemplo. Ya llegar<61> una
|
|
|
|
|
explicaci<EFBFBD>n del mismo y m<>s comentarios.
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> El <em>widget</em> texto
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
El <em>widget</em> texto permite mostrar y editar multiples l<>neas de
|
|
|
|
|
texto. Admite texto en varios colores y con varios tipos de letra,
|
|
|
|
|
permitiendo mezclarlos de cualquier forma que desee. Tambi<62>n hay un
|
|
|
|
|
gran n<>mero de teclas para la edici<63>n de textos, que son compatibles
|
|
|
|
|
con Emacs.
|
|
|
|
|
|
|
|
|
|
El <em>widget</em> texto admite copiar-y-pegar, incluyendo la
|
|
|
|
|
utilizaci<EFBFBD>n de doble y triple-click para seleccionar una palabra y una
|
|
|
|
|
l<EFBFBD>nea completa, respectivamente.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Creando y configurando un cuadro de texto
|
|
|
|
|
<p>
|
|
|
|
|
S<EFBFBD>lo hay una funci<63>n para crear un nuevo <em>widget</em> texto.
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_text_new( GtkAdjustment *hadj,
|
|
|
|
|
GtkAdjustment *vadj );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los argumentos nos permitir<69>n dar al <em>widget</em> texto punteros a
|
|
|
|
|
<tt/GtkAdjustement/ que pueden ser utilizados para controlar la visi<73>n
|
|
|
|
|
de la posici<63>n del <em>widget</em>. Si le ponemos un valor NULL en
|
|
|
|
|
cualquiera de los dos argumentos (o en los dos), la funci<63>n
|
|
|
|
|
<tt/gtk_text_new/ crear<61> su propio ajuste.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_text_set_adjustments( GtkText *text,
|
|
|
|
|
GtkAdjustment *hadj,
|
|
|
|
|
GtkAdjustment *vadj );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La funci<63>n de arriba permite cambiar en cualquier momento el ajuste
|
|
|
|
|
horizontal y vertical de un <em>widget</em> texto.
|
|
|
|
|
|
|
|
|
|
El <em>widget</em> texto no crea autom<6F>ticamente sus propiar barras
|
|
|
|
|
de desplazamiento cuando el texto a mostrar es demasiado largo
|
|
|
|
|
para la ventana en la que se encuentra. Tenemos que crearlas y
|
|
|
|
|
a<EFBFBD>adirlas a la capa del <em>display</em> nosotros mismos.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
|
|
|
|
|
gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (vscrollbar);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El trozo de c<>digo de arriba crea una nueva barra de desplazamiento
|
|
|
|
|
vertical, y la conecta con el ajuste vertical del <em>widget</em>
|
|
|
|
|
de texto, <tt/text/. Entonces la empaqueta en un cuadro de la forma
|
|
|
|
|
usual.
|
|
|
|
|
|
|
|
|
|
Observe que, actualmente el <em>widget</em> GtkText no admite barras
|
|
|
|
|
de desplazamiento horizontal.
|
|
|
|
|
|
|
|
|
|
Principalmente hay dos maneras de utilizar un <em>widget</em> de
|
|
|
|
|
texto: permitiendo al usuario editar el texto, o permiti<74>ndonos
|
|
|
|
|
mostrar varias l<>neas de texto al usuario. Para cambiar entre estos
|
|
|
|
|
dos modos de operaci<63>n, el <em>widget</em> de texto tiene las
|
|
|
|
|
siguientes funciones:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_text_set_editable( GtkText *text,
|
|
|
|
|
gint editable );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El argumento <tt/editable/ es un valor TRUE o FALSE que especifica si se
|
|
|
|
|
permite al usuario editar los contenidos del <em>widget</em> texto.
|
|
|
|
|
Cuando el <em>widget</em> texto se pueda editar, mostrar<61> un cursor
|
|
|
|
|
en la posici<63>n actual de inserci<63>n.
|
|
|
|
|
|
|
|
|
|
Sin embargo la utilizaci<63>n del <em>widget</em> en estos dos modos no
|
|
|
|
|
es algo permanente, ya que puede cambiar el estado editable del
|
|
|
|
|
<em>widget</em> texto e insertar texto en cualquier momento.
|
|
|
|
|
|
|
|
|
|
El <em>widget</em> texto corta las l<>neas de texto que son demasiado
|
|
|
|
|
largas para que quepan en una s<>lo l<>nea en la ventana. Su
|
|
|
|
|
comportamiento por defecto es cortar las palabras donde se terminan
|
|
|
|
|
las l<>neas. Esto puede cambiarse utilizando la siguiente funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_text_set_word_wrap( GtkText *text,
|
|
|
|
|
gint word_wrap );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Utilizando esta funci<63>n podremos especificar que el <em>widget</em>
|
|
|
|
|
texto deber<65>a cortar las l<>neas largas en los l<>mites de las
|
|
|
|
|
palabras. El argumento <tt/word_wrap/ es un valor TRUE o FALSE.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Manipulaci<63>n de texto
|
|
|
|
|
<P>
|
|
|
|
|
El punto actual de inserci<63>n en un <em>widget</em> texto puede
|
|
|
|
|
cambiarse utilizando
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_text_set_point( GtkText *text,
|
|
|
|
|
guint index );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
donde <tt/index/ es la posici<63>n en la que poner el punto de inserci<63>n.
|
|
|
|
|
|
|
|
|
|
An<EFBFBD>logamente tenemos la funci<63>n para obtener la posici<63>n del punto
|
|
|
|
|
de inserci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_text_get_point( GtkText *text );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Una funci<63>n que es <20>til en combinaci<63>n con las dos anteriores es
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_text_get_length( GtkText *text );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
que devuelve la longitud actual del <em>widget</em> texto. La
|
|
|
|
|
longitud es el n<>mero de caracteres que hay en el bloque de texto,
|
|
|
|
|
incluyendo caracteres como el retorno de carro, que marca el final de
|
|
|
|
|
las l<>neas.
|
|
|
|
|
|
|
|
|
|
Para insertar texto en la posici<63>n actual del cursor, tendr<64> que
|
|
|
|
|
utilizar la funci<63>n <tt/gtk_text_insert/, que nos permitir<69>
|
|
|
|
|
especificar los colores de fondo y de la letra y un tipo de letra para
|
|
|
|
|
el texto.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_text_insert( GtkText *text,
|
|
|
|
|
GdkFont *font,
|
|
|
|
|
GdkColor *fore,
|
|
|
|
|
GdkColor *back,
|
|
|
|
|
const char *chars,
|
|
|
|
|
gint length );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Pasar un valor <tt/NULL/ como el color de la letra (<tt/fore/), el
|
|
|
|
|
color de fondo (<tt/back/) o el tipo de letra (<tt/font/) har<61> que
|
|
|
|
|
se utilicen los valores que indiquen el estilo del <em>widget</em>.
|
|
|
|
|
Utilizar un valor de <tt/-1/ para el par<61>metro <tt/length/ har<61>
|
|
|
|
|
que se inserte todo el texto.
|
|
|
|
|
|
|
|
|
|
El <em/widget/ texto es uno de los pocos de GTK que se redibuja
|
|
|
|
|
a s<> mismo din<69>micamente, fuera de la funci<63>n <tt/gtk_main/. Esto
|
|
|
|
|
significa que todos los cambios en el contenido del <em/widget/ texto
|
|
|
|
|
se manifestar<61>n inmediatamente. Para permitirnos realizar varias
|
|
|
|
|
actualizaciones del <em/widget/ de texto sin que se redibuje
|
|
|
|
|
continuamente, podemos congelar el <em/widget/, lo que har<61> que pare
|
|
|
|
|
momentaneamente de redibujarse a s<> mismo cada vez que haya alg<6C>n
|
|
|
|
|
cambio. Podemos descongelarlo cuando hayamos acabado con nuestras
|
|
|
|
|
actualizaciones.
|
|
|
|
|
|
|
|
|
|
Las siguientes dos funciones realizar<61>n la acci<63>n de congelar y
|
|
|
|
|
descongelar el <em/widget/:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_text_freeze( GtkText *text );
|
|
|
|
|
|
|
|
|
|
void gtk_text_thaw( GtkText *text );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se puede borrar el texto que se encuentra en el punto actual de
|
|
|
|
|
inserci<EFBFBD>n del <em/widget/ de texto mediante dos funciones. El valor
|
|
|
|
|
devuelto es TRUE o FALSE en funci<63>n del <20>xito de la operaci<63>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_text_backward_delete( GtkText *text,
|
|
|
|
|
guint nchars );
|
|
|
|
|
|
|
|
|
|
gint gtk_text_forward_delete ( GtkText *text,
|
|
|
|
|
guint nchars );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Si quiere recuperar el contenido del <em/widget/ de texto, entonces
|
|
|
|
|
la macro <tt/GTK_TEXT_INDEX(t, index)/ le permitir<69> obtener el
|
|
|
|
|
car<EFBFBD>cter que se encuentra en la posici<63>n <tt/index/ del <em/widget/
|
|
|
|
|
de texto <tt/t/.
|
|
|
|
|
|
|
|
|
|
Para obtener mayores bloques de texto, podemos utilizar la funci<63>n
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gchar *gtk_editable_get_chars( GtkEditable *editable,
|
|
|
|
|
gint start_pos,
|
|
|
|
|
gint end_pos );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta es una funci<63>n de la clase padre del <em/widget/ texto. Un valor
|
|
|
|
|
de -1 en <tt/end_pos/ significa el final del texto. El <20>ndice del
|
|
|
|
|
texto empieza en 0.
|
|
|
|
|
|
|
|
|
|
La funci<63>n reserva un espacio de memoria para el bloque de texto,
|
|
|
|
|
por lo que no debe olvidarse de liberarlo con una llamada a
|
|
|
|
|
<tt/g_free/ cuando haya acabado el bloque.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Atajos por teclado
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ texto tiene ciertos atajos de teclado preinstalados
|
|
|
|
|
para las funciones de edici<63>n est<73>ndar, movimiento y selecci<63>n. Pueden
|
|
|
|
|
utilizarse mediante combinaciones de las teclas Control y Alt.
|
|
|
|
|
|
|
|
|
|
Adem<EFBFBD>s, si se mantiene apretada la tecla de Control y se utilizan las
|
|
|
|
|
teclas de movimiento, el cursor se mover<65> por palabras en lugar de por
|
|
|
|
|
caracteres. Manteniendo apretada la tecla Shift, las teclas de movimiento
|
|
|
|
|
har<EFBFBD>n que se extienda la selecci<63>n.
|
|
|
|
|
|
|
|
|
|
<sect2>Atajos para el movimiento
|
|
|
|
|
<p>
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> Ctrl-A Principio de l<>nea
|
|
|
|
|
<item> Ctrl-E Final de l<>nea
|
|
|
|
|
<item> Ctrl-N L<>nea siguiente
|
|
|
|
|
<item> Ctrl-P L<>nea anterior
|
|
|
|
|
<item> Ctrl-B Retrasarse un car<61>cter
|
|
|
|
|
<item> Ctrl-F Adelantarse un car<61>cter
|
|
|
|
|
<item> Alt-B Retrasarse una palabra
|
|
|
|
|
<item> Alt-F Adelantarse una palabra
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<sect2>Atajos para la edici<63>n
|
|
|
|
|
<p>
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> Ctrl-H Borrar el car<61>cter anterior (Backspace)
|
|
|
|
|
<item> Ctrl-D Borrar el car<61>cter siguiente (Suprimir)
|
|
|
|
|
<item> Ctrl-W Borrar la palabra anterior
|
|
|
|
|
<item> Alt-D Borrar la palabra siguiente
|
|
|
|
|
<item> Ctrl-K Borrar hasta el fin de la l<>nea
|
|
|
|
|
<item> Ctrl-U Borrar la l<>nea
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<sect2>Atajos de selecci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> Ctrl-X Cortar al portapapeles
|
|
|
|
|
<item> Ctrl-C Copiar al portapapeles
|
|
|
|
|
<item> Ctrl-V Pegar desde el portapapeles
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Un ejemplo de GtkText
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo text text.c */
|
|
|
|
|
|
|
|
|
|
/* text.c */
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
void text_toggle_editable (GtkWidget *checkbutton,
|
|
|
|
|
GtkWidget *text)
|
|
|
|
|
{
|
|
|
|
|
gtk_text_set_editable(GTK_TEXT(text),
|
|
|
|
|
GTK_TOGGLE_BUTTON(checkbutton)->active);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void text_toggle_word_wrap (GtkWidget *checkbutton,
|
|
|
|
|
GtkWidget *text)
|
|
|
|
|
{
|
|
|
|
|
gtk_text_set_word_wrap(GTK_TEXT(text),
|
|
|
|
|
GTK_TOGGLE_BUTTON(checkbutton)->active);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void close_application( GtkWidget *widget, gpointer data )
|
|
|
|
|
{
|
|
|
|
|
gtk_main_quit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *caja1;
|
|
|
|
|
GtkWidget *caja2;
|
|
|
|
|
GtkWidget *hbox;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *check;
|
|
|
|
|
GtkWidget *separator;
|
|
|
|
|
GtkWidget *table;
|
|
|
|
|
GtkWidget *vscrollbar;
|
|
|
|
|
GtkWidget *text;
|
|
|
|
|
GdkColormap *cmap;
|
|
|
|
|
GdkColor colour;
|
|
|
|
|
GdkFont *fixed_font;
|
|
|
|
|
|
|
|
|
|
FILE *infile;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_widget_set_usize (ventana, 600, 500);
|
|
|
|
|
gtk_window_set_policy (GTK_WINDOW(ventana), TRUE, TRUE, FALSE);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC(close_application),
|
|
|
|
|
NULL);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Text Widget Example");
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
caja1 = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), caja1);
|
|
|
|
|
gtk_widget_show (caja1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_vbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
table = gtk_table_new (2, 2, FALSE);
|
|
|
|
|
gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
|
|
|
|
|
gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), table, TRUE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (table);
|
|
|
|
|
|
|
|
|
|
/* Crear el widget GtkText */
|
|
|
|
|
text = gtk_text_new (NULL, NULL);
|
|
|
|
|
gtk_text_set_editable (GTK_TEXT (text), TRUE);
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
|
|
|
|
|
GTK_EXPAND | GTK_SHRINK | GTK_FILL,
|
|
|
|
|
GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
|
|
|
|
|
gtk_widget_show (text);
|
|
|
|
|
|
|
|
|
|
/* A<>adir una barra de desplazamiento vertical al widget GtkText */
|
|
|
|
|
vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
|
|
|
|
|
gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
|
|
|
|
|
GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
|
|
|
|
|
gtk_widget_show (vscrollbar);
|
|
|
|
|
|
|
|
|
|
/* Obtener el mapa de colores del sistema y conseguir el color rojo */
|
|
|
|
|
cmap = gdk_colormap_get_system();
|
|
|
|
|
colour.red = 0xffff;
|
|
|
|
|
colour.green = 0;
|
|
|
|
|
colour.blue = 0;
|
|
|
|
|
if (!gdk_color_alloc(cmap, &colour)) {
|
|
|
|
|
g_error("couldn't allocate colour");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Cargar un fuente de tama<6D>o fijo */
|
|
|
|
|
fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
|
|
|
|
|
|
|
|
|
|
/* Al enviar la se<73>al relize a un widget se crea una ventana para el
|
|
|
|
|
* mismo, y nos permite insertar texto */
|
|
|
|
|
gtk_widget_realize (text);
|
|
|
|
|
|
|
|
|
|
/* Congela el widget text, lo que nos permite hacer varias
|
|
|
|
|
* actualizaciones */
|
|
|
|
|
gtk_text_freeze (GTK_TEXT (text));
|
|
|
|
|
|
|
|
|
|
/* Insertamos alg<6C>n texto coloreado */
|
|
|
|
|
gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
|
|
|
|
|
"Supports ", -1);
|
|
|
|
|
gtk_text_insert (GTK_TEXT (text), NULL, &colour, NULL,
|
|
|
|
|
"colored ", -1);
|
|
|
|
|
gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
|
|
|
|
|
"text and different ", -1);
|
|
|
|
|
gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
|
|
|
|
|
"fonts\n\n", -1);
|
|
|
|
|
|
|
|
|
|
/* Cargamos el fichero text.c en la ventana de texto */
|
|
|
|
|
|
|
|
|
|
infile = fopen("text.c", "r");
|
|
|
|
|
|
|
|
|
|
if (infile) {
|
|
|
|
|
char buffer[1024];
|
|
|
|
|
int nchars;
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
nchars = fread(buffer, 1, 1024, infile);
|
|
|
|
|
gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
|
|
|
|
|
NULL, buffer, nchars);
|
|
|
|
|
|
|
|
|
|
if (nchars < 1024)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose (infile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Descongelamos el widget text, permiti<74>ndonos ver todos los
|
|
|
|
|
* cambios */
|
|
|
|
|
gtk_text_thaw (GTK_TEXT (text));
|
|
|
|
|
|
|
|
|
|
hbox = gtk_hbutton_box_new ();
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), hbox, FALSE, FALSE, 0);
|
|
|
|
|
gtk_widget_show (hbox);
|
|
|
|
|
|
|
|
|
|
check = gtk_check_button_new_with_label("Editable");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(check), "toggled",
|
|
|
|
|
GTK_SIGNAL_FUNC(text_toggle_editable), text);
|
|
|
|
|
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
|
|
|
|
|
gtk_widget_show (check);
|
|
|
|
|
check = gtk_check_button_new_with_label("Wrap Words");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(check), "toggled",
|
|
|
|
|
GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
|
|
|
|
|
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE);
|
|
|
|
|
gtk_widget_show (check);
|
|
|
|
|
|
|
|
|
|
separator = gtk_hseparator_new ();
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), separator, FALSE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (separator);
|
|
|
|
|
|
|
|
|
|
caja2 = gtk_vbox_new (FALSE, 10);
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (caja2), 10);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja1), caja2, FALSE, TRUE, 0);
|
|
|
|
|
gtk_widget_show (caja2);
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("close");
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(close_application),
|
|
|
|
|
NULL);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (caja2), boton, TRUE, TRUE, 0);
|
|
|
|
|
GTK_WIDGET_SET_FLAGS (boton, GTK_CAN_DEFAULT);
|
|
|
|
|
gtk_widget_grab_default (boton);
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> Los <em>widgets</em> no documentados
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
<EFBFBD>Todos ellos necesitan de gente que los documente! :) Por favor,
|
|
|
|
|
considere el contribuir a nuestro tutorial.
|
|
|
|
|
|
|
|
|
|
Si debe utilizar uno de estos <em/widgets/, que permanecen no
|
|
|
|
|
documentados, le sugiero que le eche un vistazo a su fichero de
|
|
|
|
|
cabecera respectivo en la distribuci<63>n GTK. Los nombre de las
|
|
|
|
|
funciones GTK son muy descriptivos. Una vez haya comprendido como
|
|
|
|
|
funcionan las cosas, no le ser<65> dif<69>cil ver como hay que utilizar un
|
|
|
|
|
<em/widget/ simplemente mirando su declaraci<63>n de funciones. Con esto,
|
|
|
|
|
y unos cu<63>ntos ejemplos del c<>digo de otros, no deber<65>a tener
|
|
|
|
|
problemas.
|
|
|
|
|
|
|
|
|
|
Cuando haya comprendido todas las funciones de un nuevo <em/widget/
|
|
|
|
|
no documentado, por favor considere el hecho de escribir un tutorial
|
|
|
|
|
para <20>l, para que as<61> otros se puedan beneficiar del tiempo que usted
|
|
|
|
|
gast<EFBFBD>.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Calendar
|
|
|
|
|
<p>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> CTree
|
|
|
|
|
<p>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Curves
|
|
|
|
|
<p>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Drawing Area
|
|
|
|
|
<p>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Font Selection Dialog
|
|
|
|
|
<p>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Gamma Curve
|
|
|
|
|
<p>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Image
|
|
|
|
|
<p>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Packer
|
|
|
|
|
<p>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Plugs and Sockets
|
|
|
|
|
<p>
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Preview
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<!--
|
|
|
|
|
|
|
|
|
|
(This may need to be rewritten to follow the style of the rest of the tutorial)
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
|
|
|
|
|
Previews serve a number of purposes in GIMP/GTK. The most important one is
|
|
|
|
|
this. High quality images may take up to tens of megabytes of memory - easy!
|
|
|
|
|
Any operation on an image that big is bound to take a long time. If it takes
|
|
|
|
|
you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
|
|
|
|
|
you make an error) to choose the desired modification, it make take you
|
|
|
|
|
literally hours to make the right one - if you don't run out of memory
|
|
|
|
|
first. People who have spent hours in color darkrooms know the feeling.
|
|
|
|
|
Previews to the rescue!
|
|
|
|
|
|
|
|
|
|
But the annoyance of the delay is not the only issue. Oftentimes it is
|
|
|
|
|
helpful to compare the Before and After versions side-by-side or at least
|
|
|
|
|
back-to-back. If you're working with big images and 10 second delays,
|
|
|
|
|
obtaining the Before and After impressions is, to say the least, difficult.
|
|
|
|
|
For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
|
|
|
|
|
out for most people, while back-to-back is more like back-to-1001, 1002,
|
|
|
|
|
..., 1010-back! Previews to the rescue!
|
|
|
|
|
|
|
|
|
|
But there's more. Previews allow for side-by-side pre-previews. In other
|
|
|
|
|
words, you write a plug-in (e.g. the filterpack simulation) which would have
|
|
|
|
|
a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
|
|
|
|
|
An approach like this acts as a sort of a preview palette and is very
|
|
|
|
|
effective for subtle changes. Let's go previews!
|
|
|
|
|
|
|
|
|
|
There's more. For certain plug-ins real-time image-specific human
|
|
|
|
|
intervention maybe necessary. In the SuperNova plug-in, for example, the
|
|
|
|
|
user is asked to enter the coordinates of the center of the future
|
|
|
|
|
supernova. The easiest way to do this, really, is to present the user with a
|
|
|
|
|
preview and ask him to interactively select the spot. Let's go previews!
|
|
|
|
|
|
|
|
|
|
Finally, a couple of misc uses. One can use previews even when not working
|
|
|
|
|
with big images. For example, they are useful when rendering complicated
|
|
|
|
|
patterns. (Just check out the venerable Diffraction plug-in + many other
|
|
|
|
|
ones!) As another example, take a look at the colormap rotation plug-in
|
|
|
|
|
(work in progress). You can also use previews for little logos inside you
|
|
|
|
|
plug-ins and even for an image of yourself, The Author. Let's go previews!
|
|
|
|
|
|
|
|
|
|
When Not to Use Previews
|
|
|
|
|
|
|
|
|
|
Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
|
|
|
|
|
previews only for rendered images!
|
|
|
|
|
|
|
|
|
|
Let's go previews!
|
|
|
|
|
|
|
|
|
|
You can stick a preview into just about anything. In a vbox, an hbox, a
|
|
|
|
|
table, a button, etc. But they look their best in tight frames around them.
|
|
|
|
|
Previews by themselves do not have borders and look flat without them. (Of
|
|
|
|
|
course, if the flat look is what you want...) Tight frames provide the
|
|
|
|
|
necessary borders.
|
|
|
|
|
|
|
|
|
|
[Image][Image]
|
|
|
|
|
|
|
|
|
|
Previews in many ways are like any other widgets in GTK (whatever that
|
|
|
|
|
means) except they possess an additional feature: they need to be filled with
|
|
|
|
|
some sort of an image! First, we will deal exclusively with the GTK aspect
|
|
|
|
|
of previews and then we'll discuss how to fill them.
|
|
|
|
|
|
|
|
|
|
GtkWidget *preview!
|
|
|
|
|
|
|
|
|
|
Without any ado:
|
|
|
|
|
|
|
|
|
|
/* Create a preview widget,
|
|
|
|
|
set its size, an show it */
|
|
|
|
|
GtkWidget *preview;
|
|
|
|
|
preview=gtk_preview_new(GTK_PREVIEW_COLOR)
|
|
|
|
|
/*Other option:
|
|
|
|
|
GTK_PREVIEW_GRAYSCALE);*/
|
|
|
|
|
gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
|
|
|
|
|
gtk_widget_show(preview);
|
|
|
|
|
my_preview_rendering_function(preview);
|
|
|
|
|
|
|
|
|
|
Oh yeah, like I said, previews look good inside frames, so how about:
|
|
|
|
|
|
|
|
|
|
GtkWidget *create_a_preview(int Width,
|
|
|
|
|
int Height,
|
|
|
|
|
int Colorfulness)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *preview;
|
|
|
|
|
GtkWidget *frame;
|
|
|
|
|
|
|
|
|
|
frame = gtk_frame_new(NULL);
|
|
|
|
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER(frame),0);
|
|
|
|
|
gtk_widget_show(frame);
|
|
|
|
|
|
|
|
|
|
preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
|
|
|
|
|
:GTK_PREVIEW_GRAYSCALE);
|
|
|
|
|
gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(frame),preview);
|
|
|
|
|
gtk_widget_show(preview);
|
|
|
|
|
|
|
|
|
|
my_preview_rendering_function(preview);
|
|
|
|
|
return frame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
That's my basic preview. This routine returns the "parent" frame so you can
|
|
|
|
|
place it somewhere else in your interface. Of course, you can pass the
|
|
|
|
|
parent frame to this routine as a parameter. In many situations, however,
|
|
|
|
|
the contents of the preview are changed continually by your application. In
|
|
|
|
|
this case you may want to pass a pointer to the preview to a
|
|
|
|
|
"create_a_preview()" and thus have control of it later.
|
|
|
|
|
|
|
|
|
|
One more important note that may one day save you a lot of time. Sometimes
|
|
|
|
|
it is desirable to label you preview. For example, you may label the preview
|
|
|
|
|
containing the original image as "Original" and the one containing the
|
|
|
|
|
modified image as "Less Original". It might occur to you to pack the
|
|
|
|
|
preview along with the appropriate label into a vbox. The unexpected caveat
|
|
|
|
|
is that if the label is wider than the preview (which may happen for a
|
|
|
|
|
variety of reasons unforseeable to you, from the dynamic decision on the
|
|
|
|
|
size of the preview to the size of the font) the frame expands and no longer
|
|
|
|
|
fits tightly over the preview. The same problem can probably arise in other
|
|
|
|
|
situations as well.
|
|
|
|
|
|
|
|
|
|
[Image]
|
|
|
|
|
|
|
|
|
|
The solution is to place the preview and the label into a 2x1 table and by
|
|
|
|
|
attaching them with the following parameters (this is one possible variations
|
|
|
|
|
of course. The key is no GTK_FILL in the second attachment):
|
|
|
|
|
|
|
|
|
|
gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
|
|
|
|
|
0,
|
|
|
|
|
GTK_EXPAND|GTK_FILL,
|
|
|
|
|
0,0);
|
|
|
|
|
gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
|
|
|
|
|
GTK_EXPAND,
|
|
|
|
|
GTK_EXPAND,
|
|
|
|
|
0,0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
And here's the result:
|
|
|
|
|
|
|
|
|
|
[Image]
|
|
|
|
|
|
|
|
|
|
Misc
|
|
|
|
|
|
|
|
|
|
Making a preview clickable is achieved most easily by placing it in a
|
|
|
|
|
boton. It also adds a nice border around the preview and you may not even
|
|
|
|
|
need to place it in a frame. See the Filter Pack Simulation plug-in for an
|
|
|
|
|
example.
|
|
|
|
|
|
|
|
|
|
This is pretty much it as far as GTK is concerned.
|
|
|
|
|
|
|
|
|
|
Filling In a Preview
|
|
|
|
|
|
|
|
|
|
In order to familiarize ourselves with the basics of filling in previews,
|
|
|
|
|
let's create the following pattern (contrived by trial and error):
|
|
|
|
|
|
|
|
|
|
[Image]
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
my_preview_rendering_function(GtkWidget *preview)
|
|
|
|
|
{
|
|
|
|
|
#define SIZE 100
|
|
|
|
|
#define HALF (SIZE/2)
|
|
|
|
|
|
|
|
|
|
guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
|
|
|
|
|
gint i, j; /* Coordinates */
|
|
|
|
|
double r, alpha, x, y;
|
|
|
|
|
|
|
|
|
|
if (preview==NULL) return; /* I usually add this when I want */
|
|
|
|
|
/* to avoid silly crashes. You */
|
|
|
|
|
/* should probably make sure that */
|
|
|
|
|
/* everything has been nicely */
|
|
|
|
|
/* initialized! */
|
|
|
|
|
for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape? */
|
|
|
|
|
/* glib.h contains ABS(x). */
|
|
|
|
|
row[i*3+0] = sqrt(1-r)*255; /* Define Red */
|
|
|
|
|
row[i*3+1] = 128; /* Define Green */
|
|
|
|
|
row[i*3+2] = 224; /* Define Blue */
|
|
|
|
|
} /* "+0" is for alignment! */
|
|
|
|
|
else {
|
|
|
|
|
row[i*3+0] = r*255;
|
|
|
|
|
row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
|
|
|
|
|
row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
|
|
|
|
|
/* Insert "row" into "preview" starting at the point with */
|
|
|
|
|
/* coordinates (0,j) first column, j_th row extending SIZE */
|
|
|
|
|
/* pixels to the right */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(row); /* save some space */
|
|
|
|
|
gtk_widget_draw(preview,NULL); /* what does this do? */
|
|
|
|
|
gdk_flush(); /* or this? */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Non-GIMP users can have probably seen enough to do a lot of things already.
|
|
|
|
|
For the GIMP users I have a few pointers to add.
|
|
|
|
|
|
|
|
|
|
Image Preview
|
|
|
|
|
|
|
|
|
|
It is probably wise to keep a reduced version of the image around with just
|
|
|
|
|
enough pixels to fill the preview. This is done by selecting every n'th
|
|
|
|
|
pixel where n is the ratio of the size of the image to the size of the
|
|
|
|
|
preview. All further operations (including filling in the previews) are then
|
|
|
|
|
performed on the reduced number of pixels only. The following is my
|
|
|
|
|
implementation of reducing the image. (Keep in mind that I've had only basic
|
|
|
|
|
C!)
|
|
|
|
|
|
|
|
|
|
(UNTESTED CODE ALERT!!!)
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
gint width;
|
|
|
|
|
gint height;
|
|
|
|
|
gint bbp;
|
|
|
|
|
guchar *rgb;
|
|
|
|
|
guchar *mask;
|
|
|
|
|
} ReducedImage;
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
SELECTION_ONLY,
|
|
|
|
|
SELECTION_IN_CONTEXT,
|
|
|
|
|
ENTIRE_IMAGE
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ReducedImage *Reduce_The_Image(GDrawable *drawable,
|
|
|
|
|
GDrawable *mask,
|
|
|
|
|
gint LongerSize,
|
|
|
|
|
gint Selection)
|
|
|
|
|
{
|
|
|
|
|
/* This function reduced the image down to the the selected preview size */
|
|
|
|
|
/* The preview size is determine by LongerSize, i.e. the greater of the */
|
|
|
|
|
/* two dimensions. Works for RGB images only! */
|
|
|
|
|
gint RH, RW; /* Reduced height and reduced width */
|
|
|
|
|
gint width, height; /* Width and Height of the area being reduced */
|
|
|
|
|
gint bytes=drawable->bpp;
|
|
|
|
|
ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
|
|
|
|
|
|
|
|
|
|
guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
|
|
|
|
|
gint i, j, whichcol, whichrow, x1, x2, y1, y2;
|
|
|
|
|
GPixelRgn srcPR, srcMask;
|
|
|
|
|
gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire */
|
|
|
|
|
/* image. */
|
|
|
|
|
|
|
|
|
|
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
|
|
|
|
|
width = x2-x1;
|
|
|
|
|
height = y2-y1;
|
|
|
|
|
/* If there's a SELECTION, we got its bounds!)
|
|
|
|
|
|
|
|
|
|
if (width != drawable->width && height != drawable->height)
|
|
|
|
|
NoSelectionMade=FALSE;
|
|
|
|
|
/* Become aware of whether the user has made an active selection */
|
|
|
|
|
/* This will become important later, when creating a reduced mask. */
|
|
|
|
|
|
|
|
|
|
/* If we want to preview the entire image, overrule the above! */
|
|
|
|
|
/* Of course, if no selection has been made, this does nothing! */
|
|
|
|
|
if (Selection==ENTIRE_IMAGE) {
|
|
|
|
|
x1=0;
|
|
|
|
|
x2=drawable->width;
|
|
|
|
|
y1=0;
|
|
|
|
|
y2=drawable->height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we want to preview a selection with some surrounding area we */
|
|
|
|
|
/* have to expand it a little bit. Consider it a bit of a riddle. */
|
|
|
|
|
if (Selection==SELECTION_IN_CONTEXT) {
|
|
|
|
|
x1=MAX(0, x1-width/2.0);
|
|
|
|
|
x2=MIN(drawable->width, x2+width/2.0);
|
|
|
|
|
y1=MAX(0, y1-height/2.0);
|
|
|
|
|
y2=MIN(drawable->height, y2+height/2.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How we can determine the width and the height of the area being */
|
|
|
|
|
/* reduced. */
|
|
|
|
|
width = x2-x1;
|
|
|
|
|
height = y2-y1;
|
|
|
|
|
|
|
|
|
|
/* The lines below determine which dimension is to be the longer */
|
|
|
|
|
/* side. The idea borrowed from the supernova plug-in. I suspect I */
|
|
|
|
|
/* could've thought of it myself, but the truth must be told. */
|
|
|
|
|
/* Plagiarism stinks! */
|
|
|
|
|
if (width>height) {
|
|
|
|
|
RW=LongerSize;
|
|
|
|
|
RH=(float) height * (float) LongerSize/ (float) width;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
RH=LongerSize;
|
|
|
|
|
RW=(float)width * (float) LongerSize/ (float) height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The entire image is stretched into a string! */
|
|
|
|
|
tempRGB = (guchar *) malloc(RW*RH*bytes);
|
|
|
|
|
tempmask = (guchar *) malloc(RW*RH);
|
|
|
|
|
|
|
|
|
|
gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height,
|
|
|
|
|
FALSE, FALSE);
|
|
|
|
|
gimp_pixel_rgn_init (&srcMask, mask, x1, y1, width, height,
|
|
|
|
|
FALSE, FALSE);
|
|
|
|
|
|
|
|
|
|
/* Grab enough to save a row of image and a row of mask. */
|
|
|
|
|
src_row = (guchar *) malloc (width*bytes);
|
|
|
|
|
src_mask_row = (guchar *) malloc (width);
|
|
|
|
|
|
|
|
|
|
for (i=0; i < RH; i++) {
|
|
|
|
|
whichrow=(float)i*(float)height/(float)RH;
|
|
|
|
|
gimp_pixel_rgn_get_row (&srcPR, src_row, x1, y1+whichrow, width);
|
|
|
|
|
gimp_pixel_rgn_get_row (&srcMask, src_mask_row, x1, y1+whichrow, width);
|
|
|
|
|
|
|
|
|
|
for (j=0; j < RW; j++) {
|
|
|
|
|
whichcol=(float)j*(float)width/(float)RW;
|
|
|
|
|
|
|
|
|
|
/* No selection made = each point is completely selected! */
|
|
|
|
|
if (NoSelectionMade)
|
|
|
|
|
tempmask[i*RW+j]=255;
|
|
|
|
|
else
|
|
|
|
|
tempmask[i*RW+j]=src_mask_row[whichcol];
|
|
|
|
|
|
|
|
|
|
/* Add the row to the one long string which now contains the image! */
|
|
|
|
|
tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
|
|
|
|
|
tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
|
|
|
|
|
tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
|
|
|
|
|
|
|
|
|
|
/* Hold on to the alpha as well */
|
|
|
|
|
if (bytes==4)
|
|
|
|
|
tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
temp->bpp=bytes;
|
|
|
|
|
temp->width=RW;
|
|
|
|
|
temp->height=RH;
|
|
|
|
|
temp->rgb=tempRGB;
|
|
|
|
|
temp->mask=tempmask;
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
The following is a preview function which used the same ReducedImage type!
|
|
|
|
|
Note that it uses fakes transparency (if one is present by means of
|
|
|
|
|
fake_transparency which is defined as follows:
|
|
|
|
|
|
|
|
|
|
gint fake_transparency(gint i, gint j)
|
|
|
|
|
{
|
|
|
|
|
if ( ((i%20)- 10) * ((j%20)- 10)>0 )
|
|
|
|
|
return 64;
|
|
|
|
|
else
|
|
|
|
|
return 196;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Now here's the preview function:
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
my_preview_render_function(GtkWidget *preview,
|
|
|
|
|
gint changewhat,
|
|
|
|
|
gint changewhich)
|
|
|
|
|
{
|
|
|
|
|
gint Inten, bytes=drawable->bpp;
|
|
|
|
|
gint i, j, k;
|
|
|
|
|
float partial;
|
|
|
|
|
gint RW=reduced->width;
|
|
|
|
|
gint RH=reduced->height;
|
|
|
|
|
guchar *row=malloc(bytes*RW);;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (i=0; i < RH; i++) {
|
|
|
|
|
for (j=0; j < RW; j++) {
|
|
|
|
|
|
|
|
|
|
row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
|
|
|
|
|
row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
|
|
|
|
|
row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
|
|
|
|
|
|
|
|
|
|
if (bytes==4)
|
|
|
|
|
for (k=0; k<3; k++) {
|
|
|
|
|
float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
|
|
|
|
|
row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(a);
|
|
|
|
|
gtk_widget_draw(preview,NULL);
|
|
|
|
|
gdk_flush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Applicable Routines
|
|
|
|
|
|
|
|
|
|
guint gtk_preview_get_type (void);
|
|
|
|
|
/* No idea */
|
|
|
|
|
void gtk_preview_uninit (void);
|
|
|
|
|
/* No idea */
|
|
|
|
|
GtkWidget* gtk_preview_new (GtkPreviewType type);
|
|
|
|
|
/* Described above */
|
|
|
|
|
void gtk_preview_size (GtkPreview *preview,
|
|
|
|
|
gint width,
|
|
|
|
|
gint height);
|
|
|
|
|
/* Allows you to resize an existing preview. */
|
|
|
|
|
/* Apparently there's a bug in GTK which makes */
|
|
|
|
|
/* this process messy. A way to clean up a mess */
|
|
|
|
|
/* is to manually resize the window containing */
|
|
|
|
|
/* the preview after resizing the preview. */
|
|
|
|
|
|
|
|
|
|
void gtk_preview_put (GtkPreview *preview,
|
|
|
|
|
GdkWindow *ventana,
|
|
|
|
|
GdkGC *gc,
|
|
|
|
|
gint srcx,
|
|
|
|
|
gint srcy,
|
|
|
|
|
gint destx,
|
|
|
|
|
gint desty,
|
|
|
|
|
gint width,
|
|
|
|
|
gint height);
|
|
|
|
|
/* No idea */
|
|
|
|
|
|
|
|
|
|
void gtk_preview_put_row (GtkPreview *preview,
|
|
|
|
|
guchar *src,
|
|
|
|
|
guchar *dest,
|
|
|
|
|
gint x,
|
|
|
|
|
gint y,
|
|
|
|
|
gint w);
|
|
|
|
|
/* No idea */
|
|
|
|
|
|
|
|
|
|
void gtk_preview_draw_row (GtkPreview *preview,
|
|
|
|
|
guchar *data,
|
|
|
|
|
gint x,
|
|
|
|
|
gint y,
|
|
|
|
|
gint w);
|
|
|
|
|
/* Described in the text */
|
|
|
|
|
|
|
|
|
|
void gtk_preview_set_expand (GtkPreview *preview,
|
|
|
|
|
gint expand);
|
|
|
|
|
/* No idea */
|
|
|
|
|
|
|
|
|
|
/* No clue for any of the below but */
|
|
|
|
|
/* should be standard for most widgets */
|
|
|
|
|
void gtk_preview_set_gamma (double gamma);
|
|
|
|
|
void gtk_preview_set_color_cube (guint nred_shades,
|
|
|
|
|
guint ngreen_shades,
|
|
|
|
|
guint nblue_shades,
|
|
|
|
|
guint ngray_shades);
|
|
|
|
|
void gtk_preview_set_install_cmap (gint install_cmap);
|
|
|
|
|
void gtk_preview_set_reserved (gint nreserved);
|
|
|
|
|
GdkVisual* gtk_preview_get_visual (void);
|
|
|
|
|
GdkColormap* gtk_preview_get_cmap (void);
|
|
|
|
|
GtkPreviewInfo* gtk_preview_get_info (void);
|
|
|
|
|
|
|
|
|
|
That's all, folks!
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Estableciendo los atributos de un <em/widget/<label id="sec_setting_widget_attributes">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
En este cap<61>tulo se describen las funciones utilizadas para manejar los
|
|
|
|
|
<em/widgets/. Pueden utilizarse para establecer el estilo, relleno,
|
|
|
|
|
tama<EFBFBD>o, etc...
|
|
|
|
|
|
|
|
|
|
(Puede que deba hacer una secci<63>n completa para los aceleradores.)
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_widget_install_accelerator( GtkWidget *widget,
|
|
|
|
|
GtkAcceleratorTable *table,
|
|
|
|
|
gchar *signal_name,
|
|
|
|
|
gchar key,
|
|
|
|
|
guint8 modifiers );
|
|
|
|
|
|
|
|
|
|
void gtk_widget_remove_accelerator ( GtkWidget *widget,
|
|
|
|
|
GtkAcceleratorTable *table,
|
|
|
|
|
gchar *signal_name);
|
|
|
|
|
|
|
|
|
|
void gtk_widget_activate( GtkWidget *widget );
|
|
|
|
|
|
|
|
|
|
void gtk_widget_set_name( GtkWidget *widget,
|
|
|
|
|
gchar *name );
|
|
|
|
|
|
|
|
|
|
gchar *gtk_widget_get_name( GtkWidget *widget );
|
|
|
|
|
|
|
|
|
|
void gtk_widget_set_sensitive( GtkWidget *widget,
|
|
|
|
|
gint sensitive );
|
|
|
|
|
|
|
|
|
|
void gtk_widget_set_style( GtkWidget *widget,
|
|
|
|
|
GtkStyle *style );
|
|
|
|
|
|
|
|
|
|
GtkStyle *gtk_widget_get_style( GtkWidget *widget );
|
|
|
|
|
|
|
|
|
|
GtkStyle *gtk_widget_get_default_style( void );
|
|
|
|
|
|
|
|
|
|
void gtk_widget_set_uposition( GtkWidget *widget,
|
|
|
|
|
gint x,
|
|
|
|
|
gint y );
|
|
|
|
|
|
|
|
|
|
void gtk_widget_set_usize( GtkWidget *widget,
|
|
|
|
|
gint width,
|
|
|
|
|
gint height );
|
|
|
|
|
|
|
|
|
|
void gtk_widget_grab_focus( GtkWidget *widget );
|
|
|
|
|
|
|
|
|
|
void gtk_widget_show( GtkWidget *widget );
|
|
|
|
|
|
|
|
|
|
void gtk_widget_hide( GtkWidget *widget );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Tiempos de espera, ES (<em/IO/) y funciones ociosas (<em/idle/)<label id="sec_timeouts">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Tiempos de espera
|
|
|
|
|
<p>
|
|
|
|
|
Puede que se est<73> preguntando como hacer que GTK haga algo <20>til
|
|
|
|
|
cuando se encuentra en <tt/gtk_main/. Bien, tiene varias
|
|
|
|
|
opciones. Utilizando las rutinas siguientes puede crear una funci<63>n
|
|
|
|
|
a la que se llamar<61> cada <tt/interval/ milisegundos.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_timeout_add( guint32 interval,
|
|
|
|
|
GtkFunction function,
|
|
|
|
|
gpointer data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El primer argumento es el n<>mero de milisegundos que habr<62> entre dos
|
|
|
|
|
llamadas a su funci<63>n. El segundo argumento es la funci<63>n a la que
|
|
|
|
|
desea llamar, y el tercero, los datos que le pasar<61> a <20>sta funci<63>n.
|
|
|
|
|
El valor devuelto es un <20>identificador<6F> (un valor entero) que puede
|
|
|
|
|
utilizar para detener las llamadas haciendo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_timeout_remove( gint tag );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n puede hacer que cesen las llamadas a la funci<63>n haciendo que
|
|
|
|
|
la misma devuelva cero o FALSE. Obviamente esto significa que si
|
|
|
|
|
quiere que se continue llamando a su funci<63>n, deber<65> devolver un valor
|
|
|
|
|
distinto de cero, es decir TRUE.
|
|
|
|
|
|
|
|
|
|
La declaraci<63>n de su funci<63>n deber<65>a ser algo como:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint timeout_callback( gpointer data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Monitorizando la ES
|
|
|
|
|
<p>
|
|
|
|
|
Otra caracter<65>stica divertida de GTK, es la habilidad que tiene de
|
|
|
|
|
comprobar datos por usted en un descriptor de fichero (tal y como
|
|
|
|
|
se devuelven por <tt/open(2)/ o <tt/socket(2)/). Esto es especialmente
|
|
|
|
|
<EFBFBD>til para las aplicaciones de red. La funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gdk_input_add( gint source,
|
|
|
|
|
GdkInputCondition condition,
|
|
|
|
|
GdkInputFunction function,
|
|
|
|
|
gpointer data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Donde el primer argumento es el descriptor de fichero que desea vigilar,
|
|
|
|
|
y el segundo especifica que es lo que quiere que GDK busque. Puede ser uno
|
|
|
|
|
de los siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>GDK_INPUT_READ - Llama a su funci<63>n cuando hay datos listos para
|
|
|
|
|
leerse del fichero.
|
|
|
|
|
|
|
|
|
|
<item>GDK_INPUT_WRITE - Llama a su funci<63>n cuando el descriptor del
|
|
|
|
|
fichero est<73> listo para la escritura.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Tal y como se habr<62> imaginado, el tercer argumento es la funci<63>n a la
|
|
|
|
|
que desea que se llame cuando se den las condiciones anteriores, y el
|
|
|
|
|
cuarto son los datos que se le pasar<61>n a <20>sta funci<63>n.
|
|
|
|
|
|
|
|
|
|
El valor devuelto es un identificador que puede utilizarse para que GDK
|
|
|
|
|
pare de vigilar ese fichero, utilizando la funci<63>n
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gdk_input_remove( gint tag );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La funci<63>n a la que quiere que se llame deber<65> declararse as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void input_callback( gpointer data,
|
|
|
|
|
gint source,
|
|
|
|
|
GdkInputCondition condition );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Donde <tt/source/ y <tt/condition/ est<73>n especificados m<>s arriba.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Funciones ociosas
|
|
|
|
|
<p>
|
|
|
|
|
<!-- Need to check on idle priorities - TRG -->
|
|
|
|
|
<EFBFBD>Qu<EFBFBD> le parece si tuviese una funci<63>n a la que se llamase cuando
|
|
|
|
|
no ocurriese nada?
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_idle_add( GtkFunction function,
|
|
|
|
|
gpointer data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esto hace que GTK llame a la funci<63>n especificada cuando no ocurra
|
|
|
|
|
nada m<>s.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_idle_remove( gint tag );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
No voy a explicar el significado de los argumentos ya que se parece
|
|
|
|
|
mucho a los que he explicado m<>s arriba. La funci<63>n a la que se apunta
|
|
|
|
|
mediante el primer argumento de <tt/gtk_idle_add/ ser<65> a la que se
|
|
|
|
|
llame cuando llegue el momento. Como antes, si devuelve FALSE har<61> que
|
|
|
|
|
cese de llamarse a la funci<63>n.
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Manejo avanzado de eventos y se<73>ales<label id="sec_Adv_Events_and_Signals">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Funciones se<73>al
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2>Conectando y desconectando los manejadores de se<73>al
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_signal_connect( GtkObject *object,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
gpointer func_data );
|
|
|
|
|
|
|
|
|
|
guint gtk_signal_connect_after( GtkObject *object,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
gpointer func_data );
|
|
|
|
|
|
|
|
|
|
guint gtk_signal_connect_object( GtkObject *object,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
GtkObject *slot_object );
|
|
|
|
|
|
|
|
|
|
guint gtk_signal_connect_object_after( GtkObject *object,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
GtkObject *slot_object );
|
|
|
|
|
|
|
|
|
|
guint gtk_signal_connect_full( GtkObject *object,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
GtkCallbackMarshal marshal,
|
|
|
|
|
gpointer data,
|
|
|
|
|
GtkDestroyNotify destroy_func,
|
|
|
|
|
gint object_signal,
|
|
|
|
|
gint after );
|
|
|
|
|
|
|
|
|
|
guint gtk_signal_connect_interp( GtkObject *object,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
GtkCallbackMarshal func,
|
|
|
|
|
gpointer data,
|
|
|
|
|
GtkDestroyNotify destroy_func,
|
|
|
|
|
gint after );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_connect_object_while_alive( GtkObject *object,
|
|
|
|
|
const gchar *signal,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
GtkObject *alive_object );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_connect_while_alive( GtkObject *object,
|
|
|
|
|
const gchar *signal,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
gpointer func_data,
|
|
|
|
|
GtkObject *alive_object );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_disconnect( GtkObject *object,
|
|
|
|
|
guint handler_id );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_disconnect_by_func( GtkObject *object,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
gpointer data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2>Bloqueando y desbloqueando los manejadores de se<73>al
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_signal_handler_block( GtkObject *object,
|
|
|
|
|
guint handler_id);
|
|
|
|
|
|
|
|
|
|
void gtk_signal_handler_block_by_func( GtkObject *object,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_handler_block_by_data( GtkObject *object,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_handler_unblock( GtkObject *object,
|
|
|
|
|
guint handler_id );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_handler_unblock_by_func( GtkObject *object,
|
|
|
|
|
GtkSignalFunc func,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_handler_unblock_by_data( GtkObject *object,
|
|
|
|
|
gpointer data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2>Emitiendo y deteniendo se<73>ales
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_signal_emit( GtkObject *object,
|
|
|
|
|
guint signal_id,
|
|
|
|
|
... );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_emit_by_name( GtkObject *object,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
... );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_emitv( GtkObject *object,
|
|
|
|
|
guint signal_id,
|
|
|
|
|
GtkArg *params );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_emitv_by_name( GtkObject *object,
|
|
|
|
|
const gchar *name,
|
|
|
|
|
GtkArg *params );
|
|
|
|
|
|
|
|
|
|
guint gtk_signal_n_emissions( GtkObject *object,
|
|
|
|
|
guint signal_id );
|
|
|
|
|
|
|
|
|
|
guint gtk_signal_n_emissions_by_name( GtkObject *object,
|
|
|
|
|
const gchar *name );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_emit_stop( GtkObject *object,
|
|
|
|
|
guint signal_id );
|
|
|
|
|
|
|
|
|
|
void gtk_signal_emit_stop_by_name( GtkObject *object,
|
|
|
|
|
const gchar *name );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Emisi<73>n y propagaci<63>n de se<73>ales
|
|
|
|
|
<p>
|
|
|
|
|
La emisi<73>n de se<73>ales es el proceso mediante el cual GTK+ ejecuta
|
|
|
|
|
todos los manejadores de un objeto y una se<73>al en especial.
|
|
|
|
|
|
|
|
|
|
Primero, observe que el valor devuelto por la emisi<73>n de una
|
|
|
|
|
se<EFBFBD>al es el mismo que el valor devuelto por el <em><3E>ltimo</em>
|
|
|
|
|
manipulador ejecutado. Ya que las se<73>ales de los eventos son todas
|
|
|
|
|
del tipo GTK_RUN_LAST, el manejador por defecto (proporcionado por
|
|
|
|
|
GTK+) ser<65> de este tipo, a menos que lo conecte con
|
|
|
|
|
<tt/gtk_signal_connect_after()/.
|
|
|
|
|
|
|
|
|
|
La forma en que se maneja un evento (digamos GTK_BUTTON_PRESS), es la
|
|
|
|
|
siguiente:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>Empieza con el <em>widget</em> donde ocurri<72> el evento.
|
|
|
|
|
|
|
|
|
|
<item>Emite la se<73>al gen<65>rica <tt/event/. Si esta se<73>al devuelve un
|
|
|
|
|
valor TRUE, detiene todo el proceso.
|
|
|
|
|
|
|
|
|
|
<item>En caso contrario, emite una se<73>al especifica,
|
|
|
|
|
<EFBFBD>button_press_event<EFBFBD> en nuestro caso. Si <20>sta devuelve TRUE, detiene
|
|
|
|
|
todo el proceso.
|
|
|
|
|
|
|
|
|
|
<item>En caso contrario, va al <em>widget</em> padre y repite los
|
|
|
|
|
pasos anteriores.
|
|
|
|
|
|
|
|
|
|
<item>Continua hasta que alg<6C>n manejador de se<73>al devuelva TRUE, o
|
|
|
|
|
hasta que se llegue al <em>widget</em> de m<>s alto nivel.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Algunas consecuencias son:
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>El valor que devuelva su manejador no tendr<64> ning<6E>n efecto si
|
|
|
|
|
hay un manejador por defecto, a menos que lo conecte mediante
|
|
|
|
|
<tt/gtk_signal_connect_after()/.
|
|
|
|
|
|
|
|
|
|
<item>Para evitar que el manejador por defecto se ejecute, necesita
|
|
|
|
|
conectar mediante <tt/gtk_signal_connect()/ y utilizar
|
|
|
|
|
<tt/gtk_signal_emit_stop_by_name()/ - el valor devuelto s<>lo se ve
|
|
|
|
|
afectado si la se<73>al se propaga, y no s<>lo por el hecho de emitirse.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Manejando selecciones
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Contenido
|
|
|
|
|
<p>
|
|
|
|
|
Un tipo de comunicaci<63>n entre procesos que se puede utilizar con GTK
|
|
|
|
|
son las <em/selecciones/. Una selecci<63>n identifica un conjunto de
|
|
|
|
|
datos, por ejemplo, un trozo de texto, seleccionado por el usuario de
|
|
|
|
|
alguna manera, por ejemplo, cogi<67>ndolo con el rat<61>n. S<>lo una
|
|
|
|
|
aplicaci<EFBFBD>n en un <em/display/ (la <em>propietaria</em>) puede tener
|
|
|
|
|
una selecci<63>n en particular en un momento dado, por lo que cuando una
|
|
|
|
|
aplicaci<EFBFBD>n pide una selecci<63>n, el propietario previo debe indicar al
|
|
|
|
|
usuario que la selecci<63>n ya no es v<>lida. Otras aplicaciones pueden
|
|
|
|
|
pedir el contenido de la selecci<63>n de diferentes formas, llamadas
|
|
|
|
|
<em/objetivos/. Puede haber cualquier n<>mero de selecciones, pero la
|
|
|
|
|
mayor<EFBFBD>a de las aplicacion X s<>lo pueden manejar una, la <em/selecci<63>n
|
|
|
|
|
primaria/.
|
|
|
|
|
|
|
|
|
|
En muchos casos, no es necesario para una aplicaci<63>n GTK tratar por
|
|
|
|
|
s<EFBFBD> misma con las selecciones. Los <em/widgets/ est<73>ndar, como el
|
|
|
|
|
<em/widget/ Entry, ya tienen la posibilidad de crear la selecci<63>n
|
|
|
|
|
cuando sea necesario (p.e., cuando el usuario pase el rat<61>n sobre el
|
|
|
|
|
texto manteniendo el bot<6F>n derecho del rat<61>n pulsado), y de recoger
|
|
|
|
|
los contenidos de la selecci<63>n propiedad de otro <em/widget/, o de
|
|
|
|
|
otra aplicaci<63>n (p.e., cuando el usuario pulsa el segundo bot<6F>n del
|
|
|
|
|
rat<EFBFBD>n). Sin embargo, pueden haber casos en los que quiera darle a
|
|
|
|
|
otros <em/widgets/ la posibilidad de proporcionar la selecci<63>n, o
|
|
|
|
|
puede que quiera recuperar objetivos que no est<73>n admitidos por
|
|
|
|
|
defecto.
|
|
|
|
|
|
|
|
|
|
Un concepto fundamental que es necesario para comprender el manejo de
|
|
|
|
|
la selecci<63>n es el de <em><3E>tomo</em>. Un <20>tomo es un entero que
|
|
|
|
|
identifica de una manera un<75>voca una cadena (en un cierto
|
|
|
|
|
<em/display/). Ciertos <20>tomos est<73>n predefinidos por el servidor X, y
|
|
|
|
|
en algunos casos hay constantes en <tt>gtk.h</tt> que corresponden a
|
|
|
|
|
estos <20>tomos. Por ejemplo la constante <tt>GDK_PRIMARY_SELECTION</tt>
|
|
|
|
|
corresponde a la cadena <20>PRIMARY<52>. En otros casos, deber<65>a utilizar
|
|
|
|
|
las funciones <tt>gdk_atom_intern()</tt>, para obtener el <20>tomo
|
|
|
|
|
correspondiente a una cadena, y <tt>gdk_atom_name()</tt>, para obtener
|
|
|
|
|
el nombre de un <20>tomo. Ambas, selecciones y objetivos, est<73>n
|
|
|
|
|
identificados por <20>tomos.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Recuperando la selecci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
Recuperar la selecci<63>n es un proceso as<61>ncrono. Para comenzar el
|
|
|
|
|
proceso, deber<65> llamar a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_selection_convert( GtkWidget *widget,
|
|
|
|
|
GdkAtom selection,
|
|
|
|
|
GdkAtom target,
|
|
|
|
|
guint32 time );
|
|
|
|
|
</verb</tscreen>
|
|
|
|
|
|
|
|
|
|
Este proceso <em/convierte/ la selecci<63>n en la forma especificada por
|
|
|
|
|
<tt/target/. Si es posible, el campo <tt/time/ debe ser el tiempo
|
|
|
|
|
desde que el evento lanz<6E> la selecci<63>n. Esto ayuda a asegurarse de que
|
|
|
|
|
los eventos ocurran en el orden en que el usuario los ha pedido. Sin
|
|
|
|
|
embargo, si no est<73> disponible (por ejemplo, si se empez<65> la
|
|
|
|
|
conversi<EFBFBD>n por una se<73>al de <20>pulsaci<63>n<EFBFBD>), entonces puede utilizar la
|
|
|
|
|
constante <tt>GDK_CURRENT_TIME</tt>.
|
|
|
|
|
|
|
|
|
|
Cuando el propietario de la selecci<63>n responda a la petici<63>n, se
|
|
|
|
|
enviar<EFBFBD> una se<73>al <20>selection_received<65> a su aplicaci<63>n. El manejador
|
|
|
|
|
de esta se<73>al recibe un puntero a una estructura
|
|
|
|
|
<tt>GtkSelectionData</tt>, que se define como:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GtkSelectionData
|
|
|
|
|
{
|
|
|
|
|
GdkAtom selection;
|
|
|
|
|
GdkAtom target;
|
|
|
|
|
GdkAtom type;
|
|
|
|
|
gint format;
|
|
|
|
|
guchar *data;
|
|
|
|
|
gint length;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt>selection</tt> y <tt>target</tt> son los valores que di<64> en su
|
|
|
|
|
llamada a <tt>gtk_selection_convert()</tt>. <tt>type</tt> es un <20>tomo
|
|
|
|
|
que identifica el tipo de datos devueltos por el propietario de la
|
|
|
|
|
selecci<EFBFBD>n. Algunos valores posibles son <20>STRING<4E>, un cadena de
|
|
|
|
|
caracteres latin-1, <20>ATOM<4F>, una serie de <20>tomos, <20>INTEGER<45>, un
|
|
|
|
|
entero, etc. Muchos objetivos s<>lo pueden devolver un
|
|
|
|
|
tipo. <tt/format/ da la longitud de las unidades (por ejemplo
|
|
|
|
|
caracteres) en bits. Normalmente, no tiene porque preocuparse de todo
|
|
|
|
|
esto cuando recibe datos. <tt/data/ es un puntero a los datos
|
|
|
|
|
devueltos, y <tt/length/ da la longitud de los datos devueltos, en
|
|
|
|
|
bytes. Si <tt/length/ es negativo, es que a ocurrido un error y no se
|
|
|
|
|
puede obtener la selecci<63>n. Esto podr<64>a ocurrir si no hay ninguna
|
|
|
|
|
aplicaci<EFBFBD>n que sea la propietaria de la selecci<63>n, o si pide un
|
|
|
|
|
objetivo que la aplicaci<63>n no admite. Actualmente se garantiza que el
|
|
|
|
|
b<EFBFBD>fer tendr<64> un byte m<>s que <tt/length/; el byte extra siempre ser<65>
|
|
|
|
|
cero, por lo que no es necesario hacer una copia de las cadenas s<>lo
|
|
|
|
|
para a<>adirles un car<61>cter nulo al final.
|
|
|
|
|
|
|
|
|
|
En el siguiente ejemplo, recuperamos el objetivo especial <20>TARGETS<54>,
|
|
|
|
|
que es una lista de todos los objetivos en los que se puede convertir
|
|
|
|
|
la selecci<63>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo selection gettargets.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
void selection_received (GtkWidget *widget,
|
|
|
|
|
GtkSelectionData *selection_data,
|
|
|
|
|
gpointer data);
|
|
|
|
|
|
|
|
|
|
/* Manejador de se<73>al invocado cuando el usuario pulsa en el bot<6F>n
|
|
|
|
|
"Get Targets" */
|
|
|
|
|
void
|
|
|
|
|
get_targets (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
static GdkAtom targets_atom = GDK_NONE;
|
|
|
|
|
|
|
|
|
|
/* Obtener el atom correpondiente a la cadena "TARGETS" */
|
|
|
|
|
if (targets_atom == GDK_NONE)
|
|
|
|
|
targets_atom = gdk_atom_intern ("TARGETS", FALSE);
|
|
|
|
|
|
|
|
|
|
/* Y pide el objetivo "TARGETS" de la selecci<63>n primaria */
|
|
|
|
|
gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
|
|
|
|
|
GDK_CURRENT_TIME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Manipulador de se<73>al llamado cuando el propietario de la se<73>al
|
|
|
|
|
* devuelve los datos */
|
|
|
|
|
void
|
|
|
|
|
selection_received (GtkWidget *widget, GtkSelectionData *selection_data,
|
|
|
|
|
gpointer data)
|
|
|
|
|
{
|
|
|
|
|
GdkAtom *atoms;
|
|
|
|
|
GList *item_list;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* **** IMPORTANTE **** Comprobar si se da la recuperaci<63>n de los
|
|
|
|
|
* datos */
|
|
|
|
|
if (selection_data->length < 0)
|
|
|
|
|
{
|
|
|
|
|
g_print ("Selection retrieval failed\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Asegurarse de que obtenemos los datos de la forma esperada */
|
|
|
|
|
if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
|
|
|
|
|
{
|
|
|
|
|
g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Imprimir los atoms que hemos recibido */
|
|
|
|
|
atoms = (GdkAtom *)selection_data->data;
|
|
|
|
|
|
|
|
|
|
item_list = NULL;
|
|
|
|
|
for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
|
|
|
|
|
{
|
|
|
|
|
char *name;
|
|
|
|
|
name = gdk_atom_name (atoms[i]);
|
|
|
|
|
if (name != NULL)
|
|
|
|
|
g_print ("%s\n",name);
|
|
|
|
|
else
|
|
|
|
|
g_print ("(bad atom)\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* Crear la ventana superior */
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Event Box");
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_exit), NULL);
|
|
|
|
|
|
|
|
|
|
/* Crear un bot<6F>n que el usuario puede pulsar para obtener los
|
|
|
|
|
* objetivos */
|
|
|
|
|
|
|
|
|
|
boton = gtk_button_new_with_label ("Get Targets");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), boton);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (get_targets), NULL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(boton), "selection_received",
|
|
|
|
|
GTK_SIGNAL_FUNC (selection_received), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Proporcionando la selecci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
Proporcionar la selecci<63>n es un poco m<>s complicado. Debe registrar
|
|
|
|
|
los manejadores a los que se llamar<61>n cuando se le pida la
|
|
|
|
|
selecci<EFBFBD>n. Por cada par selecci<63>n/objetivo que quiera manejar, deber<65>
|
|
|
|
|
hacer una llamada a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_selection_add_handler( GtkWidget *widget,
|
|
|
|
|
GdkAtom selection,
|
|
|
|
|
GdkAtom target,
|
|
|
|
|
GtkSelectionFunction function,
|
|
|
|
|
GtkRemoveFunction remove_func,
|
|
|
|
|
gpointer data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/widget/, <tt/selection/, y <tt/target/ identifican las peticiones
|
|
|
|
|
que este manejador puede manipular. Si <tt/remove_func/ no es NULL, se
|
|
|
|
|
le llamar<61> cuando se elimine el manejador de la se<73>al. Esto es <20>til,
|
|
|
|
|
por ejemplo, para los lenguajes interpretados que necesitan mantener
|
|
|
|
|
una memoria de las referencias a <tt/data/.
|
|
|
|
|
|
|
|
|
|
La funci<63>n de llamada tiene el prototipo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
typedef void (*GtkSelectionFunction)( GtkWidget *widget,
|
|
|
|
|
GtkSelectionData *selection_data,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El <tt/GtkSelectionData/ es el mismo que hay m<>s arriba, pero esta
|
|
|
|
|
vez, seremos nosotros los responsables de rellenar los campos
|
|
|
|
|
<tt/type/, <tt/format/, <tt/data/, y <tt/length/. (El campo
|
|
|
|
|
<tt/format/ es importante - el servidor X lo utiliza para saber si
|
|
|
|
|
tienen que intercambiarse los bytes que forman los datos o
|
|
|
|
|
no. Normalmente ser<65> 8 - es decir un car<61>cter - o 32 - es decir un
|
|
|
|
|
entero.) Esto se hace llamando a la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_selection_data_set( GtkSelectionData *selection_data,
|
|
|
|
|
GdkAtom type,
|
|
|
|
|
gint format,
|
|
|
|
|
guchar *data,
|
|
|
|
|
gint length );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n tiene la responsabilidad de hacer una copia de los datos
|
|
|
|
|
para que no tenga que preocuparse de ir guard<72>ndolos. (No deber<65>a
|
|
|
|
|
rellenar los campos de la estructura <tt/GtkSelectionData/ a mano.)
|
|
|
|
|
|
|
|
|
|
Cuando haga falta, puede pedir el propietario de la selecci<63>n llamando
|
|
|
|
|
a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_selection_owner_set( GtkWidget *widget,
|
|
|
|
|
GdkAtom selection,
|
|
|
|
|
guint32 time );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Si otra aplicaci<63>n pide el propietario de la selecci<63>n, recibira un
|
|
|
|
|
<EFBFBD>selection_clear_event<EFBFBD>.
|
|
|
|
|
|
|
|
|
|
Como ejemplo de proporciar la selecci<63>n, el programa siguiente le a<>ade
|
|
|
|
|
la posibilidad de selecci<63>n a un bot<6F>n de comprobaci<63>n. Cuando se presione
|
|
|
|
|
el bot<6F>n de comprobaci<63>n, el programa pedir<69> la selecci<63>n primaria. El
|
|
|
|
|
<EFBFBD>nico objetivo que admite es un objetivo <20>STRING<4E> (aparte de ciertos
|
|
|
|
|
objetivos como "TARGETS", proporcionados por GTK). Cuando se pida este
|
|
|
|
|
objetivo, se devolver<65> una representaci<63>n del tiempo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo selection setselection.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
|
|
/* Funci<63>n de llamada para cuando el usuario cambia la selecci<63>n */
|
|
|
|
|
void
|
|
|
|
|
selection_toggled (GtkWidget *widget, gint *have_selection)
|
|
|
|
|
{
|
|
|
|
|
if (GTK_TOGGLE_BUTTON(widget)->active)
|
|
|
|
|
{
|
|
|
|
|
*have_selection = gtk_selection_owner_set (widget,
|
|
|
|
|
GDK_SELECTION_PRIMARY,
|
|
|
|
|
GDK_CURRENT_TIME);
|
|
|
|
|
/* Si la demanda de la selecci<63>n ha fallado, ponemos el bot<6F>n en
|
|
|
|
|
* estado apagado */
|
|
|
|
|
if (!*have_selection)
|
|
|
|
|
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (*have_selection)
|
|
|
|
|
{
|
|
|
|
|
/* Antes de eliminar la seleci<63>n poniendo el propietario a
|
|
|
|
|
* NULL, comprobamos si somos el propietario actual */
|
|
|
|
|
if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
|
|
|
|
|
gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
|
|
|
|
|
GDK_CURRENT_TIME);
|
|
|
|
|
*have_selection = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Llamado cuando otra aplicaci<63>n pide la selecci<63>n */
|
|
|
|
|
gint
|
|
|
|
|
selection_clear (GtkWidget *widget, GdkEventSelection *event,
|
|
|
|
|
gint *have_selection)
|
|
|
|
|
{
|
|
|
|
|
*have_selection = FALSE;
|
|
|
|
|
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Proporciona el tiempo actual como selecci<63>n. */
|
|
|
|
|
void
|
|
|
|
|
selection_handle (GtkWidget *widget,
|
|
|
|
|
GtkSelectionData *selection_data,
|
|
|
|
|
gpointer data)
|
|
|
|
|
{
|
|
|
|
|
gchar *timestr;
|
|
|
|
|
time_t current_time;
|
|
|
|
|
|
|
|
|
|
current_time = time (NULL);
|
|
|
|
|
timestr = asctime (localtime(&current_time));
|
|
|
|
|
/* Cuando devolvemos una cadena, no debe terminar en NULL. La
|
|
|
|
|
* funci<63>n lo har<61> por nosotros */
|
|
|
|
|
|
|
|
|
|
gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
|
|
|
|
|
8, timestr, strlen(timestr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
|
|
|
|
|
GtkWidget *selection_button;
|
|
|
|
|
|
|
|
|
|
static int have_selection = FALSE;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
/* Crear la ventana superior */
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Event Box");
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_exit), NULL);
|
|
|
|
|
|
|
|
|
|
/* Crear un bot<6F>n de selecci<63>n para que actue como la selecci<63>n */
|
|
|
|
|
|
|
|
|
|
selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), selection_button);
|
|
|
|
|
gtk_widget_show (selection_button);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
|
|
|
|
|
GTK_SIGNAL_FUNC (selection_toggled), &have_selection);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
|
|
|
|
|
GTK_SIGNAL_FUNC (selection_clear), &have_selection);
|
|
|
|
|
|
|
|
|
|
gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
|
|
|
|
|
GDK_SELECTION_TYPE_STRING,
|
|
|
|
|
selection_handle, NULL);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (selection_button);
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Glib<label id="sec_glib">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
Glib proporciona muchas definiciones y funciones <20>tiles disponibles
|
|
|
|
|
para su utilizaci<63>n cuando se crean aplicaciones GDK y GTK. Har<61> una
|
|
|
|
|
lista con todas ellas incluyendo una peque<75>a explicaci<63>n. Muchas no
|
|
|
|
|
son m<>s que duplicados de funciones est<73>ndar de libc por lo que no
|
|
|
|
|
entrar<EFBFBD> en detalle en la explicaci<63>n de las mismas. Esta secci<63>n est<73>
|
|
|
|
|
pensada principalmente para que se utilice como referencia, para que
|
|
|
|
|
sepa que es lo que puede utilizar.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Definiciones
|
|
|
|
|
<p>
|
|
|
|
|
Las definiciones para los l<>mites de muchos de los tipos est<73>ndar son:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
G_MINFLOAT
|
|
|
|
|
G_MAXFLOAT
|
|
|
|
|
G_MINDOUBLE
|
|
|
|
|
G_MAXDOUBLE
|
|
|
|
|
G_MINSHORT
|
|
|
|
|
G_MAXSHORT
|
|
|
|
|
G_MININT
|
|
|
|
|
G_MAXINT
|
|
|
|
|
G_MINLONG
|
|
|
|
|
G_MAXLONG
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Y tambi<62>n, los siguientes <tt/typedefs/. Cuando no se especifica el
|
|
|
|
|
tipo que deber<65>a aparecer a la izquierda significa que el mismo se
|
|
|
|
|
establecer<EFBFBD> din<69>micamente en funci<63>n de la arquitectura. <20>Recuerde
|
|
|
|
|
evitar los calculos relativos al tama<6D>o de un puntero si quiere que
|
|
|
|
|
su aplicaci<63>n sea portable! P.e., un puntero en un Alpha tiene 8
|
|
|
|
|
bytes, pero 4 en Intel.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
char gchar;
|
|
|
|
|
short gshort;
|
|
|
|
|
long glong;
|
|
|
|
|
int gint;
|
|
|
|
|
char gboolean;
|
|
|
|
|
|
|
|
|
|
unsigned char guchar;
|
|
|
|
|
unsigned short gushort;
|
|
|
|
|
unsigned long gulong;
|
|
|
|
|
unsigned int guint;
|
|
|
|
|
|
|
|
|
|
float gfloat;
|
|
|
|
|
double gdouble;
|
|
|
|
|
long double gldouble;
|
|
|
|
|
|
|
|
|
|
void* gpointer;
|
|
|
|
|
|
|
|
|
|
gint8
|
|
|
|
|
guint8
|
|
|
|
|
gint16
|
|
|
|
|
guint16
|
|
|
|
|
gint32
|
|
|
|
|
guint32
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Listas doblemente enlazadas
|
|
|
|
|
<p>
|
|
|
|
|
Las funciones siguientes se utilizan para crear, manipular, y destruir
|
|
|
|
|
listas doblemente enlazadas. Supondr<64> que sabe lo que son las listas
|
|
|
|
|
enlazadas, ya que explicarlas va m<>s all<6C> del objetivo de este
|
|
|
|
|
documento. Por supuesto, no es necesario que conozca como manejar
|
|
|
|
|
todo esto para utilizar GTK, pero siempre es bonito aprender cosas.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GList *g_list_alloc( void );
|
|
|
|
|
|
|
|
|
|
void g_list_free( GList *list );
|
|
|
|
|
|
|
|
|
|
void g_list_free_1( GList *list );
|
|
|
|
|
|
|
|
|
|
GList *g_list_append( GList *list,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
GList *g_list_prepend( GList *list,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
GList *g_list_insert( GList *list,
|
|
|
|
|
gpointer data,
|
|
|
|
|
gint posicion );
|
|
|
|
|
|
|
|
|
|
GList *g_list_remove( GList *list,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
GList *g_list_remove_link( GList *list,
|
|
|
|
|
GList *link );
|
|
|
|
|
|
|
|
|
|
GList *g_list_reverse( GList *list );
|
|
|
|
|
|
|
|
|
|
GList *g_list_nth( GList *list,
|
|
|
|
|
gint n );
|
|
|
|
|
|
|
|
|
|
GList *g_list_find( GList *list,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
GList *g_list_last( GList *list );
|
|
|
|
|
|
|
|
|
|
GList *g_list_first( GList *list );
|
|
|
|
|
|
|
|
|
|
gint g_list_length( GList *list );
|
|
|
|
|
|
|
|
|
|
void g_list_foreach( GList *list,
|
|
|
|
|
GFunc func,
|
|
|
|
|
gpointer user_data );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Listas simplemente enlazadas
|
|
|
|
|
<p>
|
|
|
|
|
Muchas de las funciones para las listas enlazadas son id<69>nticas a las
|
|
|
|
|
de m<>s arriba. Aqu<71> hay una lista completa:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GSList *g_slist_alloc( void );
|
|
|
|
|
|
|
|
|
|
void g_slist_free( GSList *list );
|
|
|
|
|
|
|
|
|
|
void g_slist_free_1( GSList *list );
|
|
|
|
|
|
|
|
|
|
GSList *g_slist_append( GSList *list,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
GSList *g_slist_prepend( GSList *list,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
GSList *g_slist_insert( GSList *list,
|
|
|
|
|
gpointer data,
|
|
|
|
|
gint posicion );
|
|
|
|
|
|
|
|
|
|
GSList *g_slist_remove( GSList *list,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
GSList *g_slist_remove_link( GSList *list,
|
|
|
|
|
GSList *link );
|
|
|
|
|
|
|
|
|
|
GSList *g_slist_reverse( GSList *list );
|
|
|
|
|
|
|
|
|
|
GSList *g_slist_nth( GSList *list,
|
|
|
|
|
gint n );
|
|
|
|
|
|
|
|
|
|
GSList *g_slist_find( GSList *list,
|
|
|
|
|
gpointer data );
|
|
|
|
|
|
|
|
|
|
GSList *g_slist_last( GSList *list );
|
|
|
|
|
|
|
|
|
|
gint g_slist_length( GSList *list );
|
|
|
|
|
|
|
|
|
|
void g_slist_foreach( GSList *list,
|
|
|
|
|
GFunc func,
|
|
|
|
|
gpointer user_data );
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Control de la memoria
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gpointer g_malloc( gulong size );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Reemplaza a <tt/malloc()/. No necesita comprobar el valor devuelto, ya
|
|
|
|
|
que ya lo hace por usted esta funci<63>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gpointer g_malloc0( gulong size );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Lo mismo que antes, pero rellena con ceros la memoria antes de
|
|
|
|
|
devolver un puntero a ella.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gpointer g_realloc( gpointer mem,
|
|
|
|
|
gulong size );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Vuelve a reservar <tt/size/ bites de memoria empezando en
|
|
|
|
|
<tt/mem/. Obviamente, la memoria debe haber sido previamente reservada.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void g_free( gpointer mem );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Libera la memoria. F<>cil.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void g_mem_profile( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Crea un fichero donde vuelca la memoria que se est<73> utilizando, pero
|
|
|
|
|
tiene que a<>adir <tt/#define MEM_PROFILE/ en lo alto de
|
|
|
|
|
<tt>glib/gmem.c</tt> y tendr<64> que hacer un make y un make install.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void g_mem_check( gpointer mem );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Comprueba que una direcci<63>n de memoria es v<>lida. Tiene que a<>adir
|
|
|
|
|
<tt/#define MEM_CHECK/ en lo alto de <tt/gmem.c/ y tiene que hacer un
|
|
|
|
|
make y un make install.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Timers
|
|
|
|
|
<p>
|
|
|
|
|
Temporizadores...
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GTimer *g_timer_new( void );
|
|
|
|
|
|
|
|
|
|
void g_timer_destroy( GTimer *timer );
|
|
|
|
|
|
|
|
|
|
void g_timer_start( GTimer *timer );
|
|
|
|
|
|
|
|
|
|
void g_timer_stop( GTimer *timer );
|
|
|
|
|
|
|
|
|
|
void g_timer_reset( GTimer *timer );
|
|
|
|
|
|
|
|
|
|
gdouble g_timer_elapsed( GTimer *timer,
|
|
|
|
|
gulong *microseconds );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Manejo de cadenas de texto
|
|
|
|
|
<p>
|
|
|
|
|
Un pu<70>ado de funciones para manejar cadenas de texto. Parecen muy
|
|
|
|
|
interesantes, y probablemente sean mejores en muchos aspectos que las
|
|
|
|
|
funciones est<73>ndar de C, pero necesitan documentaci<63>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GString *g_string_new( gchar *init );
|
|
|
|
|
|
|
|
|
|
void g_string_free( GString *string,
|
|
|
|
|
gint free_segment );
|
|
|
|
|
|
|
|
|
|
GString *g_string_assign( GString *lval,
|
|
|
|
|
gchar *rval );
|
|
|
|
|
|
|
|
|
|
GString *g_string_truncate( GString *string,
|
|
|
|
|
gint len );
|
|
|
|
|
|
|
|
|
|
GString *g_string_append( GString *string,
|
|
|
|
|
gchar *val );
|
|
|
|
|
|
|
|
|
|
GString *g_string_append_c( GString *string,
|
|
|
|
|
gchar c );
|
|
|
|
|
|
|
|
|
|
GString *g_string_prepend( GString *string,
|
|
|
|
|
gchar *val );
|
|
|
|
|
|
|
|
|
|
GString *g_string_prepend_c( GString *string,
|
|
|
|
|
gchar c );
|
|
|
|
|
|
|
|
|
|
void g_string_sprintf( GString *string,
|
|
|
|
|
gchar *fmt,
|
|
|
|
|
...);
|
|
|
|
|
|
|
|
|
|
void g_string_sprintfa ( GString *string,
|
|
|
|
|
gchar *fmt,
|
|
|
|
|
... );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Funciones de error y funciones varias
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gchar *g_strdup( const gchar *str );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Reemplaza a la funci<63>n <tt/strdup/. Copia el contenido de la cadena
|
|
|
|
|
original en un nuevo lugar en memoria, y devuelve un puntero al nuevo
|
|
|
|
|
lugar.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gchar *g_strerror( gint errnum );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Recomiendo utilizar esta funci<63>n para todos los mensages de error. Es
|
|
|
|
|
mucho m<>s bonita, y m<>s portable que <tt/perror()/ y dem<65>s funciones
|
|
|
|
|
cl<EFBFBD>sicas. La salida es normalmente de la forma:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
nombre del programa:funci<63>n que fall<6C>:fichero o descripci<63>n adicional:strerror
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> hay un ejemplo de una llamada utilizada en nuestro programa
|
|
|
|
|
<tt/hello_world/:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void g_error( gchar *format, ... );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Imprime un mensaje de error. El formato es como el de <tt/printf/,
|
|
|
|
|
pero le a<>ade <tt/** ERROR **: / a su mensaje, y sale del
|
|
|
|
|
programa. S<>lo para errores fatales.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void g_warning( gchar *format, ... );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El mismo que el anterior, pero a<>ade "** WARNING **: ", y no sale del
|
|
|
|
|
programa.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void g_message( gchar *format, ... );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Imprime <tt/message: / antes de la cadena que le pase.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void g_print( gchar *format, ... );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Reemplazo de <tt/printf()/.
|
|
|
|
|
|
|
|
|
|
Y nuestra <20>ltima funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gchar *g_strsignal( gint signum );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Imprime el nombre de la se<73>al del sistema Unix que corresponde con el
|
|
|
|
|
n<EFBFBD>mero <tt/signum/. <20>til para las funciones gen<65>ricas de manejo de se<73>al.
|
|
|
|
|
|
|
|
|
|
Todo lo anterior est<73> m<>s o menos robado de <tt/glib.h/. Si alguien
|
|
|
|
|
quiere documentar una funci<63>n, <20>s<EFBFBD>lo tiene que enviarme un correo-e!
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Ficheros rc de GTK
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
GTK tiene su propia forma de conseguir los valores por defecto de una
|
|
|
|
|
aplicaci<EFBFBD>n, y es utilizando los ficheros <tt/rc/. Pueden ser
|
|
|
|
|
utilizados para poner los colores de cualquier <em/widget/, y tambi<62>n
|
|
|
|
|
pueden utilizarse para poner im<69>genes como fondos de algunos <em/widgets/.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Funciones para los ficheros <tt/rc/
|
|
|
|
|
<p>
|
|
|
|
|
Cuando empiece su aplicaci<63>n, deber<65>a incluir una llamada a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_rc_parse( char *filename );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Poniendo el nombre del fichero de su rc. Esto har<61> que GTK analice
|
|
|
|
|
este fichero, y utilice el estilo para los <em/widgets/ que se definan
|
|
|
|
|
ah<EFBFBD>.
|
|
|
|
|
|
|
|
|
|
Si desea tener un conjunto especial de <em/widgets/ con un estilo
|
|
|
|
|
diferente de los otros, o realizar cualquier otra divisi<73>n l<>gica de
|
|
|
|
|
los <em/widgets/, haga una llamada a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_widget_set_name( GtkWidget *widget,
|
|
|
|
|
gchar *name );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Pas<EFBFBD>ndole su nuevo <em/widget/ como primer argumento, y el nombre que
|
|
|
|
|
desea darle como el segundo. Mediante este nombre podr<64> cambiar los
|
|
|
|
|
atributos de ese <em/widget/.
|
|
|
|
|
|
|
|
|
|
Si hacemos algo as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
boton = gtk_button_new_with_label ("Bot<6F>n especial");
|
|
|
|
|
gtk_widget_set_name (boton, "bot<6F>n especial");
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El bot<6F>n tendr<64> el nombre <20>bot<6F>n especial<61> y podr<64>a hacersele
|
|
|
|
|
referencia en el fichero <tt/rc/ como <20>bot<6F>n especial.GtkButton<6F>.
|
|
|
|
|
[<--- <20>Verificadme! ]
|
|
|
|
|
|
|
|
|
|
El fichero de ejemplo <tt/rc/ que mostramos a continuaci<63>n, establece las
|
|
|
|
|
propiedades de la ventana principal, y deja que todos los hijos de la
|
|
|
|
|
ventana principal hereden el estilo descrito por <20>main button<6F>. El
|
|
|
|
|
c<EFBFBD>digo utilizado en la aplicaci<63>n es:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_widget_set_name (ventana, "main window");
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Y el estilo se define en el fichero <tt/rc/ utilizando:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
widget "main window.*GtkButton*" style "main_button"
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Qu<EFBFBD> hace que todos los <em/widgets/ GtkButton de la <20>main window<6F>
|
|
|
|
|
(ventana principal) tengan el estilo "main_buttons" tal y como se
|
|
|
|
|
define en el fichero <tt/rc/.
|
|
|
|
|
|
|
|
|
|
Como puede ver, es un sistema muy poderoso y flexible. Utilice su
|
|
|
|
|
imaginaci<EFBFBD>n para aprovecharse al m<>ximo de este sistema.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Formato de los ficheros <tt/rc/ de GTK
|
|
|
|
|
<p>
|
|
|
|
|
El formato de los ficheros GTK se muestra en el ejemplo de m<>s
|
|
|
|
|
abajo. <20>ste es el fichero <tt/testgtkrc/ de la distribuci<63>n GTK, pero he
|
|
|
|
|
a<EFBFBD>adido unos cuantos comentarios y alguna cosilla. Puede que quiera
|
|
|
|
|
incluir esta explicaci<63>n en su aplicaci<63>n para permitir al usuario
|
|
|
|
|
personalizar su aplicaci<63>n.
|
|
|
|
|
|
|
|
|
|
Hay varias directivas para cambiar los atributos de un <em/widget/.
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>fg - Establece el color de primer plano de un <em/widget/.
|
|
|
|
|
<item>bg - Establece el color de fondo de un <em/widget/.
|
|
|
|
|
<item>bg_pixmap - Establece la imagen que servir<69> de fondo al
|
|
|
|
|
<em/widget/ (como mosaico).
|
|
|
|
|
<item>font - Establece el tipo de letra que se utilizar<61> con el
|
|
|
|
|
<em/widget/.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Adem<EFBFBD>s de esto, hay varios estados en el que puede estar un
|
|
|
|
|
<em/widget/, y puede especificar diferentes colores, im<69>genes y tipos
|
|
|
|
|
de letra para cada estado. Estos estados son:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>NORMAL - El estado normal de un <em/widget/, sin el rat<61>n sobre
|
|
|
|
|
<EFBFBD>l, y no siendo presionado, etc...
|
|
|
|
|
<item>PRELIGHT - Cuando el rat<61>n est<73> sobre este <em/widget/ se
|
|
|
|
|
utilizar<EFBFBD>n los colores definidos para este estado.
|
|
|
|
|
<item>ACTIVE - Cuando se presiona o se pulsa sobre el <em/widget/,
|
|
|
|
|
estar<EFBFBD> activo, y los atributos asignados por est<73> etiqueta ser<65>n
|
|
|
|
|
utilizados.
|
|
|
|
|
<item>INSENSITIVE - Cuando un <em/widget/ es insensible, y no se puede
|
|
|
|
|
activar, tomar<61> estos atributos.
|
|
|
|
|
<item>SELECTED - Cuando se seleccione un objeto, tomar<61> estos atributos.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Cuando se utilizan las directivas <20>fg<66> y <20>bg<62> para poner los colores de
|
|
|
|
|
los <em/widgets/, se utilizar<61> el formato siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
fg[<STATE>] = { Red, Green, Blue }
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Donde <tt/STATE/ es uno de los estados anteriores (PRELIGHT, ACTIVE,
|
|
|
|
|
etc...), y el <tt/Red/, <tt/Green/ y <tt/Blue/ (Rojo, Verde y Azul)
|
|
|
|
|
son valores en el rango 0 - 1.0, { 1.0, 1.0, 1.0 } es blanco. Deben
|
|
|
|
|
estar en formato flotante, o ser<65>n un 0, por lo que "1" no funcionar<61>,
|
|
|
|
|
debe ser "1.0". Un "0" est<73> bien ya que es lo mismo si no se
|
|
|
|
|
reconoce. Los valores no reconocidos se pondr<64>n a 0.
|
|
|
|
|
|
|
|
|
|
<tt/bg_pixmap/ es muy similar al de arriba, salvo que los colores se
|
|
|
|
|
reemplazan por un nombre de fichero.
|
|
|
|
|
|
|
|
|
|
<tt/pixmap_path/ es una lista de los caminos (<em/paths/) separados por
|
|
|
|
|
<EFBFBD>:<3A>. Estos caminos se utilizar<61>n para buscar cualquier imagen que
|
|
|
|
|
indique.
|
|
|
|
|
|
|
|
|
|
La directiva sobre el tipo de letra es simplemente:
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
font = "<nombre del tipo de letra>"
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Donde lo <20>nico dif<69>cil es saber la cadena del tipo de letra a
|
|
|
|
|
elegir. Utilizar <tt/xfontsel/ o un programa similar deber<65>a ayudar.
|
|
|
|
|
|
|
|
|
|
El <tt/widget_class/ establece el estilo de una clase de
|
|
|
|
|
<em/widgets/. Estas clases se muestran en el resumen de <em/widgets/
|
|
|
|
|
dentro de la jerarqu<71>a de clases.
|
|
|
|
|
|
|
|
|
|
La directiva <tt/widget/ hace que un conjunto espec<65>fico de
|
|
|
|
|
<em/widgets/ tenga un estido determinado, sobreescribiendo cualquier
|
|
|
|
|
estilo anterior que tuviese esa clase de <em/widgets/. Estos
|
|
|
|
|
<em/widgets/ se registran dentro de la aplicaci<63>n utilizando una
|
|
|
|
|
llamada a <tt/gtk_widget_set_name()/. Esto le permitir<69> especificar
|
|
|
|
|
los atributos de un <em/widget/ uno a uno, en vez de establecer los
|
|
|
|
|
atributos de toda una clase <em/widget/. Deber<65> documentar cualquiera
|
|
|
|
|
de estos <em/widgets/ especiales para que los usuarios puedan
|
|
|
|
|
personalizarlos.
|
|
|
|
|
|
|
|
|
|
Cuando la palabra clave <tt/parent/ se utiliza como un atributo, el
|
|
|
|
|
<em/widget/ tomar<61> los atributos de su padre en la aplicaci<63>n.
|
|
|
|
|
|
|
|
|
|
Puede asignar los atributos de un estilo previamente definido a uno
|
|
|
|
|
nuevo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
style "main_button" = "button"
|
|
|
|
|
{
|
|
|
|
|
font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
|
|
|
|
|
bg[PRELIGHT] = { 0.75, 0, 0 }
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Este ejemplo toma el estilo <20>button<6F>, y crea un nuevo estilo
|
|
|
|
|
<EFBFBD>main_button<EFBFBD> cambiando simplemente el tipo de letra y cambiando el
|
|
|
|
|
color de fondo cuando el <em/widget/ est<73> en estado <tt/PRELIGHT/.
|
|
|
|
|
|
|
|
|
|
Por supuesto, muchos de estos atributos no se aplican a todos los
|
|
|
|
|
<em/widgets/. Realmente es una cuesti<74>n de sentido com<6F>n. Se utilizar<61>
|
|
|
|
|
cualquier atributo que se pueda aplicar.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Fichero <tt/rc/ de ejemplo
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
<!-- Esto hay que traducirlo -->
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
|
|
|
|
|
#
|
|
|
|
|
pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
|
|
|
|
|
#
|
|
|
|
|
# style <name> [= <name>]
|
|
|
|
|
# {
|
|
|
|
|
# <option>
|
|
|
|
|
# }
|
|
|
|
|
#
|
|
|
|
|
# widget <widget_set> style <style_name>
|
|
|
|
|
# widget_class <widget_class_set> style <style_name>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Here is a list of all the possible states. Note that some do not apply to
|
|
|
|
|
# certain widgets.
|
|
|
|
|
#
|
|
|
|
|
# NORMAL - The normal state of a widget, without the mouse over top of
|
|
|
|
|
# it, and not being pressed etc.
|
|
|
|
|
#
|
|
|
|
|
# PRELIGHT - When the mouse is over top of the widget, colors defined
|
|
|
|
|
# using this state will be in effect.
|
|
|
|
|
#
|
|
|
|
|
# ACTIVE - When the widget is pressed or clicked it will be active, and
|
|
|
|
|
# the attributes assigned by this tag will be in effect.
|
|
|
|
|
#
|
|
|
|
|
# INSENSITIVE - When a widget is set insensitive, and cannot be
|
|
|
|
|
# activated, it will take these attributes.
|
|
|
|
|
#
|
|
|
|
|
# SELECTED - When an object is selected, it takes these attributes.
|
|
|
|
|
#
|
|
|
|
|
# Given these states, we can set the attributes of the widgets in each of
|
|
|
|
|
# these states using the following directives.
|
|
|
|
|
#
|
|
|
|
|
# fg - Sets the foreground color of a widget.
|
|
|
|
|
# fg - Sets the background color of a widget.
|
|
|
|
|
# bg_pixmap - Sets the background of a widget to a tiled pixmap.
|
|
|
|
|
# font - Sets the font to be used with the given widget.
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
# This sets a style called "button". The name is not really important, as
|
|
|
|
|
# it is assigned to the actual widgets at the bottom of the file.
|
|
|
|
|
|
|
|
|
|
style "window"
|
|
|
|
|
{
|
|
|
|
|
#This sets the padding around the window to the pixmap specified.
|
|
|
|
|
#bg_pixmap[<STATE>] = "<pixmap filename>"
|
|
|
|
|
bg_pixmap[NORMAL] = "warning.xpm"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
style "scale"
|
|
|
|
|
{
|
|
|
|
|
#Sets the foreground color (font color) to red when in the "NORMAL"
|
|
|
|
|
#state.
|
|
|
|
|
|
|
|
|
|
fg[NORMAL] = { 1.0, 0, 0 }
|
|
|
|
|
|
|
|
|
|
#Sets the background pixmap of this widget to that of its parent.
|
|
|
|
|
bg_pixmap[NORMAL] = "<parent>"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
style "button"
|
|
|
|
|
{
|
|
|
|
|
# This shows all the possible states for a button. The only one that
|
|
|
|
|
# doesn't apply is the SELECTED state.
|
|
|
|
|
|
|
|
|
|
fg[PRELIGHT] = { 0, 1.0, 1.0 }
|
|
|
|
|
bg[PRELIGHT] = { 0, 0, 1.0 }
|
|
|
|
|
bg[ACTIVE] = { 1.0, 0, 0 }
|
|
|
|
|
fg[ACTIVE] = { 0, 1.0, 0 }
|
|
|
|
|
bg[NORMAL] = { 1.0, 1.0, 0 }
|
|
|
|
|
fg[NORMAL] = { .99, 0, .99 }
|
|
|
|
|
bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
|
|
|
|
|
fg[INSENSITIVE] = { 1.0, 0, 1.0 }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# In this example, we inherit the attributes of the "button" style and then
|
|
|
|
|
# override the font and background color when prelit to create a new
|
|
|
|
|
# "main_button" style.
|
|
|
|
|
|
|
|
|
|
style "main_button" = "button"
|
|
|
|
|
{
|
|
|
|
|
font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
|
|
|
|
|
bg[PRELIGHT] = { 0.75, 0, 0 }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
style "toggle_button" = "button"
|
|
|
|
|
{
|
|
|
|
|
fg[NORMAL] = { 1.0, 0, 0 }
|
|
|
|
|
fg[ACTIVE] = { 1.0, 0, 0 }
|
|
|
|
|
|
|
|
|
|
# This sets the background pixmap of the toggle_button to that of its
|
|
|
|
|
# parent widget (as defined in the application).
|
|
|
|
|
bg_pixmap[NORMAL] = "<parent>"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
style "text"
|
|
|
|
|
{
|
|
|
|
|
bg_pixmap[NORMAL] = "marble.xpm"
|
|
|
|
|
fg[NORMAL] = { 1.0, 1.0, 1.0 }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
style "ruler"
|
|
|
|
|
{
|
|
|
|
|
font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# pixmap_path "~/.pixmaps"
|
|
|
|
|
|
|
|
|
|
# These set the widget types to use the styles defined above.
|
|
|
|
|
# The widget types are listed in the class hierarchy, but could probably be
|
|
|
|
|
# just listed in this document for the users reference.
|
|
|
|
|
|
|
|
|
|
widget_class "GtkWindow" style "window"
|
|
|
|
|
widget_class "GtkDialog" style "window"
|
|
|
|
|
widget_class "GtkFileSelection" style "window"
|
|
|
|
|
widget_class "*Gtk*Scale" style "scale"
|
|
|
|
|
widget_class "*GtkCheckButton*" style "toggle_button"
|
|
|
|
|
widget_class "*GtkRadioButton*" style "toggle_button"
|
|
|
|
|
widget_class "*GtkButton*" style "button"
|
|
|
|
|
widget_class "*Ruler" style "ruler"
|
|
|
|
|
widget_class "*GtkText" style "text"
|
|
|
|
|
|
|
|
|
|
# This sets all the buttons that are children of the "main window" to
|
|
|
|
|
# the main_button style. These must be documented to be taken advantage of.
|
|
|
|
|
widget "main window.*GtkButton*" style "main_button"
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Escribiendo sus propios <em/widgets/
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Visi<73>n general
|
|
|
|
|
<p>
|
|
|
|
|
Aunque la distribuci<63>n de GTK viene con muchos tipos de <em/widgets/
|
|
|
|
|
que deber<65>a cubrir todas la mayor<6F>a de las necesidades b<>sicas, puede
|
|
|
|
|
que haya llegado el momento en que necesite crear su propio
|
|
|
|
|
<em/widget/. Debido a que GTK utiliza mucho la herencia de
|
|
|
|
|
<em/widgets/, y si ya hay un <em/widget/ que se acerque lo suficiente
|
|
|
|
|
a lo que quiere, tal vez pueda hacer un nuevo <em/widget/ con tan solo
|
|
|
|
|
unas cuantas l<>neas de c<>digo. Pero antes de empezar a trabajar en un
|
|
|
|
|
nuevo <em/widget/, aseg<65>rese primero de que no hay nadie que ya haya
|
|
|
|
|
hecho otro parecido. As<41> evitar<61> la duplicaci<63>n de esfuerzo y
|
|
|
|
|
mantendr<EFBFBD> el n<>mero de <em/widgets/ GTK en su valor m<>nimo, lo que
|
|
|
|
|
ayudar<EFBFBD> a que el c<>digo y la interfaz de las diferentes aplicaciones
|
|
|
|
|
sea consistente. Por otra parte, cuando haya acabado su <em/widget/,
|
|
|
|
|
an<EFBFBD>ncielo al mundo entreo para que todo el mundo se pueda
|
|
|
|
|
beneficiar. Probablemente el mejor lugar para hacerlo sea la
|
|
|
|
|
<tt>gtk-list</tt>.
|
|
|
|
|
|
|
|
|
|
Las fuentes completas de los <em/widgets/ de ejemplo est<73>n disponibles
|
|
|
|
|
en el mismo lugar en el que consigui<75> este tutorial, o en:
|
|
|
|
|
|
|
|
|
|
<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
|
|
|
|
|
name="http://www.gtk.org/~otaylor/gtk/tutorial/">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> La anatom<6F>a de un <em/widget/
|
|
|
|
|
<p>
|
|
|
|
|
Para crear un nuevo <em/widget/, es importante conocer como funcionan
|
|
|
|
|
los objetos de GTK. Esta secci<63>n es s<>lo un breve resumen. Ver la
|
|
|
|
|
documentaci<EFBFBD>n a la que se hace referencia para obtener m<>s detalles.
|
|
|
|
|
|
|
|
|
|
Los widgets GTK est<73>n implementados siguiendo una orientaci<63>n a
|
|
|
|
|
objetos. Sin embargo, est<73>n implementados en C est<73>ndar. De esta forma
|
|
|
|
|
se mejora enormemente la portabilidad y la estabilidad con respecto a
|
|
|
|
|
la actual generaci<63>n de compiladores C++; sin embargo, con todo esto
|
|
|
|
|
no queremos decir que el creador de <em/widgets/ tenga que prestar
|
|
|
|
|
atenci<EFBFBD>n a ninguno de los detalles de implementaci<63>n. La informaci<63>n
|
|
|
|
|
que es com<6F>n a todos los <em/widgets/ de una clase de <em/widgets/
|
|
|
|
|
(p.e., a todos los <em/widgets/ bot<6F>n) se almacena en la
|
|
|
|
|
<em>estructura de clase</em>. S<>lo hay una copia de <20>sta en la que se
|
|
|
|
|
almacena informaci<63>n sobre las se<73>ales de la clase (que actuan como
|
|
|
|
|
funciones virtuales en C). Para permitir la herencia, el primer campo
|
|
|
|
|
en la estructura de la clase debe ser una copia de la estructura de la
|
|
|
|
|
clase del padre. La declaraci<63>n de la estructura de la clase de
|
|
|
|
|
GtkButton debe ser algo as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GtkButtonClass
|
|
|
|
|
{
|
|
|
|
|
GtkContainerClass parent_class;
|
|
|
|
|
|
|
|
|
|
void (* pressed) (GtkButton *button);
|
|
|
|
|
void (* released) (GtkButton *button);
|
|
|
|
|
void (* clicked) (GtkButton *button);
|
|
|
|
|
void (* enter) (GtkButton *button);
|
|
|
|
|
void (* leave) (GtkButton *button);
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Cuando un bot<6F>n se trata como un contenedor (por ejemplo, cuando se le
|
|
|
|
|
cambia el tama<6D>o), su estructura de clase puede convertirse a
|
|
|
|
|
GtkContainerClass, y los campos relevantes se utilizar<61>n para manejar
|
|
|
|
|
las se<73>ales.
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n hay una estructura que se crea para cada <em/widget/. Esta
|
|
|
|
|
estructura tiene campos para almacenar la informaci<63>n que es diferente
|
|
|
|
|
para cada copia del <em/widget/. Nosotros llamaremos a esta estructura
|
|
|
|
|
la <em>estructura objeto</em>. Para la clase bot<6F>n, es as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GtkButton
|
|
|
|
|
{
|
|
|
|
|
GtkContainer container;
|
|
|
|
|
|
|
|
|
|
GtkWidget *child;
|
|
|
|
|
|
|
|
|
|
guint in_button : 1;
|
|
|
|
|
guint button_down : 1;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Observe que, como en la estructura de clase, el primer campo es la
|
|
|
|
|
estructura objeto de la clase padre, por lo que esta estructura puede
|
|
|
|
|
convertirse en la estructura de la clase del objeto padre cuando haga
|
|
|
|
|
falta.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Creando un <em/widget/ compuesto
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Introducci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
Un tipo de widget que puede interesarnos es uno que sea un mero
|
|
|
|
|
agregado de otros <em/widgets/ GTK. Este tipo de <em/widget/ no hace
|
|
|
|
|
nada que no pueda hacerse sin la necesidad de crear un nuevo
|
|
|
|
|
<em/widget/, pero proporciona una forma conveniente de empaquetar los
|
|
|
|
|
elementos del interfaz de usuario para su reutilizaci<63>n. Los
|
|
|
|
|
<em/widgets/ <tt/FileSelection/ y <tt/ColorSelection/ incluidos en la
|
|
|
|
|
distribuci<EFBFBD>n est<73>ndar son ejemplos de este tipo de <em/widgets/.
|
|
|
|
|
|
|
|
|
|
El <em/widget/ ejemplo que hemos creado en esta secci<63>n es el
|
|
|
|
|
<em/widget/ Tictactoe, una matriz de 3x3 de botones de selecci<63>n que
|
|
|
|
|
lanza una se<73>al cuando est<73>n deseleccionados tres botones en una misma
|
|
|
|
|
fila, columna, o diagonal.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Escogiendo una clase padre
|
|
|
|
|
<p>
|
|
|
|
|
Normalmente la clase padre para un <em/widget/ compuesto es la clase
|
|
|
|
|
contenedor que tenga todos los elementos del <em/widget/
|
|
|
|
|
compuesto. Por ejemplo, la clase padre del <em/widget/
|
|
|
|
|
<tt/FileSelection/ es la clase <tt/Dialog/. Ya que nuestros botones se
|
|
|
|
|
ordenar<EFBFBD>n en una tabla, parece natural hacer que nuestra clase padre
|
|
|
|
|
sea la clase <tt/GtkTable/. Desafortunadamente, esto no
|
|
|
|
|
funcionar<EFBFBD>a. La creaci<63>n de un <em/widget/ se divide en dos funciones
|
|
|
|
|
- una funci<63>n <tt/NOMBREWIDGET_new()/ que utilizar<61> el usuario, y una
|
|
|
|
|
funci<EFBFBD>n <tt/NOMBREWIDGET_init()/ que har<61> el trabajo b<>sico de
|
|
|
|
|
inicializar el <em/widget/ que es independiente de los argumentos que
|
|
|
|
|
se le pasen a la funci<63>n <tt/_new()/. Los <em/widgets/ derivados s<>lo
|
|
|
|
|
llaman a la funci<63>n <tt/_init/ de su <em/widget/ padre. Pero esta
|
|
|
|
|
divisi<EFBFBD>n del trabajo no funciona bien con las tablas, que necesitan
|
|
|
|
|
saber en el momento de su creaci<63>n el n<>mero de filas y de columnas
|
|
|
|
|
que deben tener. A menos que queramos duplicar la mayor parte de lo
|
|
|
|
|
hecho en <tt/gtk_table_new()/ en nuestro <em/widget/ Tictactoe,
|
|
|
|
|
haremos mejor si evitamos derivar de GtkTable. Por esta raz<61>n,
|
|
|
|
|
derivaremos de <tt/GtkVBox/, y meteremos nuestra tabla dentro de la
|
|
|
|
|
caja vertical.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> El fichero de cabecera
|
|
|
|
|
<p>
|
|
|
|
|
Cada clase <em/widget/ tiene un fichero de cabecera que declara el
|
|
|
|
|
objeto y las estructuras de clase para ese <em/widget/, as<61> como las
|
|
|
|
|
funciones p<>blicas. Un par de caracter<65>sticas que merecen dejarse
|
|
|
|
|
aparte. Para evitar la duplicaci<63>n de definiciones, meteremos el
|
|
|
|
|
fichero de cabecera al completo entre:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
#ifndef __TICTACTOE_H__
|
|
|
|
|
#define __TICTACTOE_H__
|
|
|
|
|
.
|
|
|
|
|
.
|
|
|
|
|
.
|
|
|
|
|
#endif /* __TICTACTOE_H__ */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Y para que los programas en C++ incluyan sin problemas el fichero de
|
|
|
|
|
cabecera, pondremos:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
.
|
|
|
|
|
.
|
|
|
|
|
.
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Con las funciones y las estructuras, declararemos tres macros est<73>ndar
|
|
|
|
|
en nuestro fichero de cabecera, <tt/TICTACTOE(obj)/,
|
|
|
|
|
<tt/TICTACTOE_CLASS(class)/, y <tt/IS_TICTACTOE(obj)/, que,
|
|
|
|
|
convierten, respectivamente, un puntero en un puntero al objeto o a la
|
|
|
|
|
estructura de la clase, y comprueba si un objeto es un <em/widget/
|
|
|
|
|
Tictactoe.
|
|
|
|
|
|
|
|
|
|
Aqu<EFBFBD> est<73> el fichero de cabecera al completo:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* tictactoe.h */
|
|
|
|
|
|
|
|
|
|
#ifndef __TICTACTOE_H__
|
|
|
|
|
#define __TICTACTOE_H__
|
|
|
|
|
|
|
|
|
|
#include <gdk/gdk.h>
|
|
|
|
|
#include <gtk/gtkvbox.h>
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
|
|
#define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
|
|
|
|
|
#define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
|
|
|
|
|
#define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _Tictactoe Tictactoe;
|
|
|
|
|
typedef struct _TictactoeClass TictactoeClass;
|
|
|
|
|
|
|
|
|
|
struct _Tictactoe
|
|
|
|
|
{
|
|
|
|
|
GtkVBox vbox;
|
|
|
|
|
|
|
|
|
|
GtkWidget *botones[3][3];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _TictactoeClass
|
|
|
|
|
{
|
|
|
|
|
GtkVBoxClass parent_class;
|
|
|
|
|
|
|
|
|
|
void (* tictactoe) (Tictactoe *ttt);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
guint tictactoe_get_type (void);
|
|
|
|
|
GtkWidget* tictactoe_new (void);
|
|
|
|
|
void tictactoe_clear (Tictactoe *ttt);
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
|
|
#endif /* __TICTACTOE_H__ */
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> La funci<63>n <tt/_get_type()/.
|
|
|
|
|
<p>
|
|
|
|
|
Ahora continuaremos con la implementaci<63>n de nuestro <em/widget/. Una
|
|
|
|
|
funci<EFBFBD>n del n<>cleo de todo <em/widget/ es
|
|
|
|
|
<tt/NOMBREWIDGET_get_type()/. Cuando se llame a esta funci<63>n por
|
|
|
|
|
vez primera, le informar<61> a GTK sobre la clase del <em/widget/, y
|
|
|
|
|
devolver<EFBFBD> un ID que identificar<61> un<75>vocamente la clase <em/widget/. En
|
|
|
|
|
las llamadas siguientes, lo <20>nico que har<61> ser<65> devolver el ID.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint
|
|
|
|
|
tictactoe_get_type ()
|
|
|
|
|
{
|
|
|
|
|
static guint ttt_type = 0;
|
|
|
|
|
|
|
|
|
|
if (!ttt_type)
|
|
|
|
|
{
|
|
|
|
|
GtkTypeInfo ttt_info =
|
|
|
|
|
{
|
|
|
|
|
"Tictactoe",
|
|
|
|
|
sizeof (Tictactoe),
|
|
|
|
|
sizeof (TictactoeClass),
|
|
|
|
|
(GtkClassInitFunc) tictactoe_class_init,
|
|
|
|
|
(GtkObjectInitFunc) tictactoe_init,
|
|
|
|
|
(GtkArgSetFunc) NULL,
|
|
|
|
|
(GtkArgGetFunc) NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ttt_type;
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La estructura GtkTypeInfo tiene la definici<63>n siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GtkTypeInfo
|
|
|
|
|
{
|
|
|
|
|
gchar *type_name;
|
|
|
|
|
guint object_size;
|
|
|
|
|
guint class_size;
|
|
|
|
|
GtkClassInitFunc class_init_func;
|
|
|
|
|
GtkObjectInitFunc object_init_func;
|
|
|
|
|
GtkArgSetFunc arg_set_func;
|
|
|
|
|
GtkArgGetFunc arg_get_func;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los utilidad de cada campo de esta estructura se explica por su propio
|
|
|
|
|
nombre. Ignoraremos por ahora los campos <tt/arg_set_func/
|
|
|
|
|
y <tt/arg_get_func/: son importantes, pero todav<61>a es raro
|
|
|
|
|
utilizarlos, su papel es permitir que las opciones de los <em/wdigets/
|
|
|
|
|
puedan establecerse correctamente mediante lenguajes
|
|
|
|
|
interpretados. Una vez que GTK tiene una copia de esta estructura
|
|
|
|
|
correctamente rellenada, sabr<62> como crear objetos de un tipo
|
|
|
|
|
particular de <em/widget/.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> La funci<63>n <tt/_class_init()/
|
|
|
|
|
<p>
|
|
|
|
|
La funci<63>n <tt/NOMBREWIDGET_class_init()/ inicializa los campos de la
|
|
|
|
|
estructura clase del <em/widget/, y establece las se<73>ales de la
|
|
|
|
|
clase. Para nuestro <em/widget/ Tictactoe ser<65> una cosa as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
TICTACTOE_SIGNAL,
|
|
|
|
|
LAST_SIGNAL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tictactoe_class_init (TictactoeClass *class)
|
|
|
|
|
{
|
|
|
|
|
GtkObjectClass *object_class;
|
|
|
|
|
|
|
|
|
|
object_class = (GtkObjectClass*) class;
|
|
|
|
|
|
|
|
|
|
tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
|
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
|
object_class->type,
|
|
|
|
|
GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
|
|
|
|
|
gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
|
|
|
|
|
|
|
|
|
|
class->tictactoe = NULL;
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Nuestro <em/widget/ s<>lo tiene una se<73>al, la se<73>al <tt/tictactoe/ que
|
|
|
|
|
se invoca cuando una fila, columna, o diagonal se rellena
|
|
|
|
|
completamente. No todos los <em/widgets/ compuestos necesitan se<73>ales,
|
|
|
|
|
por lo que si est<73> leyendo esto por primera vez, puede que sea mejor
|
|
|
|
|
que pase a la secci<63>n siguiente, ya que las cosas van a complicarse un
|
|
|
|
|
poco.
|
|
|
|
|
|
|
|
|
|
La funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_signal_new( const gchar *name,
|
|
|
|
|
GtkSignalRunType run_type,
|
|
|
|
|
GtkType object_type,
|
|
|
|
|
gint function_offset,
|
|
|
|
|
GtkSignalMarshaller marshaller,
|
|
|
|
|
GtkType return_val,
|
|
|
|
|
guint nparams,
|
|
|
|
|
...);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
crea una nueva se<73>al. Los par<61>metros son:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> <tt/name/: El nombre de la se<73>al.
|
|
|
|
|
<item> <tt/run_type/: Si el manejador por defecto se ejecuta antes o
|
|
|
|
|
despues del manejador de usuario. Normalmente debe ser
|
|
|
|
|
<tt/GTK_RUN_FIRST/, o <tt/GTK_RUN_LAST/, aunque hay otras
|
|
|
|
|
posibilidades.
|
|
|
|
|
<item> <tt/object_type/: El ID del objeto al que se le aplica esta
|
|
|
|
|
se<EFBFBD>al. (Tambi<62>n se aplicar<61> a los descendientes de los objetos)
|
|
|
|
|
<item> <tt/function_offset/: El desplazamiento en la estructura de la
|
|
|
|
|
clase de un puntero al manejador por defecto.
|
|
|
|
|
<item> <tt/marshaller/: Una funci<63>n que se utiliza para invocar al
|
|
|
|
|
manejador de se<73>al. Para los manejadores de se<73>al que no tengan m<>s
|
|
|
|
|
argumentos que el objeto que emiti<74> la se<73>al podemos utilizar la
|
|
|
|
|
funci<EFBFBD>n marshaller por defecto <tt/gtk_signal_default_marshaller/.
|
|
|
|
|
<item> <tt/return_val/: El tipo del valor devuelto.
|
|
|
|
|
<item> <tt/nparams/: El n<>mero de par<61>metros del manejador de se<73>al
|
|
|
|
|
(distintos de los dos por defecto que hemos mencionado arriba).
|
|
|
|
|
<item> <tt/.../: Los tipos de los par<61>metros.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Cuando se especifican los tipos, se utilizar<61> la enumeraci<63>n
|
|
|
|
|
<tt/GtkType/:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
typedef enum
|
|
|
|
|
{
|
|
|
|
|
GTK_TYPE_INVALID,
|
|
|
|
|
GTK_TYPE_NONE,
|
|
|
|
|
GTK_TYPE_CHAR,
|
|
|
|
|
GTK_TYPE_BOOL,
|
|
|
|
|
GTK_TYPE_INT,
|
|
|
|
|
GTK_TYPE_UINT,
|
|
|
|
|
GTK_TYPE_LONG,
|
|
|
|
|
GTK_TYPE_ULONG,
|
|
|
|
|
GTK_TYPE_FLOAT,
|
|
|
|
|
GTK_TYPE_DOUBLE,
|
|
|
|
|
GTK_TYPE_STRING,
|
|
|
|
|
GTK_TYPE_ENUM,
|
|
|
|
|
GTK_TYPE_FLAGS,
|
|
|
|
|
GTK_TYPE_BOXED,
|
|
|
|
|
GTK_TYPE_FOREIGN,
|
|
|
|
|
GTK_TYPE_CALLBACK,
|
|
|
|
|
GTK_TYPE_ARGS,
|
|
|
|
|
|
|
|
|
|
GTK_TYPE_POINTER,
|
|
|
|
|
|
|
|
|
|
/* it'd be great if the next two could be removed eventually */
|
|
|
|
|
GTK_TYPE_SIGNAL,
|
|
|
|
|
GTK_TYPE_C_CALLBACK,
|
|
|
|
|
|
|
|
|
|
GTK_TYPE_OBJECT
|
|
|
|
|
|
|
|
|
|
} GtkFundamentalType;
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/gtk_signal_new()/ devuelve un identificador entero <20>nico para la
|
|
|
|
|
se<EFBFBD>al, que almacenamos en el vector <tt/tictactoe_signals/, que
|
|
|
|
|
indexaremos utilizando una enumeraci<63>n. (Convencionalmente, los
|
|
|
|
|
elementos de la enumeraci<63>n son el nombre de la se<73>al, en may<61>sculas,
|
|
|
|
|
pero aqu<71> tendr<64>amos un conflicto con la macro <tt/TICTACTOE()/, por
|
|
|
|
|
lo que lo llamaremos <tt/TICTACTOE_SIGNAL/.
|
|
|
|
|
|
|
|
|
|
Despu<EFBFBD>s de crear nuestras se<73>ales, necesitamos llamar a GTK para
|
|
|
|
|
asociarlas con la clase Tictactoe. Hacemos esto llamando a
|
|
|
|
|
<tt/gtk_object_class_add_signals()/. Entonces haremos que el puntero
|
|
|
|
|
que apunta al manejador por defecto para la se<73>al `tictactoe' sea NULL,
|
|
|
|
|
indicando que no hay ninguna acci<63>n por defecto.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> La funci<63>n <tt/_init()/.
|
|
|
|
|
<p>
|
|
|
|
|
Cada clase <em/widget/ tambi<62>n necesita una funci<63>n para inicializar
|
|
|
|
|
la estructura del objeto. Normalmente, esta funci<63>n tiene el limitado
|
|
|
|
|
rol de poner los distintos campos de la estructura a su valor por
|
|
|
|
|
defecto. Sin embargo para los <em/widgets/ de composici<63>n, esta
|
|
|
|
|
funci<EFBFBD>n tambi<62>n crea los distintos <em/widgets/ componentes.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static void
|
|
|
|
|
tictactoe_init (Tictactoe *ttt)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *table;
|
|
|
|
|
gint i,j;
|
|
|
|
|
|
|
|
|
|
table = gtk_table_new (3, 3, TRUE);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(ttt), table);
|
|
|
|
|
gtk_widget_show (table);
|
|
|
|
|
|
|
|
|
|
for (i=0;i<3; i++)
|
|
|
|
|
for (j=0;j<3; j++)
|
|
|
|
|
{
|
|
|
|
|
ttt->buttons[i][j] = gtk_toggle_button_new ();
|
|
|
|
|
gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
|
|
|
|
|
i, i+1, j, j+1);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
|
|
|
|
|
GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
|
|
|
|
|
gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
|
|
|
|
|
gtk_widget_show (ttt->buttons[i][j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Y el resto...
|
|
|
|
|
<p>
|
|
|
|
|
Hay una funci<63>n m<>s que cada <em/widget/ (excepto los <em/widget/ muy
|
|
|
|
|
b<EFBFBD>sicos como GtkBin que no pueden crear objetos) tiene que
|
|
|
|
|
tener - la funci<63>n que el usuario llama para crear un objeto de ese
|
|
|
|
|
tipo. Normalmente se llama <tt/NOMBREWIDGET_new()/. En algunos
|
|
|
|
|
<em/widgets/, que no es el caso del <em/widget/ Tictactoe, esta
|
|
|
|
|
funci<EFBFBD>n toma argumentos, y hace alguna inicializaci<63>n en funci<63>n de
|
|
|
|
|
estos. Las otras dos funciones son espec<65>ficas al <em/widget/
|
|
|
|
|
Tictactoe.
|
|
|
|
|
|
|
|
|
|
<tt/tictactoe_clear()/ es una funci<63>n p<>blica que reinicia todos los
|
|
|
|
|
botones en el <em/widget/ a la posici<63>n alta. Observe la utilizaci<63>n
|
|
|
|
|
de <tt/gtk_signal_handler_block_by_data()/ para hacer que no se
|
|
|
|
|
ejecute nuestro manejador de se<73>al innecesariamente por cambios en los
|
|
|
|
|
botones.
|
|
|
|
|
|
|
|
|
|
<tt/tictactoe_toggle()/ es el manejador de se<73>al que se invoca cuando
|
|
|
|
|
el usuario pulsa un bot<6F>n. Hace una comprobaci<63>n para ver si hay
|
|
|
|
|
alguna combinaci<63>n ganadora, y si la hay, emite la se<73>al
|
|
|
|
|
<EFBFBD>tictactoe<EFBFBD>.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget*
|
|
|
|
|
tictactoe_new ()
|
|
|
|
|
{
|
|
|
|
|
return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
tictactoe_clear (Tictactoe *ttt)
|
|
|
|
|
{
|
|
|
|
|
int i,j;
|
|
|
|
|
|
|
|
|
|
for (i=0;i<3;i++)
|
|
|
|
|
for (j=0;j<3;j++)
|
|
|
|
|
{
|
|
|
|
|
gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
|
|
|
|
|
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
|
|
|
|
|
FALSE);
|
|
|
|
|
gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
|
|
|
|
|
{
|
|
|
|
|
int i,k;
|
|
|
|
|
|
|
|
|
|
static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
|
|
|
|
|
{ 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
|
|
|
|
|
{ 0, 1, 2 }, { 0, 1, 2 } };
|
|
|
|
|
static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
|
|
|
|
|
{ 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
|
|
|
|
|
{ 0, 1, 2 }, { 2, 1, 0 } };
|
|
|
|
|
|
|
|
|
|
int success, found;
|
|
|
|
|
|
|
|
|
|
for (k=0; k<8; k++)
|
|
|
|
|
{
|
|
|
|
|
success = TRUE;
|
|
|
|
|
found = FALSE;
|
|
|
|
|
|
|
|
|
|
for (i=0;i<3;i++)
|
|
|
|
|
{
|
|
|
|
|
success = success &&
|
|
|
|
|
GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
|
|
|
|
|
found = found ||
|
|
|
|
|
ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (success && found)
|
|
|
|
|
{
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (ttt),
|
|
|
|
|
tictactoe_signals[TICTACTOE_SIGNAL]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Y finalmente, un programa ejemplo que utiliza nuestro <em/widget/
|
|
|
|
|
Tictactoe:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
#include "tictactoe.h"
|
|
|
|
|
|
|
|
|
|
/* Invocado cuando se completa una fila, columna o diagonal */
|
|
|
|
|
void
|
|
|
|
|
win (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
g_print ("Yay!\n");
|
|
|
|
|
tictactoe_clear (TICTACTOE (widget));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *ttt;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Aspect Frame");
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_exit), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
/* Create a new Tictactoe widget */
|
|
|
|
|
ttt = tictactoe_new ();
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), ttt);
|
|
|
|
|
gtk_widget_show (ttt);
|
|
|
|
|
|
|
|
|
|
/* And attach to its "tictactoe" signal */
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
|
|
|
|
|
GTK_SIGNAL_FUNC (win), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Creando un <em/widget/ desde cero.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Introducci<63>n
|
|
|
|
|
<p>
|
|
|
|
|
En esta secci<63>n, averiguaremos como se dibujan los <em/widgets/ a s<>
|
|
|
|
|
mismos en pantalla y como interactuan con los eventos. Como ejemplo,
|
|
|
|
|
crearemos un marcador anal<61>gico con un puntero que el usuario
|
|
|
|
|
podr<EFBFBD> arrastrar para hacer que el marcador tenga un valor dado.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Mostrando un <em/widget/ en la pantalla
|
|
|
|
|
<p>
|
|
|
|
|
Hay varios pasos que est<73>n involucrados en el dibujado en pantalla.
|
|
|
|
|
Despu<EFBFBD>s de que el <em/widget/ se cree con una llamada a
|
|
|
|
|
<tt/NOMBREWIDGET_new()/, se necesitar<61>n muchas m<>s funciones:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> <tt/NOMBREWIDGET_realize()/ es la responsable de crear una
|
|
|
|
|
ventana X para el <em/widget/, si tiene alguna.
|
|
|
|
|
<item> <tt/NOMBREWIDGET_map()/ se invoca despu<70>s de las llamadas del
|
|
|
|
|
usuario
|
|
|
|
|
<tt/gtk_widget_show()/. Es la responsable de asegurarse de que el
|
|
|
|
|
<em/widget/ est<73> dibujado (<em/mapeado/) en la pantalla. Para una
|
|
|
|
|
clase contenedor, tambi<62>n deber<65> ocuparse de llamar a las funciones
|
|
|
|
|
<tt/map()/ de cada <em/widget/ hijo.
|
|
|
|
|
<item> <tt/NOMBREWIDGET_draw()/ se invoca cuando se llama a
|
|
|
|
|
<tt/gtk_widget_draw()/ desde el <em/widget/ de uno de sus
|
|
|
|
|
antepasados. Hace las llamadas necesarias a las funciones de dibujo
|
|
|
|
|
para dibujar el <em/widget/ en la pantalla. Para los <em/widgets/
|
|
|
|
|
contenedores, esta funci<63>n debe llamar a las <tt/gtk_widget_draw/ de
|
|
|
|
|
sus <em/widgets/ hijos.
|
|
|
|
|
<item> <tt/NOMBREWIDGET_expose()/ es un manejador de los eventos
|
|
|
|
|
<tt/expose/ del <em/widget/. Hace las llamadas necesarias a las
|
|
|
|
|
funciones de dibujo para dibujar la parte expuesta en la
|
|
|
|
|
pantalla. Para los <em/widgets/ contenedores, esta funci<63>n debe
|
|
|
|
|
generar los eventos <tt/expose/ de sus <em/widgets/ hijos que no
|
|
|
|
|
tengan su propia ventana. (Si tuviesen su propia ventana, X generar<61>a
|
|
|
|
|
los eventos <tt/expose/ necesarios)
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Las <20>ltimas dos funciones son bastante similares - ambas son
|
|
|
|
|
responsables de dibujar el <em/widget/ en pantalla. De hecho en muchos
|
|
|
|
|
<em/widgets/ realmente no importa la diferencia que hay entre ambas
|
|
|
|
|
funciones. La funci<63>n <em/draw()/ que hay por defecto en
|
|
|
|
|
la clase <em/widget/ simplemente genera un evento <tt/expose/
|
|
|
|
|
artificial de la zona a redibujar. Sin embargo, algunos tipos de
|
|
|
|
|
<em/widgets/ puede ahorrarse trabajo distinguiendo entre las dos
|
|
|
|
|
funciones. Por ejemplo, si un <em/widget/ tiene varias ventanas X,
|
|
|
|
|
entonces, como los eventos <tt/expose/ identifican a la ventana
|
|
|
|
|
expuesta, podr<64>n redibujar s<>lo la ventana afectada, lo que no es
|
|
|
|
|
posible con llamadas a <tt/draw()/.
|
|
|
|
|
|
|
|
|
|
Los <em/widgets/ contenedores, aunque no utilicen la diferecia
|
|
|
|
|
existente entre las dos funciones por s<> mismos, no pueden utilizar
|
|
|
|
|
simplemente las funciones <tt/draw()/ que hay por defecto ya que sus
|
|
|
|
|
<em/widgets/ hijos puede que tengan que utilizar la diferencia. Sin
|
|
|
|
|
embargo, ser<65>a un derroche duplicar el c<>digo de dibujado entre las
|
|
|
|
|
dos funciones. Lo normal es que cada <em/widget/ tenga una funci<63>n
|
|
|
|
|
llamada <tt/NOMBREWIDGET_paint()/ que haga el trabajo de dibujar el
|
|
|
|
|
<em/widget/, <20>sta funci<63>n ser<65> a la que se llame por las funciones
|
|
|
|
|
<tt/draw()/ y <tt/expose()/.
|
|
|
|
|
|
|
|
|
|
En nuestro ejemplo, como el <em/widget/ Dial no es un <em/widget/
|
|
|
|
|
contenedor, y s<>lo tiene una ventana, podemos tomar el camino m<>s
|
|
|
|
|
corto, utilizar la funci<63>n <tt/draw()/ por defecto y s<>lo
|
|
|
|
|
implementar la funci<63>n <tt/expose()/.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Los or<6F>genes del <em/widget/ Dial
|
|
|
|
|
<p>
|
|
|
|
|
As<EFBFBD> como todos los animales terrestes son variaciones del primer
|
|
|
|
|
anf<EFBFBD>bio que sali<6C> del barro, los <em/widgets/ Gtk tienden a nacer
|
|
|
|
|
como variaciones de alg<6C>n otro <em/widget/ escrito previamente. Por
|
|
|
|
|
tanto, aunque esta secci<63>n se titule `Creando un <em/widget/ de la
|
|
|
|
|
nada', el <em/widget/ Dial empieza realmente con el c<>digo fuente
|
|
|
|
|
del <em/widget/ Range. He tomado <20>ste como punto de arranque porque
|
|
|
|
|
ser<EFBFBD>a bonito que nuestro dial tuviese la misma interfaz que los
|
|
|
|
|
<em/widgets/ Scale, que son s<>lo una especializaci<63>n del <em/widget/
|
|
|
|
|
Range. Por tanto, aunque el c<>digo fuente se presente m<>s adelante en
|
|
|
|
|
su forma final, no implica que fuese escrito de esta forma <em>deus ex
|
|
|
|
|
machina</em>. Si todav<61>a no est<73> familiarizado, desde el punto de
|
|
|
|
|
vista del escritor de aplicaciones, con la forma de funcionar de los
|
|
|
|
|
<em/widgets/ Scale, ser<65>a una buena idea echarles un vistazo antes de
|
|
|
|
|
continuar.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Los comienzos
|
|
|
|
|
<p>
|
|
|
|
|
Nuestro <em/widget/ tiene un aspecto algo parecido al del <em/widget/
|
|
|
|
|
Tictactoe. Primero, tenemos un fichero de cabecera:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
2008-07-01 22:57:50 +00:00
|
|
|
|
/* GTK - The GIMP Toolkit
|
2000-04-23 09:17:36 +00:00
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the Free
|
|
|
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef __GTK_DIAL_H__
|
|
|
|
|
#define __GTK_DIAL_H__
|
|
|
|
|
|
|
|
|
|
#include <gdk/gdk.h>
|
|
|
|
|
#include <gtk/gtkadjustment.h>
|
|
|
|
|
#include <gtk/gtkwidget.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
|
|
|
|
|
#define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
|
|
|
|
|
#define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _GtkDial GtkDial;
|
|
|
|
|
typedef struct _GtkDialClass GtkDialClass;
|
|
|
|
|
|
|
|
|
|
struct _GtkDial
|
|
|
|
|
{
|
|
|
|
|
GtkWidget widget;
|
|
|
|
|
|
|
|
|
|
/* pol<6F>tica de actualizaci<63>n
|
|
|
|
|
* (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
|
|
|
|
|
guint policy : 2;
|
|
|
|
|
|
|
|
|
|
/* Bot<6F>n actualmente presionado o 0 si no hay ninguno */
|
|
|
|
|
guint8 boton;
|
|
|
|
|
|
|
|
|
|
/* Dimensi<73>n de los componendes del dial */
|
|
|
|
|
gint radius;
|
|
|
|
|
gint pointer_width;
|
|
|
|
|
|
|
|
|
|
/* ID del temporizador de actualizaci<63>n, o 0 si no hay ninguno */
|
|
|
|
|
guint32 timer;
|
|
|
|
|
|
|
|
|
|
/* <20>ngulo actual */
|
|
|
|
|
gfloat angle;
|
|
|
|
|
|
|
|
|
|
/* Viejos valores almacenados del adjustment, para que as<61> no
|
|
|
|
|
* tengamos que saber cuando cambia algo */
|
|
|
|
|
gfloat old_value;
|
|
|
|
|
gfloat old_lower;
|
|
|
|
|
gfloat old_upper;
|
|
|
|
|
|
|
|
|
|
/* El objeto adjustment que almacena los datos para este dial */
|
|
|
|
|
GtkAdjustment *adjustment;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GtkDialClass
|
|
|
|
|
{
|
|
|
|
|
GtkWidgetClass parent_class;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
|
|
|
|
|
guint gtk_dial_get_type (void);
|
|
|
|
|
GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
|
|
|
|
|
void gtk_dial_set_update_policy (GtkDial *dial,
|
|
|
|
|
GtkUpdateType policy);
|
|
|
|
|
|
|
|
|
|
void gtk_dial_set_adjustment (GtkDial *dial,
|
|
|
|
|
GtkAdjustment *adjustment);
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* __GTK_DIAL_H__ */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Como vamos a ir con este <em/widget/ un poco m<>s lejos que con el
|
|
|
|
|
<EFBFBD>ltimo que creamos, ahora tenemos unos cuantos campos m<>s en la
|
|
|
|
|
estructura de datos, pero el resto de las cosas son muy parecidas.
|
|
|
|
|
|
|
|
|
|
Ahora, despu<70>s de incluir los ficheros de cabecera, y declarar unas
|
|
|
|
|
cuantas constantes, tenemos algunas funciones que proporcionan
|
|
|
|
|
informaci<EFBFBD>n sobre el <em/widget/ y lo inicializan:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <gtk/gtkmain.h>
|
|
|
|
|
#include <gtk/gtksignal.h>
|
|
|
|
|
|
|
|
|
|
#include "gtkdial.h"
|
|
|
|
|
|
|
|
|
|
#define SCROLL_DELAY_LENGTH 300
|
|
|
|
|
#define DIAL_DEFAULT_SIZE 100
|
|
|
|
|
|
|
|
|
|
/* Declaraciones de funciones */
|
|
|
|
|
|
|
|
|
|
[ omitido para salvar espacio ]
|
|
|
|
|
|
|
|
|
|
/* datos locales */
|
|
|
|
|
|
|
|
|
|
static GtkWidgetClass *parent_class = NULL;
|
|
|
|
|
|
|
|
|
|
guint
|
|
|
|
|
gtk_dial_get_type ()
|
|
|
|
|
{
|
|
|
|
|
static guint dial_type = 0;
|
|
|
|
|
|
|
|
|
|
if (!dial_type)
|
|
|
|
|
{
|
|
|
|
|
GtkTypeInfo dial_info =
|
|
|
|
|
{
|
|
|
|
|
"GtkDial",
|
|
|
|
|
sizeof (GtkDial),
|
|
|
|
|
sizeof (GtkDialClass),
|
|
|
|
|
(GtkClassInitFunc) gtk_dial_class_init,
|
|
|
|
|
(GtkObjectInitFunc) gtk_dial_init,
|
|
|
|
|
(GtkArgSetFunc) NULL,
|
|
|
|
|
(GtkArgGetFunc) NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dial_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_class_init (GtkDialClass *class)
|
|
|
|
|
{
|
|
|
|
|
GtkObjectClass *object_class;
|
|
|
|
|
GtkWidgetClass *widget_class;
|
|
|
|
|
|
|
|
|
|
object_class = (GtkObjectClass*) class;
|
|
|
|
|
widget_class = (GtkWidgetClass*) class;
|
|
|
|
|
|
|
|
|
|
parent_class = gtk_type_class (gtk_widget_get_type ());
|
|
|
|
|
|
|
|
|
|
object_class->destroy = gtk_dial_destroy;
|
|
|
|
|
|
|
|
|
|
widget_class->realize = gtk_dial_realize;
|
|
|
|
|
widget_class->expose_event = gtk_dial_expose;
|
|
|
|
|
widget_class->size_request = gtk_dial_size_request;
|
|
|
|
|
widget_class->size_allocate = gtk_dial_size_allocate;
|
|
|
|
|
widget_class->button_press_event = gtk_dial_button_press;
|
|
|
|
|
widget_class->button_release_event = gtk_dial_button_release;
|
|
|
|
|
widget_class->motion_notify_event = gtk_dial_motion_notify;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_init (GtkDial *dial)
|
|
|
|
|
{
|
|
|
|
|
dial->button = 0;
|
|
|
|
|
dial->policy = GTK_UPDATE_CONTINUOUS;
|
|
|
|
|
dial->timer = 0;
|
|
|
|
|
dial->radius = 0;
|
|
|
|
|
dial->pointer_width = 0;
|
|
|
|
|
dial->angle = 0.0;
|
|
|
|
|
dial->old_value = 0.0;
|
|
|
|
|
dial->old_lower = 0.0;
|
|
|
|
|
dial->old_upper = 0.0;
|
|
|
|
|
dial->adjustment = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GtkWidget*
|
|
|
|
|
gtk_dial_new (GtkAdjustment *adjustment)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
dial = gtk_type_new (gtk_dial_get_type ());
|
|
|
|
|
|
|
|
|
|
if (!adjustment)
|
|
|
|
|
adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
|
|
|
|
|
|
gtk_dial_set_adjustment (dial, adjustment);
|
|
|
|
|
|
|
|
|
|
return GTK_WIDGET (dial);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_destroy (GtkObject *object)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (object));
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (object);
|
|
|
|
|
|
|
|
|
|
if (dial->adjustment)
|
|
|
|
|
gtk_object_unref (GTK_OBJECT (dial->adjustment));
|
|
|
|
|
|
|
|
|
|
if (GTK_OBJECT_CLASS (parent_class)->destroy)
|
|
|
|
|
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Observe que <20>sta funci<63>n <tt/init()/ hace menos cosas de las que hac<61>a
|
|
|
|
|
la funci<63>n <tt/init()/ que utilizamos con el <em/widget/ Tictactoe, ya
|
|
|
|
|
que <20>ste no es un <em/widget/ compuesto, y la funci<63>n <tt/new()/ hace
|
|
|
|
|
m<EFBFBD>s cosas, ya que ahora admite un argumento. Observe tambi<62>n que
|
|
|
|
|
cuando almacenamos un puntero en un objeto Adjustment, incrementamos
|
|
|
|
|
su contador interno, (y lo decrementamos cuando ya no lo utilizamos)
|
|
|
|
|
por lo que GTK puede saber cuando se puede destruir sin que se
|
|
|
|
|
produzcan problemas.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Aqu<EFBFBD> tenemos unas cuantas funciones para manipular las opciones del
|
|
|
|
|
<em/widget/:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkAdjustment*
|
|
|
|
|
gtk_dial_get_adjustment (GtkDial *dial)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (dial != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
|
|
|
|
|
|
|
|
|
|
return dial->adjustment;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gtk_dial_set_update_policy (GtkDial *dial,
|
|
|
|
|
GtkUpdateType policy)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (dial != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (dial));
|
|
|
|
|
|
|
|
|
|
dial->policy = policy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gtk_dial_set_adjustment (GtkDial *dial,
|
|
|
|
|
GtkAdjustment *adjustment)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (dial != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (dial));
|
|
|
|
|
|
|
|
|
|
if (dial->adjustment)
|
|
|
|
|
{
|
|
|
|
|
gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
|
|
|
|
|
gtk_object_unref (GTK_OBJECT (dial->adjustment));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dial->adjustment = adjustment;
|
|
|
|
|
gtk_object_ref (GTK_OBJECT (dial->adjustment));
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
|
|
|
|
|
(GtkSignalFunc) gtk_dial_adjustment_changed,
|
|
|
|
|
(gpointer) dial);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
|
|
|
|
|
(GtkSignalFunc) gtk_dial_adjustment_value_changed,
|
|
|
|
|
(gpointer) dial);
|
|
|
|
|
|
|
|
|
|
dial->old_value = adjustment->value;
|
|
|
|
|
dial->old_lower = adjustment->lower;
|
|
|
|
|
dial->old_upper = adjustment->upper;
|
|
|
|
|
|
|
|
|
|
gtk_dial_update (dial);
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<sect2> <tt/gtk_dial_realize()/
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Ahora vienen algunas funciones nuevas. Primero, tenemos una funci<63>n
|
|
|
|
|
que hace el trabajo de crear la ventana X. A la funci<63>n se le pasar<61>
|
|
|
|
|
una m<>scara <tt/gdk_window_new()/ que especifica que campos de la
|
|
|
|
|
estructura <tt/GdkWindowAttr/ tienen datos (los campos restantes
|
|
|
|
|
tendr<EFBFBD>n los valores por defecto). Tambi<62>n es bueno fijarse en la forma
|
|
|
|
|
en que se crea la m<>scara de eventos. Llamamos a
|
|
|
|
|
<tt/gtk_widget_get_events()/ para recuperar la m<>scara de eventos que
|
|
|
|
|
el usuario ha especificado para su <em/widget/ (con
|
|
|
|
|
<tt/gtk_widget_set_events()/), y a<>adir nosotros mismos los eventos
|
|
|
|
|
en los que estemos interesados.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Despu<EFBFBD>s de crear la ventana, decidiremos su estilo y su fondo, y
|
|
|
|
|
pondremos un puntero al <em/widget/ en el campo de datos del usuario
|
|
|
|
|
de la <tt/GdkWindow/. Este <20>ltimo paso le permite a GTK despachar los
|
|
|
|
|
eventos que hayan para esta ventana hacia el <em/widget/ correcto.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_realize (GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
GdkWindowAttr attributes;
|
|
|
|
|
gint attributes_mask;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (widget));
|
|
|
|
|
|
|
|
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
attributes.x = widget->allocation.x;
|
|
|
|
|
attributes.y = widget->allocation.y;
|
|
|
|
|
attributes.width = widget->allocation.width;
|
|
|
|
|
attributes.height = widget->allocation.height;
|
|
|
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
|
|
|
attributes.event_mask = gtk_widget_get_events (widget) |
|
|
|
|
|
GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
|
|
|
|
|
GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
|
|
|
|
|
GDK_POINTER_MOTION_HINT_MASK;
|
|
|
|
|
attributes.visual = gtk_widget_get_visual (widget);
|
|
|
|
|
attributes.colormap = gtk_widget_get_colormap (widget);
|
|
|
|
|
|
|
|
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
|
|
|
|
|
widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
|
|
|
|
|
|
|
|
|
|
widget->style = gtk_style_attach (widget->style, widget->window);
|
|
|
|
|
|
|
|
|
|
gdk_window_set_user_data (widget->window, widget);
|
|
|
|
|
|
|
|
|
|
gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<sect2> Negociaci<63>n del tama<6D>o
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Antes de que se muestre por primera vez la ventana conteniendo un
|
|
|
|
|
<em/widget/, y cuando quiera que la capa de la ventana cambie, GTK le
|
|
|
|
|
preguntara a cada <em/widget/ hijo por su tama<6D>o deseado. Esta
|
|
|
|
|
petici<EFBFBD>n se controla mediante la funci<63>n
|
|
|
|
|
<tt/gtk_dial_size_request()/. Como nuestro <em/widget/ no es un
|
|
|
|
|
<em/widget/ contenedor, y no tiene ninguna limitaci<63>n en su tama<6D>o,
|
|
|
|
|
nos contentaremos con devolver un valor por defecto.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_size_request (GtkWidget *widget,
|
|
|
|
|
GtkRequisition *requisition)
|
|
|
|
|
{
|
|
|
|
|
requisition->width = DIAL_DEFAULT_SIZE;
|
|
|
|
|
requisition->height = DIAL_DEFAULT_SIZE;
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Despu<EFBFBD>s de que todos los <em/widgets/ hayan pedido su tama<6D>o ideal,
|
|
|
|
|
se calcular<61> la ventana y cada <em/widget/ hijo ser<65> informado de su
|
|
|
|
|
tama<EFBFBD>o actual. Normalmente, <20>ste ser<65> al menos tan grande como el
|
|
|
|
|
pedido, pero si por ejemplo, el usuario ha redimensionado la ventana,
|
|
|
|
|
entonces puede que el tama<6D>o que se le de al <em/widget/ sea menor
|
|
|
|
|
que el que pidi<64>. La notificaci<63>n del tama<6D>o se maneja mediante la
|
|
|
|
|
funci<EFBFBD>n <tt/gtk_dial_size_allocate()/. F<>jese que esta funci<63>n calcula
|
|
|
|
|
los tama<6D>os de los diferentes elementos que componen la ventana para
|
|
|
|
|
su uso futuro, as<61> como todo el trabajo sucio que poner los
|
|
|
|
|
<em/widgets/ de la ventana X en la nueva posici<63>n y con el nuevo
|
|
|
|
|
tama<EFBFBD>o.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_size_allocate (GtkWidget *widget,
|
|
|
|
|
GtkAllocation *allocation)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (widget));
|
|
|
|
|
g_return_if_fail (allocation != NULL);
|
|
|
|
|
|
|
|
|
|
widget->allocation = *allocation;
|
|
|
|
|
if (GTK_WIDGET_REALIZED (widget))
|
|
|
|
|
{
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
gdk_window_move_resize (widget->window,
|
|
|
|
|
allocation->x, allocation->y,
|
|
|
|
|
allocation->width, allocation->height);
|
|
|
|
|
|
|
|
|
|
dial->radius = MAX(allocation->width,allocation->height) * 0.45;
|
|
|
|
|
dial->pointer_width = dial->radius / 5;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> <tt/gtk_dial_expose()/
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Como se mencion<6F> arriba, todo el dibujado de este <em/widget/ se hace
|
|
|
|
|
en el manejador de los eventos <tt/expose/. No hay mucho destacable
|
|
|
|
|
aqu<EFBFBD>, excepto la utilizaci<63>n de la funci<63>n <tt/gtk_draw_polygon/ para
|
|
|
|
|
dibujar el puntero con un degradado tridimensional de acuerdo con los
|
|
|
|
|
colores almacenados en el estilo del <em/widget/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_expose (GtkWidget *widget,
|
|
|
|
|
GdkEventExpose *event)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
GdkPoint points[3];
|
|
|
|
|
gdouble s,c;
|
|
|
|
|
gdouble theta;
|
|
|
|
|
gint xc, yc;
|
|
|
|
|
gint tick_length;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
|
|
|
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
if (event->count > 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
gdk_window_clear_area (widget->window,
|
|
|
|
|
0, 0,
|
|
|
|
|
widget->allocation.width,
|
|
|
|
|
widget->allocation.height);
|
|
|
|
|
|
|
|
|
|
xc = widget->allocation.width/2;
|
|
|
|
|
yc = widget->allocation.height/2;
|
|
|
|
|
|
|
|
|
|
/* Dibujar las rayitas */
|
|
|
|
|
|
|
|
|
|
for (i=0; i<25; i++)
|
|
|
|
|
{
|
|
|
|
|
theta = (i*M_PI/18. - M_PI/6.);
|
|
|
|
|
s = sin(theta);
|
|
|
|
|
c = cos(theta);
|
|
|
|
|
|
|
|
|
|
tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
|
|
|
|
|
|
|
|
|
|
gdk_draw_line (widget->window,
|
|
|
|
|
widget->style->fg_gc[widget->state],
|
|
|
|
|
xc + c*(dial->radius - tick_length),
|
|
|
|
|
yc - s*(dial->radius - tick_length),
|
|
|
|
|
xc + c*dial->radius,
|
|
|
|
|
yc - s*dial->radius);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dibujar el puntero */
|
|
|
|
|
|
|
|
|
|
s = sin(dial->angle);
|
|
|
|
|
c = cos(dial->angle);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
points[0].x = xc + s*dial->pointer_width/2;
|
|
|
|
|
points[0].y = yc + c*dial->pointer_width/2;
|
|
|
|
|
points[1].x = xc + c*dial->radius;
|
|
|
|
|
points[1].y = yc - s*dial->radius;
|
|
|
|
|
points[2].x = xc - s*dial->pointer_width/2;
|
|
|
|
|
points[2].y = yc - c*dial->pointer_width/2;
|
|
|
|
|
|
|
|
|
|
gtk_draw_polygon (widget->style,
|
|
|
|
|
widget->window,
|
|
|
|
|
GTK_STATE_NORMAL,
|
|
|
|
|
GTK_SHADOW_OUT,
|
|
|
|
|
points, 3,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Manejo de eventos
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
El resto del c<>digo del <em/widget/ controla varios tipos de eventos,
|
|
|
|
|
y no es muy diferente del que podemos encontrar en muchas aplicaciones
|
|
|
|
|
GTK. Pueden ocurrir dos tipos de eventos - el usuario puede pulsar en
|
|
|
|
|
el <em/widget/ con el rat<61>n y arrastrar para mover el puntero, o el
|
|
|
|
|
valor del objeto Adjustement puede cambiar debido a alguna
|
|
|
|
|
circunstancia externa.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Cuando el usuario pulsa en el <em/widget/, haremos una comprobaci<63>n
|
|
|
|
|
para ver si la pulsaci<63>n se hizo lo suficientemente cerca del
|
|
|
|
|
puntero, y si as<61> fue, almacenamos el bot<6F>n que puls<6C> el usuario en
|
|
|
|
|
en el campo <tt/button/ de la estructura del <em/widget/, y grabamos
|
|
|
|
|
todos los eventos del rat<61>n con una llamada a <tt/gtk_grab_add()/. El
|
|
|
|
|
movimiento del rat<61>n har<61> que se recalcule el valor del control
|
|
|
|
|
(mediante la funci<63>n <tt/gtk_dial_update_mouse/). Dependiendo de la
|
|
|
|
|
pol<EFBFBD>tica que sigamos, o bien se generar<61>n instant<6E>neamente los eventos
|
|
|
|
|
<tt/value_changed/ (<tt/GTK_UPDATE_CONTINUOUS/), o bien despu<70>s de una
|
|
|
|
|
espera del temporizador establecido mediante <tt/gtk_timeout_add()/
|
|
|
|
|
(<tt/GTK_UPDATE_DELAYED/), o bien s<>lo cuando se levante el bot<6F>n
|
|
|
|
|
(<tt/GTK_UPDATE_DISCONTINUOUS/).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_button_press (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
gint dx, dy;
|
|
|
|
|
double s, c;
|
|
|
|
|
double d_parallel;
|
|
|
|
|
double d_perpendicular;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
|
|
|
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
/* Determinar si la pulsaci<63>n del bot<6F>n fue dentro de la regi<67>n del
|
|
|
|
|
puntero - esto lo hacemos calculando la distancia x e y del punto
|
|
|
|
|
donde se puls<6C> el bot<6F>n rat<61>n de la l<>nea que se ha pasado mediante el
|
|
|
|
|
puntero */
|
|
|
|
|
|
|
|
|
|
dx = event->x - widget->allocation.width / 2;
|
|
|
|
|
dy = widget->allocation.height / 2 - event->y;
|
|
|
|
|
|
|
|
|
|
s = sin(dial->angle);
|
|
|
|
|
c = cos(dial->angle);
|
|
|
|
|
|
|
|
|
|
d_parallel = s*dy + c*dx;
|
|
|
|
|
d_perpendicular = fabs(s*dx - c*dy);
|
|
|
|
|
|
|
|
|
|
if (!dial->button &&
|
|
|
|
|
(d_perpendicular < dial->pointer_width/2) &&
|
|
|
|
|
(d_parallel > - dial->pointer_width))
|
|
|
|
|
{
|
|
|
|
|
gtk_grab_add (widget);
|
|
|
|
|
|
|
|
|
|
dial->button = event->button;
|
|
|
|
|
|
|
|
|
|
gtk_dial_update_mouse (dial, event->x, event->y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_button_release (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
|
|
|
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
if (dial->button == event->button)
|
|
|
|
|
{
|
|
|
|
|
gtk_grab_remove (widget);
|
|
|
|
|
|
|
|
|
|
dial->button = 0;
|
|
|
|
|
|
|
|
|
|
if (dial->policy == GTK_UPDATE_DELAYED)
|
|
|
|
|
gtk_timeout_remove (dial->timer);
|
|
|
|
|
|
|
|
|
|
if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
|
|
|
|
|
(dial->old_value != dial->adjustment->value))
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_motion_notify (GtkWidget *widget,
|
|
|
|
|
GdkEventMotion *event)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
GdkModifierType mods;
|
|
|
|
|
gint x, y, mask;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
|
|
|
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
if (dial->button != 0)
|
|
|
|
|
{
|
|
|
|
|
x = event->x;
|
|
|
|
|
y = event->y;
|
|
|
|
|
|
|
|
|
|
if (event->is_hint || (event->window != widget->window))
|
|
|
|
|
gdk_window_get_pointer (widget->window, &x, &y, &mods);
|
|
|
|
|
|
|
|
|
|
switch (dial->button)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
mask = GDK_BUTTON1_MASK;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
mask = GDK_BUTTON2_MASK;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
mask = GDK_BUTTON3_MASK;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
mask = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mods & mask)
|
|
|
|
|
gtk_dial_update_mouse (dial, x,y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_timer (GtkDial *dial)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (dial != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
|
|
|
|
|
|
|
|
|
|
if (dial->policy == GTK_UPDATE_DELAYED)
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
|
|
|
|
|
{
|
|
|
|
|
gint xc, yc;
|
|
|
|
|
gfloat old_value;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (dial != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (dial));
|
|
|
|
|
|
|
|
|
|
xc = GTK_WIDGET(dial)->allocation.width / 2;
|
|
|
|
|
yc = GTK_WIDGET(dial)->allocation.height / 2;
|
|
|
|
|
|
|
|
|
|
old_value = dial->adjustment->value;
|
|
|
|
|
dial->angle = atan2(yc-y, x-xc);
|
|
|
|
|
|
|
|
|
|
if (dial->angle < -M_PI/2.)
|
|
|
|
|
dial->angle += 2*M_PI;
|
|
|
|
|
|
|
|
|
|
if (dial->angle < -M_PI/6)
|
|
|
|
|
dial->angle = -M_PI/6;
|
|
|
|
|
|
|
|
|
|
if (dial->angle > 7.*M_PI/6.)
|
|
|
|
|
dial->angle = 7.*M_PI/6.;
|
|
|
|
|
|
|
|
|
|
dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
|
|
|
|
|
(dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
|
|
|
|
|
|
|
|
|
|
if (dial->adjustment->value != old_value)
|
|
|
|
|
{
|
|
|
|
|
if (dial->policy == GTK_UPDATE_CONTINUOUS)
|
|
|
|
|
{
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gtk_widget_draw (GTK_WIDGET(dial), NULL);
|
|
|
|
|
|
|
|
|
|
if (dial->policy == GTK_UPDATE_DELAYED)
|
|
|
|
|
{
|
|
|
|
|
if (dial->timer)
|
|
|
|
|
gtk_timeout_remove (dial->timer);
|
|
|
|
|
|
|
|
|
|
dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
|
|
|
|
|
(GtkFunction) gtk_dial_timer,
|
|
|
|
|
(gpointer) dial);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Cambios en el Adjustment por motivos externos significa que se le
|
|
|
|
|
comunicar<EFBFBD>n a nuestro <em/widget/ mediante las se<73>ales <tt/changed/ y
|
|
|
|
|
<tt/value_changed/. Los manejadores de estas funciones llaman a
|
|
|
|
|
<tt/gtk_dial_update()/ para comprobar los argumentos, calcular el
|
|
|
|
|
nuevo <20>ngulo del puntero, y redibujar el <em/widget/ (llamando a
|
|
|
|
|
<tt/gtk_widget_draw()/).
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_update (GtkDial *dial)
|
|
|
|
|
{
|
|
|
|
|
gfloat new_value;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (dial != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (dial));
|
|
|
|
|
|
|
|
|
|
new_value = dial->adjustment->value;
|
|
|
|
|
|
|
|
|
|
if (new_value < dial->adjustment->lower)
|
|
|
|
|
new_value = dial->adjustment->lower;
|
|
|
|
|
|
|
|
|
|
if (new_value > dial->adjustment->upper)
|
|
|
|
|
new_value = dial->adjustment->upper;
|
|
|
|
|
|
|
|
|
|
if (new_value != dial->adjustment->value)
|
|
|
|
|
{
|
|
|
|
|
dial->adjustment->value = new_value;
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
|
|
|
|
|
(dial->adjustment->upper - dial->adjustment->lower);
|
|
|
|
|
|
|
|
|
|
gtk_widget_draw (GTK_WIDGET(dial), NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
|
|
|
|
|
gpointer data)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (adjustment != NULL);
|
|
|
|
|
g_return_if_fail (data != NULL);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (data);
|
|
|
|
|
|
|
|
|
|
if ((dial->old_value != adjustment->value) ||
|
|
|
|
|
(dial->old_lower != adjustment->lower) ||
|
|
|
|
|
(dial->old_upper != adjustment->upper))
|
|
|
|
|
{
|
|
|
|
|
gtk_dial_update (dial);
|
|
|
|
|
|
|
|
|
|
dial->old_value = adjustment->value;
|
|
|
|
|
dial->old_lower = adjustment->lower;
|
|
|
|
|
dial->old_upper = adjustment->upper;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
|
|
|
|
|
gpointer data)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (adjustment != NULL);
|
|
|
|
|
g_return_if_fail (data != NULL);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (data);
|
|
|
|
|
|
|
|
|
|
if (dial->old_value != adjustment->value)
|
|
|
|
|
{
|
|
|
|
|
gtk_dial_update (dial);
|
|
|
|
|
|
|
|
|
|
dial->old_value = adjustment->value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> Posibles mejoras
|
|
|
|
|
<p>
|
|
|
|
|
|
|
|
|
|
El <em/widget/ Dial tal y como lo hemos descrito tiene unas 670
|
|
|
|
|
l<EFBFBD>neas de c<>digo. Aunque pueda parecer un poco exagerado, todav<61>a
|
|
|
|
|
no hemos escrito demasiado c<>digo, ya que la mayor<6F>a de las l<>neas
|
|
|
|
|
son de ficheros de cabecera y de adornos. Todav<61>a se le pueden hacer
|
|
|
|
|
algunas mejoras a este <em/widget/:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> Si prueba el <em/widget/, ver<65> que el puntero cambia a
|
|
|
|
|
pantallazos cuando se le arrastra. Esto es debido a que todo el
|
|
|
|
|
<em/widget/ se borra cada vez que se mueve el puntero, antes de
|
|
|
|
|
redibujarse. Normalmente, la mejor forma de tratar este problema es
|
|
|
|
|
dibujar en un <em/pixmap/ que no represente lo que se ve directamente
|
|
|
|
|
en pantalla, y copiar el resultado final en la pantalla en s<>lo un
|
|
|
|
|
paso. (El <em/widget/ ProgressBar funciona de esta forma.)
|
|
|
|
|
|
|
|
|
|
<item> El usuario deber<65>a ser capaz de utilizar las flechas de arriba
|
|
|
|
|
y abajo para aumentar y decrementar el valor.
|
|
|
|
|
|
|
|
|
|
<item> Ser<65>a bonito si el <em/widget/ tuviese botones para
|
|
|
|
|
incrementar y decrementar el valor a saltos m<>s o menos
|
|
|
|
|
grandes. Es posible utilizar <em/widgets/ bot<6F>n, aunque tambi<62>n
|
|
|
|
|
queremos que los botones pudiesen realizar la operaci<63>n de incrementar
|
|
|
|
|
o decrementar varias veces, mientras se mantenga el bot<6F>n pulsado, tal
|
|
|
|
|
y como lo hacen las flechas en una barra de desplazamiento. La mayor<6F>a
|
|
|
|
|
del c<>digo para implementar todo esto lo podemos encontrar en el
|
|
|
|
|
<em/widget/ GtkRange.
|
|
|
|
|
|
|
|
|
|
<item> El <em/widget/ Dial puede utilizarse en un <em/widget/
|
|
|
|
|
contenedor con un simple <em/widget/ hijo colocado en la parte
|
|
|
|
|
inferior entre los botones antes mencionados. El usuario puede a<>adir
|
|
|
|
|
(seg<65>n prefiera) una etiqueta o un <em/widget/ entry para mostrar el
|
|
|
|
|
valor actual del marcador.
|
|
|
|
|
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Aprendiendo m<>s
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
S<EFBFBD>lo se han descrito una peque<75>a parte de los muchos detalles
|
|
|
|
|
involucrados en la creaci<63>n de <em/widgets/, la mejor fuente de
|
|
|
|
|
ejemplos es el c<>digo mismo de GTK. H<>gase algunas preguntas acerca
|
|
|
|
|
del <em/widget/ que desea crear: <20>es un <em/widget/ contenedor?
|
|
|
|
|
<EFBFBD>Debe tener su propia ventana? <20>Es una modificaci<63>n de un
|
|
|
|
|
<em/widget/ existente? En ese momento busque un <em/widget/ similar, y
|
|
|
|
|
comience a hacer los cambios.
|
|
|
|
|
<EFBFBD>Buena suerte!
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Scribble, un sencillo programa de dibujo de ejemplo
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Objetivos
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
En esta secci<63>n, vamos a crear un sencillo programa de dibujo. En el
|
|
|
|
|
proceso, vamos a examinar como se manejan los eventos de rat<61>n, como
|
|
|
|
|
dibujar en una ventana, y como mejorar el dibujado utilizando un
|
|
|
|
|
<em/pixmap/ intermedio. Despu<70>s de crear el programa de dibujo, lo
|
|
|
|
|
ampliaremos a<>adiendole la posibilidad de utilizar dispositivos
|
|
|
|
|
XInput, como tabletas digitalizadoras. GTK proporciona las rutinas que
|
|
|
|
|
nos dar<61>n la posibilidad de obtener informaci<63>n extra, como la presi<73>n
|
|
|
|
|
y la inclinaci<63>n, de todo tipo de dispositivos de una forma sencilla.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Manejo de eventos
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Las se<73>ales GTK sobre las que ya hemos discutido son para las
|
|
|
|
|
acciones de alto nivel, como cuando se selecciona un elemento de un
|
|
|
|
|
men<EFBFBD>. Sin embargo a veces es <20>til tratar con los acontecimientos a
|
|
|
|
|
bajo nivel, como cuando se mueve el rat<61>n, o cuando se est<73>
|
|
|
|
|
presionando una tecla. Tambi<62>n hay se<73>ales GTK relacionadas con
|
|
|
|
|
estos <em/eventos/ de bajo nivel. Los manejadores de estas se<73>ales
|
|
|
|
|
tienen un par<61>metro extra que es un puntero a una estructura
|
|
|
|
|
conteniendo informaci<63>n sobre el evento. Por ejemplo, a los manejadores
|
|
|
|
|
de los eventos de movimiento se les pasa una estructura
|
|
|
|
|
<tt/GdkEventMotion/ que es (en parte) as<61>:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GdkEventMotion
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *ventana;
|
|
|
|
|
guint32 time;
|
|
|
|
|
gdouble x;
|
|
|
|
|
gdouble y;
|
|
|
|
|
...
|
|
|
|
|
guint state;
|
|
|
|
|
...
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/type/ adquirir<69> su valor adecuado dependiendo del tipo de evento,
|
|
|
|
|
en nuestro caso <tt/GDK_MOTION_NOTIFY/, <tt/ventana/ es la ventana en
|
|
|
|
|
la que ocurre el evento. <tt/x/ e <tt/y/ dan las coordenadas del
|
|
|
|
|
evento, y <tt/state/ especifica cual es la modificaci<63>n que ha habido
|
|
|
|
|
cuando ocurri<72> el evento (esto es, especifica que teclas han cambiado
|
|
|
|
|
su estado y que botones del rat<61>n se han presionado.) Es la
|
|
|
|
|
operaci<EFBFBD>n OR (O) de algunos de los siguientes valores:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GDK_SHIFT_MASK
|
|
|
|
|
GDK_LOCK_MASK
|
|
|
|
|
GDK_CONTROL_MASK
|
|
|
|
|
GDK_MOD1_MASK
|
|
|
|
|
GDK_MOD2_MASK
|
|
|
|
|
GDK_MOD3_MASK
|
|
|
|
|
GDK_MOD4_MASK
|
|
|
|
|
GDK_MOD5_MASK
|
|
|
|
|
GDK_BUTTON1_MASK
|
|
|
|
|
GDK_BUTTON2_MASK
|
|
|
|
|
GDK_BUTTON3_MASK
|
|
|
|
|
GDK_BUTTON4_MASK
|
|
|
|
|
GDK_BUTTON5_MASK
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Como con las otras se<73>ales, para especificar que es lo que pasa cuando
|
|
|
|
|
ocurre un evento, llamaremos a <tt>gtk_signal_connect()</tt>. Pero
|
|
|
|
|
tambi<EFBFBD>n necesitamos decirle a GTK sobre que eventos queremos ser
|
|
|
|
|
informados. Para ello, llamaremos a la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_widget_set_events (GtkWidget *widget,
|
|
|
|
|
gint events);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El segundo campo especifica los eventos en los que estamos
|
|
|
|
|
interesados. Es el OR (O) de las constantes que especifican los
|
|
|
|
|
diferentes tipos de eventos. Por las referencias futuras que podamos
|
|
|
|
|
hacer, presentamos aqu<71> los tipos de eventos que hay disponibles:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GDK_EXPOSURE_MASK
|
|
|
|
|
GDK_POINTER_MOTION_MASK
|
|
|
|
|
GDK_POINTER_MOTION_HINT_MASK
|
|
|
|
|
GDK_BUTTON_MOTION_MASK
|
|
|
|
|
GDK_BUTTON1_MOTION_MASK
|
|
|
|
|
GDK_BUTTON2_MOTION_MASK
|
|
|
|
|
GDK_BUTTON3_MOTION_MASK
|
|
|
|
|
GDK_BUTTON_PRESS_MASK
|
|
|
|
|
GDK_BUTTON_RELEASE_MASK
|
|
|
|
|
GDK_KEY_PRESS_MASK
|
|
|
|
|
GDK_KEY_RELEASE_MASK
|
|
|
|
|
GDK_ENTER_NOTIFY_MASK
|
|
|
|
|
GDK_LEAVE_NOTIFY_MASK
|
|
|
|
|
GDK_FOCUS_CHANGE_MASK
|
|
|
|
|
GDK_STRUCTURE_MASK
|
|
|
|
|
GDK_PROPERTY_CHANGE_MASK
|
|
|
|
|
GDK_PROXIMITY_IN_MASK
|
|
|
|
|
GDK_PROXIMITY_OUT_MASK
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Hay unos cuantas sutilezas que debemos respetar cuando llamamos a
|
|
|
|
|
<tt/gtk_widget_set_events()/. Primero, debemos llamar a esta funci<63>n
|
|
|
|
|
antes de que se cree la ventana X para el <em/widget/ GTK. En
|
|
|
|
|
t<EFBFBD>rminos pr<70>cticos, significa que debemos llamarla inmediatamente
|
|
|
|
|
despu<EFBFBD>s de crear el <em/widget/. Segundo, el <em/widget/ debe tener
|
|
|
|
|
una ventana X asociado. Por motivos de eficiencia, hay muchos
|
|
|
|
|
<em/widgets/ que no tienen su propia ventana, sino que dibujan en la
|
|
|
|
|
de su padre. Estos <em/widgets/ son:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkAlignment
|
|
|
|
|
GtkArrow
|
|
|
|
|
GtkBin
|
|
|
|
|
GtkBox
|
|
|
|
|
GtkImage
|
|
|
|
|
GtkItem
|
|
|
|
|
GtkLabel
|
|
|
|
|
GtkPixmap
|
|
|
|
|
GtkScrolledWindow
|
|
|
|
|
GtkSeparator
|
|
|
|
|
GtkTable
|
|
|
|
|
GtkAspectFrame
|
|
|
|
|
GtkFrame
|
|
|
|
|
GtkVBox
|
|
|
|
|
GtkHBox
|
|
|
|
|
GtkVSeparator
|
|
|
|
|
GtkHSeparator
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Para capturar eventos para estos <em/widgets/, necesita utilizar un
|
|
|
|
|
<em/widget/ EventBox. Vea la secci<63>n <ref
|
|
|
|
|
id="sec_The_EventBox_Widget" name="El widget EventBox"> para m<>s
|
|
|
|
|
detalles.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Para nuestro programa de dibujo, queremos saber cuando se presiona el
|
|
|
|
|
bot<EFBFBD>n del rat<61>n y cuando se mueve, por lo que debemos especificar
|
|
|
|
|
los eventos <tt/GDK_POINTER_MOTION_MASK/ y
|
|
|
|
|
<tt/GDK_BUTTON_PRESS_MASK/. Tambi<62>n queremos saber cuando necesitamos
|
|
|
|
|
redibujar nuestra ventana, por lo que especificaremos el evento
|
|
|
|
|
<tt/GDK_EXPOSURE_MASK/. Aunque queremos estar informados mediante un
|
|
|
|
|
evento <tt/Configure/ cuando cambie el tama<6D>o de nuestra ventana, no
|
|
|
|
|
tenemos que especificar la correspondiente <tt/GDK_STRUCTURE_MASK/,
|
|
|
|
|
porque ya est<73> activada por defecto para todas las ventanas.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Tenemos un problema con lo que acabamos de hacer, y tiene que ver con
|
|
|
|
|
la utilizaci<63>n de <tt/GDK_POINTER_MOTION_MASK/. Si especificamos este
|
|
|
|
|
evento, el servidor a<>adir<69> un evento de movimiento a la cola de
|
|
|
|
|
eventos cada vez que el usuario mueva el rat<61>n. Imagine que nos
|
|
|
|
|
cuesta 0'1 segundo tratar el evento de movimiento, pero que el
|
|
|
|
|
servidor X a<>ade a la cola un nuevo evento de moviento cada 0'05
|
|
|
|
|
segundos. Pronto nos iremos quedando retrasados con respecto al resto
|
|
|
|
|
de los eventos. Si el usuario dibuja durante 5 segundos, <20>nos llevar<61>
|
|
|
|
|
otros 5 segundos el cazarle despu<70>s de que hay levantado el bot<6F>n
|
|
|
|
|
del rat<61>n! Lo que queremos es s<>lo un evento de movimiento por cada
|
|
|
|
|
evento que procesemos. La manera de hacerlo es especificando
|
|
|
|
|
<tt/GDK_POINTER_MOTION_HINT_MASK/.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Cuando especificamos <tt/GDK_POINTER_MOTION_HINT_MASK/, el servidor
|
|
|
|
|
nos envia un evento de movimiento la primera ver que el puntero se
|
|
|
|
|
mueve depu<70>s de entrar en nuestra ventana, o despu<70>s de que se
|
|
|
|
|
apriete o se suelte un bot<6F>n (y se reciba el evento
|
|
|
|
|
correspondiente). Los eventos de movimiento restantes se eliminar<61>n a
|
|
|
|
|
no ser que preguntemos especificamente por la posici<63>n del puntero
|
|
|
|
|
utilizando la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GdkWindow* gdk_window_get_pointer (GdkWindow *ventana,
|
|
|
|
|
gint *x,
|
|
|
|
|
gint *y,
|
|
|
|
|
GdkModifierType *mask);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
(Hay otra funci<63>n, <tt>gtk_widget_get_pointer()</tt> que tiene una
|
|
|
|
|
interfaz m<>s sencillo, pero esta simplificaci<63>n le resta utilidad, ya
|
|
|
|
|
que s<>lo devuelve la posici<63>n del rat<61>n, y no si alguno de sus botones
|
|
|
|
|
est<EFBFBD> presionado.)
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
El c<>digo para establecer los eventos para nuestra ventana es el
|
|
|
|
|
siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
|
|
|
|
|
(GtkSignalFunc) expose_event, NULL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
|
|
|
|
|
(GtkSignalFunc) configure_event, NULL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
|
|
|
|
|
(GtkSignalFunc) motion_notify_event, NULL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
|
|
|
|
|
(GtkSignalFunc) button_press_event, NULL);
|
|
|
|
|
|
|
|
|
|
gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
|
|
|
|
|
| GDK_LEAVE_NOTIFY_MASK
|
|
|
|
|
| GDK_BUTTON_PRESS_MASK
|
|
|
|
|
| GDK_POINTER_MOTION_MASK
|
|
|
|
|
| GDK_POINTER_MOTION_HINT_MASK);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Vamos a dejar los manejadores de los eventos <tt/expose_event/ y
|
|
|
|
|
<tt/configure_event/ para despu<70>s. Los manejadores de
|
|
|
|
|
<tt/motion_notify_event/ y de <tt/button_press_event/ son bastante
|
|
|
|
|
simples:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static gint
|
|
|
|
|
button_press_event (GtkWidget *widget, GdkEventButton *event)
|
|
|
|
|
{
|
|
|
|
|
if (event->button == 1 && pixmap != NULL)
|
|
|
|
|
draw_brush (widget, event->x, event->y);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
|
|
|
|
|
{
|
|
|
|
|
int x, y;
|
|
|
|
|
GdkModifierType state;
|
|
|
|
|
|
|
|
|
|
if (event->is_hint)
|
|
|
|
|
gdk_window_get_pointer (event->window, &x, &y, &state);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
x = event->x;
|
|
|
|
|
y = event->y;
|
|
|
|
|
state = event->state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state & GDK_BUTTON1_MASK && pixmap != NULL)
|
|
|
|
|
draw_brush (widget, x, y);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> El <em/widget/ DrawingArea, y dibujando
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Vamos a pasar al proceso de dibujar en la pantalla. El <em/widget/ que
|
|
|
|
|
utilizaremos ser<65> el DrawingArea. Un <em/widget/ DrawingArea es
|
|
|
|
|
esencialmente una ventana X y nada m<>s. Es un lienzo en blanco en
|
|
|
|
|
el que podemos dibujar lo que queramos. Crearemos un <20>rea de dibujo
|
|
|
|
|
utilizando la llamada:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget* gtk_drawing_area_new (void);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se puede especificar un tama<6D>o por defecto para el <em/widget/
|
|
|
|
|
llamando a:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_drawing_area_size (GtkDrawingArea *darea,
|
|
|
|
|
gint width,
|
|
|
|
|
gint height);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se puede cambiar el tama<6D>o por defecto, como para todos los
|
|
|
|
|
<em/widgets/, llamando a <tt/gtk_widget_set_usize()/, y esto, adem<65>s,
|
|
|
|
|
puede cambiarse si el usuario cambia manualmente el tama<6D>o de la
|
|
|
|
|
ventana que contiene el <20>rea de dibujo.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Debemos hacer notar que cuando creamos un <em/widget/ DrawingArea,
|
|
|
|
|
seremos <em/completamente/ responsables de dibujar su contenido. Si
|
|
|
|
|
nuestra ventana se tapa y se vuelve a poner al descubierto,
|
|
|
|
|
obtendremos un evento de exposici<63>n y deberemos redibujar lo que se
|
|
|
|
|
hab<EFBFBD>a tapado.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Tener que recordar todo lo que se dibuj<75> en la pantalla para que
|
|
|
|
|
podamos redibujarla convenientemente es, por decirlo de alguna manera
|
|
|
|
|
suave, una locura. Adem<65>s puede quedar mal si hay que borrar partes
|
|
|
|
|
de la pantalla y hay que redibujarlas paso a paso. La soluci<63>n a este
|
|
|
|
|
problema es utilizar un <em>pixmap</em> intermedio. En lugar de
|
|
|
|
|
dibujar directamente en la pantalla, dibujaremos en una imagen que
|
|
|
|
|
estar<EFBFBD> almacenada en la memoria del servidor, pero que no se mostrar<61>,
|
|
|
|
|
y cuando cambie la imagen o se muestren nuevas partes de
|
|
|
|
|
la misma, copiaremos las porciones relevantes en la pantalla.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Para crear un <em/pixmap/ intermedio, llamaremos a la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GdkPixmap* gdk_pixmap_new (GdkWindow *ventana,
|
|
|
|
|
gint width,
|
|
|
|
|
gint height,
|
|
|
|
|
gint depth);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El par<61>metro <tt/widget/ especifica una ventana GDK de las que este
|
|
|
|
|
<em/pixmap/ tomar<61> algunas propiedades. <tt/width/ y <tt/height/
|
|
|
|
|
especifican el tama<6D>o del <em/pixmap/. <tt/depth/ especifica la
|
|
|
|
|
<em/profundidad del color/, que es el n<>mero de bits por pixel de la
|
|
|
|
|
nueva ventana. Si la profundidad que se especifica es <tt/-1/, se
|
|
|
|
|
utilizar<EFBFBD> la misma profundidad de color que tenga la <tt/ventana/.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Creamos nuestro <em/pixmap/ en nuestro manejador del evento
|
|
|
|
|
<tt/configure_event/. Este evento se genera cada vez que cambia el
|
|
|
|
|
tama<EFBFBD>o de la ventana, incluyendo cuando <20>sta se crea.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* Backing pixmap for drawing area */
|
|
|
|
|
static GdkPixmap *pixmap = NULL;
|
|
|
|
|
|
|
|
|
|
/* Create a new backing pixmap of the appropriate size */
|
|
|
|
|
static gint
|
|
|
|
|
configure_event (GtkWidget *widget, GdkEventConfigure *event)
|
|
|
|
|
{
|
|
|
|
|
if (pixmap)
|
|
|
|
|
gdk_pixmap_unref(pixmap);
|
|
|
|
|
|
|
|
|
|
pixmap = gdk_pixmap_new(widget->window,
|
|
|
|
|
widget->allocation.width,
|
|
|
|
|
widget->allocation.height,
|
|
|
|
|
-1);
|
|
|
|
|
gdk_draw_rectangle (pixmap,
|
|
|
|
|
widget->style->white_gc,
|
|
|
|
|
TRUE,
|
|
|
|
|
0, 0,
|
|
|
|
|
widget->allocation.width,
|
|
|
|
|
widget->allocation.height);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
La llamada a <tt/gdk_draw_rectangle()/ rellena todo el <em/pixmap/ de
|
|
|
|
|
blanco. Hablaremos m<>s de todo esto en un momento.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Nuestro manejador del evento de exposici<63>n simplemente copia la
|
|
|
|
|
porci<EFBFBD>n relevante del <em/pixmap/ en la pantalla (determinaremos la
|
|
|
|
|
zona a redibujar utilizando el campo <tt/event->area/ del evento de
|
|
|
|
|
exposici<EFBFBD>n):
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* Redraw the screen from the backing pixmap */
|
|
|
|
|
static gint
|
|
|
|
|
expose_event (GtkWidget *widget, GdkEventExpose *event)
|
|
|
|
|
{
|
|
|
|
|
gdk_draw_pixmap(widget->window,
|
|
|
|
|
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
|
|
|
|
|
pixmap,
|
|
|
|
|
event->area.x, event->area.y,
|
|
|
|
|
event->area.x, event->area.y,
|
|
|
|
|
event->area.width, event->area.height);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Ahora ya sabemos como mantener la pantalla actualizada con el
|
|
|
|
|
contenido de nuestro <em/pixmap/, pero <20>c<EFBFBD>mo podemos dibujar algo
|
|
|
|
|
interesante en nuestro <em/pixmap/? Hay un gran n<>mero de llamadas en
|
|
|
|
|
la biblioteca GDK para dibujar en los <em/dibujables/. Un dibujable es
|
|
|
|
|
simplemente algo sobre lo que se puede dibujar. Puede ser una ventana,
|
|
|
|
|
un <em/pixmap/, un <em/bitmap/ (una imagen en blanco y negro), etc. Ya
|
|
|
|
|
hemos visto arriba dos de estas llamadas,
|
|
|
|
|
<tt>gdk_draw_rectangle()</tt> y <tt>gdk_draw_pixmap()</tt>. La lista
|
|
|
|
|
completa de funciones para dibujar es:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gdk_draw_line ()
|
|
|
|
|
gdk_draw_rectangle ()
|
|
|
|
|
gdk_draw_arc ()
|
|
|
|
|
gdk_draw_polygon ()
|
|
|
|
|
gdk_draw_string ()
|
|
|
|
|
gdk_draw_text ()
|
|
|
|
|
gdk_draw_pixmap ()
|
|
|
|
|
gdk_draw_bitmap ()
|
|
|
|
|
gdk_draw_image ()
|
|
|
|
|
gdk_draw_points ()
|
|
|
|
|
gdk_draw_segments ()
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Ver la documentaci<63>n de estas funciones o el fichero de cabecera
|
|
|
|
|
<tt><gdk/gdk.h></tt> para obtener m<>s detalles sobre estas
|
|
|
|
|
funciones. Todas comparten los dos primeros argumentos. El primero es
|
|
|
|
|
el dibujable en el que se dibujar<61>, y el segundo argumento es un
|
|
|
|
|
<em/contexto gr<67>fico/ (GC).
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Un contexto gr<67>fico re<72>ne la informaci<63>n sobre cosas como el color
|
|
|
|
|
de fondo y del color de lo que se dibuja, el ancho de la l<>nea,
|
|
|
|
|
etc... GDK tiene un conjunto completo de funciones para crear y
|
|
|
|
|
modificar los contextos gr<67>ficos. Cada <em/widget/ tiene un GC
|
|
|
|
|
asociado. (Que puede modificarse en un fichero gtkrc, ver la secci<63>n
|
|
|
|
|
<EFBFBD>Ficheros rc de GTK<54>.) Estos, junto con otras cosas, almacenan
|
|
|
|
|
GC's. Algunos ejemplos de como acceder a estos GC's son:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
widget->style->white_gc
|
|
|
|
|
widget->style->black_gc
|
|
|
|
|
widget->style->fg_gc[GTK_STATE_NORMAL]
|
|
|
|
|
widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Los campos <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, y
|
|
|
|
|
<tt>light_gc</tt> se indexan con un par<61>metro del tipo
|
|
|
|
|
<tt/GtkStateType/ que puede tomar uno de los valores:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GTK_STATE_NORMAL,
|
|
|
|
|
GTK_STATE_ACTIVE,
|
|
|
|
|
GTK_STATE_PRELIGHT,
|
|
|
|
|
GTK_STATE_SELECTED,
|
|
|
|
|
GTK_STATE_INSENSITIVE
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Por ejemplo, para el <tt/GTK_STATE_SELECTED/, el color que se utiliza
|
|
|
|
|
para pintar por defecto es el blanco y el color del fondo por defecto,
|
|
|
|
|
es el azul oscuro.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Nuestra funci<63>n <tt/draw_brush()/, que es la que dibuja en la
|
|
|
|
|
pantalla, ser<65> la siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* Draw a rectangle on the screen */
|
|
|
|
|
static void
|
|
|
|
|
draw_brush (GtkWidget *widget, gdouble x, gdouble y)
|
|
|
|
|
{
|
|
|
|
|
GdkRectangle update_rect;
|
|
|
|
|
|
|
|
|
|
update_rect.x = x - 5;
|
|
|
|
|
update_rect.y = y - 5;
|
|
|
|
|
update_rect.width = 10;
|
|
|
|
|
update_rect.height = 10;
|
|
|
|
|
gdk_draw_rectangle (pixmap,
|
|
|
|
|
widget->style->black_gc,
|
|
|
|
|
TRUE,
|
|
|
|
|
update_rect.x, update_rect.y,
|
|
|
|
|
update_rect.width, update_rect.height);
|
|
|
|
|
gtk_widget_draw (widget, &update_rect);
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Despu<EFBFBD>s de que dibujemos el rect<63>ngulo representando la brocha en el
|
|
|
|
|
<em/pixmap/ llamaremos a la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_widget_draw (GtkWidget *widget,
|
|
|
|
|
GdkRectangle *area);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
que le informa a X de que la zona dada por el par<61>metro <tt/area/
|
|
|
|
|
necesita actualizarse. X generar<61> un evento de exposici<63>n
|
|
|
|
|
(combinando posiblemente distintas zonas pasadas mediante distintas
|
|
|
|
|
llamadas a <tt/gtk_widget_draw()/) que har<61> que nuestro manejador de
|
|
|
|
|
eventos de exposici<63>n copie las porciones relevantes en la pantalla.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Ya hemos cubierto el programa de dibujo completo, excepto unos cuantos
|
|
|
|
|
detalles mundanos como crear la ventana principal. El c<>digo completo
|
|
|
|
|
est<EFBFBD> disponible en el mismo lugar en el que consigui<75> este tutorial,
|
|
|
|
|
o en:
|
|
|
|
|
|
|
|
|
|
<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
|
|
|
|
|
name="http://www.gtk.org/~otaylor/gtk/tutorial/">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> A<>adiendo la capacidad de utilizar XInput
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Ahora es posible comprar dispositos de entrada bastante baratos, como
|
|
|
|
|
tabletas digitalizadoras, que permiten dibujar de forma art<72>stica
|
|
|
|
|
mucho m<>s f<>cilmente de c<>mo lo har<61>amos con un rat<61>n. La forma
|
|
|
|
|
m<EFBFBD>s sencilla de utilizar estos dispositivos es simplemente
|
|
|
|
|
reemplazando a los ratones, pero as<61> perdemos muchas de las ventajas
|
|
|
|
|
de este tipo de dispositivos, como por ejemplo:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> Sensibilidad a la presi<73>n
|
|
|
|
|
<item> Informaci<63>n sobre la inclinaci<63>n
|
|
|
|
|
<item> Colocaci<63>n subpixel
|
|
|
|
|
<item> Multiples entradas (por ejemplo, un l<>piz con una punta y una
|
|
|
|
|
goma)
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
Para informaci<63>n sobre la extensi<73>n XInput, ver el <htmlurl
|
|
|
|
|
url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
|
|
|
|
|
name="XInput-HOWTO">.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Si examinamos la definici<63>n completa de, por ejemplo, la estructura
|
|
|
|
|
<tt/GdkEventMotion/, veremos que tiene campos para almacenar la
|
|
|
|
|
informaci<EFBFBD>n de los dispositivos extendidos.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GdkEventMotion
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *ventana;
|
|
|
|
|
guint32 time;
|
|
|
|
|
gdouble x;
|
|
|
|
|
gdouble y;
|
|
|
|
|
gdouble pressure;
|
|
|
|
|
gdouble xtilt;
|
|
|
|
|
gdouble ytilt;
|
|
|
|
|
guint state;
|
|
|
|
|
gint16 is_hint;
|
|
|
|
|
GdkInputSource source;
|
|
|
|
|
guint32 deviceid;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/pressure/ da la presi<73>n como un n<>mero de coma flotante entre 0
|
|
|
|
|
y 1. <tt/xtilt/ e <tt/ytilt/ pueden tomar valores entre -1 y 1,
|
|
|
|
|
correspondiendo al grado de inclinaci<63>n en cada direcci<63>n. <tt/source/
|
|
|
|
|
y <tt/deviceid/ especifican el dispositivo para el que ocurre el
|
|
|
|
|
evento de dos maneras diferentes. <tt/source/ da alguna informaci<63>n
|
|
|
|
|
simple sobre el tipo de dispositivo. Puede tomar los valores de la
|
|
|
|
|
enumeraci<EFBFBD>n siguiente:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GDK_SOURCE_MOUSE
|
|
|
|
|
GDK_SOURCE_PEN
|
|
|
|
|
GDK_SOURCE_ERASER
|
|
|
|
|
GDK_SOURCE_CURSOR
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<tt/deviceid/ especifica un n<>mero <20>nico ID para el dispositivo. Puede
|
|
|
|
|
utilizarse para obtener m<>s informaci<63>n sobre el dispositivo
|
|
|
|
|
utilizando la funci<63>n <tt/gdk_input_list_devices()/ (ver abajo). El
|
|
|
|
|
valor especial <tt/GDK_CORE_POINTER/ se utiliza para el n<>cleo del
|
|
|
|
|
dispositivo apuntador. (Normalmente el rat<61>n.)
|
|
|
|
|
|
|
|
|
|
<sect2> Activando la informaci<63>n del dispositivo extendido
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Para informar a GTK de nuestro inter<65>s en la informaci<63>n sobre los
|
|
|
|
|
dispositivos extendidos, s<>lo tenemos que a<>adirle una l<>nea a
|
|
|
|
|
nuestro programa:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Dando el valor <tt/GDK_EXTENSION_EVENTS_CURSOR/ decimos que estamos
|
|
|
|
|
interesados en los eventos de extensi<73>n, pero s<>lo si no tenemos que
|
|
|
|
|
dibujar nuestro propio cursor. Ver la secci<63>n <ref
|
|
|
|
|
id="sec_Further_Sophistications" name="Sofisticaciones adicionales">
|
|
|
|
|
m<EFBFBD>s abajo para obtener m<>s informaci<63>n sobre el dibujado del
|
|
|
|
|
cursor. Tambi<62>n podr<64>amos dar los valores
|
|
|
|
|
<tt/GDK_EXTENSION_EVENTS_ALL/ si queremos dibujar nuestro propio
|
|
|
|
|
cursor, o <tt/GDK_EXTENSION_EVENTS_NONE/ para volver al estado
|
|
|
|
|
inicial.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Todav<EFBFBD>a no hemos llegado al final de la historia. Por defecto, no hay
|
|
|
|
|
ning<EFBFBD>n dispositivo extra activado. Necesitamos un mecanismo que
|
|
|
|
|
permita a los usuarios activar y configurar sus dispositivos
|
|
|
|
|
extra. GTK proporciona el <em/widget/ InputDialog para automatizar el
|
|
|
|
|
proceso. El siguiente procedimiento utiliza el <em/widget/
|
|
|
|
|
InputDialog. Crea el cuadro de di<64>logo si no ha sido ya creado, y lo
|
|
|
|
|
pone en primer plano en caso contrario.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void
|
|
|
|
|
input_dialog_destroy (GtkWidget *w, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
*((GtkWidget **)data) = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
create_input_dialog ()
|
|
|
|
|
{
|
|
|
|
|
static GtkWidget *inputd = NULL;
|
|
|
|
|
|
|
|
|
|
if (!inputd)
|
|
|
|
|
{
|
|
|
|
|
inputd = gtk_input_dialog_new();
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
|
|
|
|
|
(GtkSignalFunc)input_dialog_destroy, &inputd);
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
|
|
|
|
|
"clicked",
|
|
|
|
|
(GtkSignalFunc)gtk_widget_hide,
|
|
|
|
|
GTK_OBJECT(inputd));
|
|
|
|
|
gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (inputd);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!GTK_WIDGET_MAPPED(inputd))
|
|
|
|
|
gtk_widget_show(inputd);
|
|
|
|
|
else
|
|
|
|
|
gdk_window_raise(inputd->window);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
(Tome nota de la manera en que hemos manejado el cuadro de
|
|
|
|
|
di<EFBFBD>logo. Conectando la se<73>al <tt/destroy/, nos aseguramos de que no
|
|
|
|
|
tendremos un puntero al cuadro de di<64>logo despu<70>s de que haya sido
|
|
|
|
|
destruido, lo que nos podr<64>a llevar a un segfault.)
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
El InputDialog tiene dos botones <20>Cerrar<61> y <20>Guardar<61>, que por
|
|
|
|
|
defecto no tienen ninguna acci<63>n asignada. En la funci<63>n anterior
|
|
|
|
|
hemos hecho que <20>Cerrar<61> oculte el cuadro de di<64>logo, ocultando el
|
|
|
|
|
bot<EFBFBD>n <20>Guardar<61>, ya que no implementaremos en este programa la
|
|
|
|
|
acci<EFBFBD>n de guardar las opciones de XInput.
|
|
|
|
|
|
|
|
|
|
<sect2> Utilizando la informaci<63>n de los dispositivos extras
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Una vez hemos activado el dispositivo, podemos utilizar la
|
|
|
|
|
informaci<EFBFBD>n que hay respecto a los dispositivos extendidos en los
|
|
|
|
|
campos extras de las estructuras de los eventos. De hecho, es bueno
|
|
|
|
|
utilizar esa informaci<63>n ya que esos campos tienen unos valores por
|
|
|
|
|
defecto razonables a<>n cuando no se activen los eventos extendidos.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Un cambio que tenemos que hacer es llamar a
|
|
|
|
|
<tt/gdk_input_window_get_pointer()/ en vez de a
|
|
|
|
|
<tt/gdk_window_get_pointer/. Esto es necesario porque
|
|
|
|
|
<tt/gdk_window_get_pointer/ no devuelve la informaci<63>n de los
|
|
|
|
|
dispositivos extra.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gdk_input_window_get_pointer (GdkWindow *ventana,
|
|
|
|
|
guint32 deviceid,
|
|
|
|
|
gdouble *x,
|
|
|
|
|
gdouble *y,
|
|
|
|
|
gdouble *pressure,
|
|
|
|
|
gdouble *xtilt,
|
|
|
|
|
gdouble *ytilt,
|
|
|
|
|
GdkModifierType *mask);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Cuando llamamos a esta funci<63>n, necesitamos especificar tanto el ID
|
|
|
|
|
del dispositivo como la ventana. Normalmente, obtendremos el ID del
|
|
|
|
|
dispositivo del campo <tt/deviceid/ de una estructura de evento. De
|
|
|
|
|
nuevo, esta funci<63>n devolver<65> valores razonables cuando no est<73>n
|
|
|
|
|
activados los eventos extendidos. (En ese caso, <tt/event->deviceid/
|
|
|
|
|
tendr<EFBFBD> el valor <tt/GDK_CORE_POINTER/).
|
|
|
|
|
|
|
|
|
|
Por tanto la estructura b<>sica de nuestros manejadores de los
|
|
|
|
|
eventos de movimiento y de pulsaci<63>n del bot<6F>n del rat<61>n no
|
|
|
|
|
cambiar<EFBFBD>n mucho - s<>lo tenemos que a<>adir c<>digo para manejar la
|
|
|
|
|
informaci<EFBFBD>n extra.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static gint
|
|
|
|
|
button_press_event (GtkWidget *widget, GdkEventButton *event)
|
|
|
|
|
{
|
|
|
|
|
print_button_press (event->deviceid);
|
|
|
|
|
|
|
|
|
|
if (event->button == 1 && pixmap != NULL)
|
|
|
|
|
draw_brush (widget, event->source, event->x, event->y, event->pressure);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
|
|
|
|
|
{
|
|
|
|
|
gdouble x, y;
|
|
|
|
|
gdouble pressure;
|
|
|
|
|
GdkModifierType state;
|
|
|
|
|
|
|
|
|
|
if (event->is_hint)
|
|
|
|
|
gdk_input_window_get_pointer (event->window, event->deviceid,
|
|
|
|
|
&x, &y, &pressure, NULL, NULL, &state);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
x = event->x;
|
|
|
|
|
y = event->y;
|
|
|
|
|
pressure = event->pressure;
|
|
|
|
|
state = event->state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state & GDK_BUTTON1_MASK && pixmap != NULL)
|
|
|
|
|
draw_brush (widget, event->source, x, y, pressure);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Tambi<EFBFBD>n tenemos que hacer algo con la nueva informaci<63>n. Nuestra
|
|
|
|
|
nueva funci<63>n <tt/draw_brush()/ dibuja con un color diferente
|
|
|
|
|
dependiendo de <tt/event->source/ y cambia el tama<6D>o de la brocha
|
|
|
|
|
dependiendo de la presi<73>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* Draw a rectangle on the screen, size depending on pressure,
|
|
|
|
|
and color on the type of device */
|
|
|
|
|
static void
|
|
|
|
|
draw_brush (GtkWidget *widget, GdkInputSource source,
|
|
|
|
|
gdouble x, gdouble y, gdouble pressure)
|
|
|
|
|
{
|
|
|
|
|
GdkGC *gc;
|
|
|
|
|
GdkRectangle update_rect;
|
|
|
|
|
|
|
|
|
|
switch (source)
|
|
|
|
|
{
|
|
|
|
|
case GDK_SOURCE_MOUSE:
|
|
|
|
|
gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
|
|
|
|
|
break;
|
|
|
|
|
case GDK_SOURCE_PEN:
|
|
|
|
|
gc = widget->style->black_gc;
|
|
|
|
|
break;
|
|
|
|
|
case GDK_SOURCE_ERASER:
|
|
|
|
|
gc = widget->style->white_gc;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_rect.x = x - 10 * pressure;
|
|
|
|
|
update_rect.y = y - 10 * pressure;
|
|
|
|
|
update_rect.width = 20 * pressure;
|
|
|
|
|
update_rect.height = 20 * pressure;
|
|
|
|
|
gdk_draw_rectangle (pixmap, gc, TRUE,
|
|
|
|
|
update_rect.x, update_rect.y,
|
|
|
|
|
update_rect.width, update_rect.height);
|
|
|
|
|
gtk_widget_draw (widget, &update_rect);
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<sect2> Obteniendo m<>s informaci<63>n de un dispositivo
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Como ejemplo de como podemos obtener m<>s informaci<63>n de un
|
|
|
|
|
dispositivo, nuestro programa imprimir<69> el nombre del dispositivo que
|
|
|
|
|
genera cada pulsaci<63>n de bot<6F>n. Para encontrar el nombre de un
|
|
|
|
|
dispositivo, llamaremos a la funci<63>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GList *gdk_input_list_devices (void);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
que devuelve una GList (una lista enlazada de la biblioteca glib)
|
|
|
|
|
de estructuras <tt/GdkDeviceInfo/. La estructura <tt/GdkDeviceInfo/ se
|
|
|
|
|
define como:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GdkDeviceInfo
|
|
|
|
|
{
|
|
|
|
|
guint32 deviceid;
|
|
|
|
|
gchar *name;
|
|
|
|
|
GdkInputSource source;
|
|
|
|
|
GdkInputMode mode;
|
|
|
|
|
gint has_cursor;
|
|
|
|
|
gint num_axes;
|
|
|
|
|
GdkAxisUse *axes;
|
|
|
|
|
gint num_keys;
|
|
|
|
|
GdkDeviceKey *keys;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Muchos de estos campos son informaci<63>n de configuraci<63>n que puede
|
|
|
|
|
ignorar, a menos que quiera permitir la opci<63>n de grabar la
|
|
|
|
|
configuraci<EFBFBD>n de XInput. El campo que nos interesa ahora es <tt/name/
|
|
|
|
|
que es simplemente el nombre que X le asigna al dispositivo. El otro
|
|
|
|
|
campo que no tiene informaci<63>n sobre la configuraci<63>n es
|
|
|
|
|
<tt/has_cursor/. Si <tt/has_cursor/ es falso, tendremos que dibujar
|
|
|
|
|
nuestro propio cursor. Pero como hemos especificado
|
|
|
|
|
<tt/GDK_EXTENSION_EVENTS_CURSOR/, no tendremos que preocuparnos por
|
|
|
|
|
esto.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Nuestra funci<63>n <tt/print_button_press()/ simplemente recorre la
|
|
|
|
|
lista devuelta hasta que encuentra una coincidencia, y entonces
|
|
|
|
|
imprime el nombre del dispositivo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
static void
|
|
|
|
|
print_button_press (guint32 deviceid)
|
|
|
|
|
{
|
|
|
|
|
GList *tmp_list;
|
|
|
|
|
|
|
|
|
|
/* gdk_input_list_devices returns an internal list, so we shouldn't
|
|
|
|
|
free it afterwards */
|
|
|
|
|
tmp_list = gdk_input_list_devices();
|
|
|
|
|
|
|
|
|
|
while (tmp_list)
|
|
|
|
|
{
|
|
|
|
|
GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
|
|
|
|
|
|
|
|
|
|
if (info->deviceid == deviceid)
|
|
|
|
|
{
|
|
|
|
|
printf("Button press on device '%s'\n", info->name);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tmp_list = tmp_list->next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Con esto hemos completado los cambios para `XInputizar' nuestro
|
|
|
|
|
programa. Como ocurr<72>a con la primera versi<73>n, el c<>digo completo se
|
|
|
|
|
encuentra disponible en el mismo sitio donde obtuvo este tutorial, o
|
|
|
|
|
desde:
|
|
|
|
|
|
|
|
|
|
<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
|
|
|
|
|
name="http://www.gtk.org/~otaylor/gtk/tutorial/">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<sect2> Sofisticaciones adicionales <label id="sec_Further_Sophistications">
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Aunque ahora nuestro programa admite XInput bastante bien, todav<61>a
|
|
|
|
|
falla en algunas caracter<65>sticas que deber<65>an estar disponibles en una
|
|
|
|
|
aplicaci<EFBFBD>n bien hecha. Primero, el usuario no deber<65>a tener que
|
|
|
|
|
configurar su dispositivo cada vez que ejecute el programa, por lo que
|
|
|
|
|
deber<EFBFBD>a estar disponible la opci<63>n de guardar la configuraci<63>n del
|
|
|
|
|
dispositivo. Esto se hace recorriendo el resultado de
|
|
|
|
|
<tt/gdk_input_list_devices()/ y escribiendo la configuraci<63>n en un
|
|
|
|
|
fichero.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Para cargar la configuraci<63>n del dispositivo cuando se vuelva a
|
|
|
|
|
ejecutar el programa, puede utilizar las funciones que proporciona GDK
|
|
|
|
|
para cambiar la configuraci<63>n de los dispositivos:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gdk_input_set_extension_events()
|
|
|
|
|
gdk_input_set_source()
|
|
|
|
|
gdk_input_set_mode()
|
|
|
|
|
gdk_input_set_axes()
|
|
|
|
|
gdk_input_set_key()
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
(La lista devuelta por <tt/gdk_input_list_devices()/ no deber<65>a
|
|
|
|
|
modificarse directamente.) Podemos encontrar un ejemplo de como debe
|
|
|
|
|
utilizarse en el programa de dibujo <tt/gsumi/. (Disponible en
|
|
|
|
|
<htmlurl url="http://www.msc.cornell.edu/~otaylor/gsumi/"
|
|
|
|
|
name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Estar<61>a bien
|
|
|
|
|
tener un procedimiento est<73>ndar para poder hacer todo esto en
|
|
|
|
|
cualquier aplicaciones. Probablemente se llegue a esto en una capa
|
|
|
|
|
superior a GTK, quiz<69>s en la biblioteca GNOME.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
El programa tiene otra carencia importante que ya hemos mencionado m<>s
|
|
|
|
|
arriba, y es la falta del cursor. Ninguna plataforma distinta de
|
|
|
|
|
XFree86 permite utilizar simultaneamente un dispositivo como puntero
|
|
|
|
|
n<EFBFBD>cleo y como dispositivo directamente utilizable por una
|
|
|
|
|
aplicaci<EFBFBD>n. Ver el <url
|
|
|
|
|
url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
|
|
|
|
|
name="XInput-HOWTO"> para m<>s informaci<63>n sobre esto. Con esto
|
|
|
|
|
queremos decir que si quiere tener la m<>xima audiencia necesita
|
|
|
|
|
dibujar su propio cursor.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Una aplicaci<63>n que dibuja su propio cursor necesita hacer dos cosas:
|
|
|
|
|
determinar si el dispositivo actual necesita que se dibuje un cursor o
|
|
|
|
|
no, y determinar si el dispositivo est<73> <20>pr<70>ximo<6D>. (Si el
|
|
|
|
|
dispositivo es una tableta digitalizadora, queda muy bonito que el
|
|
|
|
|
cursor desaparezca cuando el l<>piz se separa de la tableta. Cuando el
|
|
|
|
|
l<EFBFBD>piz est<73> tocando la tableta, se dice que el dispositivo est<73>
|
|
|
|
|
<EFBFBD>pr<EFBFBD>ximo<EFBFBD>). Lo primero se hace buscando la lista de dispositivos,
|
|
|
|
|
tal y como hicimos para encontrar el nombre del dispositivo. Lo
|
|
|
|
|
segundo se consigue seleccionando los eventos
|
|
|
|
|
<em/proximity_out/. Podemos encontrar un ejemplo de como dibujar
|
|
|
|
|
nuestro propio cursor en el programa `testinput' que viene con la
|
|
|
|
|
distribuci<EFBFBD>n de GTK.
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Trucos para escribir aplicaciones GTK
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Esta secci<63>n es s<>lo un compendio de sabiduria, de gu<67>as generales
|
|
|
|
|
de estilo y de consejos para crear buenas aplicaciones GTK. Y es
|
|
|
|
|
totalmente in<69>til por ahora ya que esta frase es s<>lo un t<>pico :)
|
|
|
|
|
|
|
|
|
|
<EFBFBD>Utilice GNU autoconf y automake! Son sus amigos :) Pretendo poner
|
|
|
|
|
aqu<EFBFBD> una r<>pida introducci<63>n a ambos.
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Contribuyendo <label id="sec_Contributing">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Este documento, como muchos otros grandes paquetes de programas que
|
|
|
|
|
hay por ah<61>, fue creado de forma libre por voluntarios. Si comprende
|
|
|
|
|
algo de GTK que todav<61>a no se ha documentado, por favor piense en
|
|
|
|
|
contribuir a este documento.
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Si decide contribuir, por favor mande un correo-e con su texto a Tony
|
|
|
|
|
Gale, <tt><htmlurl url="mailto:gale@gtk.org"
|
|
|
|
|
name="gale@gtk.org"></tt>. Recuerde que todas las partes que componen
|
|
|
|
|
este documento son libre, y cualquier a<>adido que haga debe ser
|
|
|
|
|
libre. Esto es, la gente debe de poder utilizar cualquier trozo de sus
|
|
|
|
|
ejemplos en sus programas, podr<64>n distribuir copias de su documento
|
|
|
|
|
como deseen, etc...
|
|
|
|
|
<p>
|
|
|
|
|
Gracias.
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect>Cr<43>ditos
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
Quiero agradecer a las siguientes personas por sus contribuciones a
|
|
|
|
|
este texto.
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
|
|
|
|
|
name="chamele0n@geocities.com"></tt> por el tutorial sobre los men<65>s.
|
|
|
|
|
|
|
|
|
|
<item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
|
|
|
|
|
name="raph@acm.org"></tt> por el <20>hola mundo<64> a la GTK, el
|
|
|
|
|
empaquetado de <em/widgets/, y su sabidur<75>a general. Ha donado
|
|
|
|
|
generosamente un hogar para este tutorial.
|
|
|
|
|
|
|
|
|
|
<item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
|
|
|
|
|
name="petm@xcf.berkeley.edu"></tt> por el m<>s simple de los programas
|
|
|
|
|
GTK... y por la posibilidad de hacerlo :)
|
|
|
|
|
|
|
|
|
|
<item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
|
|
|
|
|
name="werner.koch@guug.de"></tt> por convertir el texto original a
|
|
|
|
|
SGML, y por la jerarquia de clases de <em/widgets/.
|
|
|
|
|
|
|
|
|
|
<item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
|
|
|
|
|
name="crichton@expert.cc.purdue.edu"></tt> por el c<>digo del men<65>
|
|
|
|
|
factory, y el tutorial sobre el empaquetamiento de las tablas.
|
|
|
|
|
|
|
|
|
|
<item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
|
|
|
|
|
name="owt1@cornell.edu"></tt> por la secci<63>n sobre el <em/widget/
|
|
|
|
|
EventBox (y el parche para el distro). Tambi<62>n es el responsable
|
|
|
|
|
del c<>digo de las selecciones y el tutorial, as<61> como de la
|
|
|
|
|
secci<EFBFBD>n de escribiendo su propio <em/widget/ GTK, y la aplicaci<63>n de
|
|
|
|
|
ejemplo. <20>Muchas gracias por toda tu ayuda, Owen!
|
|
|
|
|
|
|
|
|
|
<item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
|
|
|
|
|
name="mvboom42@calvin.edu"></tt> por su fant<6E>stico trabajo sobre los
|
|
|
|
|
<em/widgets/ Notebook, Progress Bar, Dialog, y selecci<63>n de ficheros.
|
|
|
|
|
<EFBFBD>Muchas gracias Mark!
|
|
|
|
|
Has sido de una gran ayuda.
|
|
|
|
|
|
2000-07-11 19:34:44 +00:00
|
|
|
|
<item>Tim Janik <tt><htmlurl url="mailto:timj@gtk.org"
|
|
|
|
|
name="timj@gtk.org"></tt> por su gran trabajo en el <em/widget/ List.
|
2000-04-23 09:17:36 +00:00
|
|
|
|
Gracias Tim :)
|
|
|
|
|
|
|
|
|
|
<item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
|
|
|
|
|
name="rajat@ix.netcom.com"</tt> por el excelente trabajo con el
|
|
|
|
|
tutorial Pixmap.
|
|
|
|
|
|
|
|
|
|
<item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
|
|
|
|
|
name="johnsonm@redhat.com"></tt> por la informaci<63>n y el c<>digo de
|
|
|
|
|
los men<65>s ("popup").
|
|
|
|
|
|
|
|
|
|
<item>David Huggins-Daines <tt><htmlurl url="mailto:bn711@freenet.carleton.ca"
|
|
|
|
|
name="bn711@freenet.carleton.ca"></tt> por las secciones sobre los
|
|
|
|
|
<em/widgets/ Range y Tree.
|
|
|
|
|
|
|
|
|
|
<item>Stefan Mars <tt><htmlurl url="mailto:mars@lysator.liu.se"
|
|
|
|
|
name="mars@lysator.liu.se"></tt> por la secci<63>n GtkCList
|
|
|
|
|
</itemize>
|
|
|
|
|
<p>
|
|
|
|
|
Y a todos los que han comentado y ayudado a refinar este documento.
|
|
|
|
|
<p>
|
|
|
|
|
Gracias.
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> Copyright del Tutorial y notas sobre los permisos
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Esta traducci<63>n est<73> bajo la misma licencia bajo la que est<73>
|
|
|
|
|
el documento original. A continuaci<63>n se presenta la traducci<63>n
|
|
|
|
|
de la licencia y la licencia en versi<73>n original. En caso de haber
|
|
|
|
|
alguna discrepancia entre la traducci<63>n y la licencia original, se
|
|
|
|
|
aplicar<EFBFBD> esta <20>ltima.
|
|
|
|
|
|
|
|
|
|
El Tutorial GTK tiene Copyright (C) 1997 Ian Main.
|
|
|
|
|
|
|
|
|
|
Copyright (C) 1998 Tony Gale.
|
|
|
|
|
<p>
|
|
|
|
|
Se da permiso para hacer y distribuir copias id<69>nticas de este manual
|
|
|
|
|
siempre que se incluya el copyright en todas las copias.
|
|
|
|
|
<p>
|
|
|
|
|
Se da permiso para copiar y distribuir versiones modificadas de este
|
|
|
|
|
documento bajo las mismas condiciones que para las copias id<69>nticas,
|
|
|
|
|
siempre que el copyright se incluya exactamente tal y como se
|
|
|
|
|
encuentra en el original, y que el trabajo completo derivado de este
|
|
|
|
|
documento se distribuya bajo los t<>rminos de un permiso id<69>ntico a
|
|
|
|
|
<EFBFBD>ste.
|
|
|
|
|
<P>
|
|
|
|
|
Se da permiso para copiar y distribuir traducciones de este documento
|
|
|
|
|
en otro lenguaje, bajo las condiciones arriba mencionadas para las
|
|
|
|
|
versiones modificadas.
|
|
|
|
|
<P>
|
|
|
|
|
Si se propone incluir este documento en un trabajo que vaya a ser
|
|
|
|
|
impreso, por favor contacte con el encargado del mantenimiento, y
|
|
|
|
|
haremos un esfuerzo para asegurarnos de que dispone de la informaci<63>n
|
|
|
|
|
lo m<>s actualizada posible.
|
|
|
|
|
<P>
|
|
|
|
|
No hay ninguna garantia de que este documento se mantenga activo lo
|
|
|
|
|
suficiente como para conseguir cumplir con su prop<6F>sito. Se
|
|
|
|
|
proporciona como un documento libre. Como tal, los autores y
|
|
|
|
|
encargados del mantenimiento de la informaci<63>n que se da en el
|
|
|
|
|
documento no pueden dar ninguna garantia de que la misma est<73> al d<>a.
|
|
|
|
|
<P>
|
|
|
|
|
-----------------------------
|
|
|
|
|
<p>
|
|
|
|
|
The GTK Tutorial is Copyright (C) 1997 Ian Main.
|
|
|
|
|
|
|
|
|
|
Copyright (C) 1998 Tony Gale.
|
|
|
|
|
<p>
|
|
|
|
|
Permission is granted to make and distribute verbatim copies of this
|
|
|
|
|
manual provided the copyright notice and this permission notice are
|
|
|
|
|
preserved on all copies.
|
|
|
|
|
<P>Permission is granted to copy and distribute modified versions of
|
|
|
|
|
this document under the conditions for verbatim copying, provided that
|
|
|
|
|
this copyright notice is included exactly as in the original,
|
|
|
|
|
and that the entire resulting derived work is distributed under
|
|
|
|
|
the terms of a permission notice identical to this one.
|
|
|
|
|
<P>Permission is granted to copy and distribute translations of this
|
|
|
|
|
document into another language, under the above conditions for modified
|
|
|
|
|
versions.
|
|
|
|
|
<P>If you are intending to incorporate this document into a published
|
|
|
|
|
work, please contact the maintainer, and we will make an effort
|
|
|
|
|
to ensure that you have the most up to date information available.
|
|
|
|
|
<P>There is no guarantee that this document lives up to its intended
|
|
|
|
|
purpose. This is simply provided as a free resource. As such,
|
|
|
|
|
the authors and maintainers of the information provided within can
|
|
|
|
|
not make any guarantee that the information is even accurate.
|
|
|
|
|
|
|
|
|
|
<sect1>Acerca de la traducci<63>n
|
|
|
|
|
|
|
|
|
|
<p>
|
|
|
|
|
Esta traduccion tiene copyright (C) 1999 de Joaqu<71>n Cuenca Abela
|
|
|
|
|
<tt><htmlurl url="mailto:e98cuenc@criens.u-psud.fr"
|
|
|
|
|
name="<e98cuenc@criens.u-psud.fr>"></tt>
|
|
|
|
|
y de Eduardo Anglada Varela
|
|
|
|
|
<tt><htmlurl url="mailto:eduardo.anglada@adi.uam.es"
|
|
|
|
|
name="<eduardo.anglada@adi.uam.es>"></tt>.
|
|
|
|
|
Si tiene cualquier
|
|
|
|
|
duda, sugerencia o correcci<63>n no dude en consultarnos.
|
|
|
|
|
|
|
|
|
|
Gracias a Manuel de Vega Barreiro <tt><htmlurl
|
|
|
|
|
url="mailto:barreiro@arrakis.es"
|
|
|
|
|
name="<barreiro@arrakis.es>"></tt> por haber hospedado las
|
|
|
|
|
versiones beta y la versi<73>n actual de este tutorial en su p<>gina
|
|
|
|
|
web Linux Landia <tt><url
|
|
|
|
|
url="http://www.croftj.net/~barreiro/spain/gnome/"
|
|
|
|
|
name="www.croftj.net/~barreiro/spain/gnome/"></tt>.
|
|
|
|
|
|
|
|
|
|
</sect1>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<appendix>
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> Se<53>ales GTK <label id="sec_GTK_Signals">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
GTK+, al ser un conjunto de <em/widgets/ orientado al objeto, tiene
|
|
|
|
|
una jerarqu<71>a de herencias. Este mecanismo de herencia se aplica a las
|
|
|
|
|
se<EFBFBD>ales. Por eso, debe utilizar el <20>rbol de jerarqu<71>as de los
|
|
|
|
|
<em/widgets/ cuando utilice las se<73>ales que aparecen en esta secci<63>n.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkObject
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkObject::destroy (GtkObject *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkWidget
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
|
|
|
|
|
void GtkWidget::show (GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::hide (GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::map (GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::unmap (GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::realize (GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::unrealize (GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::draw (GtkWidget *,
|
|
|
|
|
ggpointer,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::draw-focus (GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::draw-default (GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::size-request (GtkWidget *,
|
|
|
|
|
ggpointer,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::size-allocate (GtkWidget *,
|
|
|
|
|
ggpointer,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::state-changed (GtkWidget *,
|
|
|
|
|
GtkStateType,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::parent-set (GtkWidget *,
|
|
|
|
|
GtkObject *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::style-set (GtkWidget *,
|
|
|
|
|
GtkStyle *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::add-accelerator (GtkWidget *,
|
|
|
|
|
gguint,
|
|
|
|
|
GtkAccelGroup *,
|
|
|
|
|
gguint,
|
|
|
|
|
GdkModifierType,
|
|
|
|
|
GtkAccelFlags,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::remove-accelerator (GtkWidget *,
|
|
|
|
|
GtkAccelGroup *,
|
|
|
|
|
gguint,
|
|
|
|
|
GdkModifierType,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::button-press-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::button-release-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::motion-notify-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::delete-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::destroy-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::expose-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::key-press-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::key-release-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::enter-notify-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::leave-notify-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::configure-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::focus-in-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::focus-out-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::map-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::unmap-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::property-notify-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::selection-clear-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::selection-request-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::selection-notify-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::selection-get (GtkWidget *,
|
|
|
|
|
GtkSelectionData *,
|
|
|
|
|
gguint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::selection-received (GtkWidget *,
|
|
|
|
|
GtkSelectionData *,
|
|
|
|
|
gguint,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::proximity-in-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::proximity-out-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::drag-begin (GtkWidget *,
|
|
|
|
|
GdkDragContext *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::drag-end (GtkWidget *,
|
|
|
|
|
GdkDragContext *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::drag-data-delete (GtkWidget *,
|
|
|
|
|
GdkDragContext *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::drag-leave (GtkWidget *,
|
|
|
|
|
GdkDragContext *,
|
|
|
|
|
gguint,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::drag-motion (GtkWidget *,
|
|
|
|
|
GdkDragContext *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
gguint,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::drag-drop (GtkWidget *,
|
|
|
|
|
GdkDragContext *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
gguint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::drag-data-get (GtkWidget *,
|
|
|
|
|
GdkDragContext *,
|
|
|
|
|
GtkSelectionData *,
|
|
|
|
|
gguint,
|
|
|
|
|
gguint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::drag-data-received (GtkWidget *,
|
|
|
|
|
GdkDragContext *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
GtkSelectionData *,
|
|
|
|
|
gguint,
|
|
|
|
|
gguint,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::client-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::no-expose-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkWidget::visibility-notify-event (GtkWidget *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkWidget::debug-msg (GtkWidget *,
|
|
|
|
|
GtkString *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkData
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkData::disconnect (GtkData *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkContainer
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkContainer::add (GtkContainer *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkContainer::remove (GtkContainer *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkContainer::check-resize (GtkContainer *,
|
|
|
|
|
gpointer);
|
|
|
|
|
GtkDirectionType GtkContainer::focus (GtkContainer *,
|
|
|
|
|
GtkDirectionType,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkContainer::set-focus-child (GtkContainer *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkCalendar
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkCalendar::month-changed (GtkCalendar *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCalendar::day-selected (GtkCalendar *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCalendar::day-selected-double-click (GtkCalendar *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCalendar::prev-month (GtkCalendar *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCalendar::next-month (GtkCalendar *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCalendar::prev-year (GtkCalendar *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCalendar::next-year (GtkCalendar *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkEditable
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkEditable::changed (GtkEditable *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::insert-text (GtkEditable *,
|
|
|
|
|
GtkString *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggpointer,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::delete-text (GtkEditable *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::activate (GtkEditable *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::set-editable (GtkEditable *,
|
|
|
|
|
gboolean,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::move-cursor (GtkEditable *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::move-word (GtkEditable *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::move-page (GtkEditable *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::move-to-row (GtkEditable *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::move-to-column (GtkEditable *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::kill-char (GtkEditable *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::kill-word (GtkEditable *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::kill-line (GtkEditable *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::cut-clipboard (GtkEditable *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::copy-clipboard (GtkEditable *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkEditable::paste-clipboard (GtkEditable *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkTipsQuery
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkTipsQuery::start-query (GtkTipsQuery *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkTipsQuery::stop-query (GtkTipsQuery *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkTipsQuery::widget-entered (GtkTipsQuery *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
GtkString *,
|
|
|
|
|
GtkString *,
|
|
|
|
|
gpointer);
|
|
|
|
|
gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
GtkString *,
|
|
|
|
|
GtkString *,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkCList
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkCList::select-row (GtkCList *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::unselect-row (GtkCList *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
GdkEvent *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::row-move (GtkCList *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::click-column (GtkCList *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::resize-column (GtkCList *,
|
|
|
|
|
ggint,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::toggle-focus-row (GtkCList *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::select-all (GtkCList *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::unselect-all (GtkCList *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::undo-selection (GtkCList *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::start-selection (GtkCList *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::end-selection (GtkCList *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::toggle-add-mode (GtkCList *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::extend-selection (GtkCList *,
|
|
|
|
|
GtkScrollType,
|
|
|
|
|
ggfloat,
|
|
|
|
|
gboolean,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::scroll-vertical (GtkCList *,
|
|
|
|
|
GtkScrollType,
|
|
|
|
|
ggfloat,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::scroll-horizontal (GtkCList *,
|
|
|
|
|
GtkScrollType,
|
|
|
|
|
ggfloat,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCList::abort-column-resize (GtkCList *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkNotebook
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkNotebook::switch-page (GtkNotebook *,
|
|
|
|
|
ggpointer,
|
|
|
|
|
gguint,
|
|
|
|
|
gpointer);
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkList
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkList::selection-changed (GtkList *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkList::select-child (GtkList *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkList::unselect-child (GtkList *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkMenuShell
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkMenuShell::deactivate (GtkMenuShell *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkMenuShell::selection-done (GtkMenuShell *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkMenuShell::move-current (GtkMenuShell *,
|
|
|
|
|
GtkMenuDirectionType,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkMenuShell::activate-current (GtkMenuShell *,
|
|
|
|
|
gboolean,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkMenuShell::cancel (GtkMenuShell *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkToolbar
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkToolbar::orientation-changed (GtkToolbar *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkToolbar::style-changed (GtkToolbar *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkTree
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkTree::selection-changed (GtkTree *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkTree::select-child (GtkTree *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkTree::unselect-child (GtkTree *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkButton
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkButton::pressed (GtkButton *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkButton::released (GtkButton *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkButton::clicked (GtkButton *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkButton::enter (GtkButton *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkButton::leave (GtkButton *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkItem
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkItem::select (GtkItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkItem::deselect (GtkItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkItem::toggle (GtkItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkWindow
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkWindow::set-focus (GtkWindow *,
|
|
|
|
|
ggpointer,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkHandleBox
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkHandleBox::child-attached (GtkHandleBox *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkHandleBox::child-detached (GtkHandleBox *,
|
|
|
|
|
GtkWidget *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkToggleButton
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkToggleButton::toggled (GtkToggleButton *,
|
|
|
|
|
gpointer);
|
|
|
|
|
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkMenuItem
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkMenuItem::activate (GtkMenuItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkMenuItem::activate-item (GtkMenuItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkListItem
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkListItem::toggle-focus-row (GtkListItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkListItem::select-all (GtkListItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkListItem::unselect-all (GtkListItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkListItem::undo-selection (GtkListItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkListItem::start-selection (GtkListItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkListItem::end-selection (GtkListItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkListItem::toggle-add-mode (GtkListItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkListItem::extend-selection (GtkListItem *,
|
|
|
|
|
GtkEnum,
|
|
|
|
|
ggfloat,
|
|
|
|
|
gboolean,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkListItem::scroll-vertical (GtkListItem *,
|
|
|
|
|
GtkEnum,
|
|
|
|
|
ggfloat,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkListItem::scroll-horizontal (GtkListItem *,
|
|
|
|
|
GtkEnum,
|
|
|
|
|
ggfloat,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkTreeItem
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkTreeItem::collapse (GtkTreeItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkTreeItem::expand (GtkTreeItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkCheckMenuItem
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkCheckMenuItem::toggled (GtkCheckMenuItem *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkInputDialog
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkInputDialog::enable-device (GtkInputDialog *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkInputDialog::disable-device (GtkInputDialog *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkColorSelection
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkColorSelection::color-changed (GtkColorSelection *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkStatusBar
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkStatusbar::text-pushed (GtkStatusbar *,
|
|
|
|
|
gguint,
|
|
|
|
|
GtkString *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkStatusbar::text-popped (GtkStatusbar *,
|
|
|
|
|
gguint,
|
|
|
|
|
GtkString *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkCTree
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkCTree::tree-select-row (GtkCTree *,
|
|
|
|
|
GtkCTreeNode *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCTree::tree-unselect-row (GtkCTree *,
|
|
|
|
|
GtkCTreeNode *,
|
|
|
|
|
ggint,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCTree::tree-expand (GtkCTree *,
|
|
|
|
|
GtkCTreeNode *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCTree::tree-collapse (GtkCTree *,
|
|
|
|
|
ggpointer,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCTree::tree-move (GtkCTree *,
|
|
|
|
|
GtkCTreeNode *,
|
|
|
|
|
GtkCTreeNode *,
|
|
|
|
|
GtkCTreeNode *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkCTree::change-focus-row-expansion (GtkCTree *,
|
|
|
|
|
GtkCTreeExpansionType,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkCurve
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkCurve::curve-type-changed (GtkCurve *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>GtkAdjustment
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void GtkAdjustment::changed (GtkAdjustment *,
|
|
|
|
|
gpointer);
|
|
|
|
|
void GtkAdjustment::value-changed (GtkAdjustment *,
|
|
|
|
|
gpointer);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> Tipos de eventos GDK<label id="sec_GDK_Event_Types">
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
Los siguientes tipos de datos se pasan en los manejadores de los
|
|
|
|
|
eventos por GTK+. Para cada tipo de dato que se muestra, se muestran
|
|
|
|
|
las se<73>ales que utilizan ese tipo de dato.
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GdkEvent
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>drag_end_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventType
|
|
|
|
|
|
|
|
|
|
<item> GdkEventAny
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>delete_event
|
|
|
|
|
<item>destroy_event
|
|
|
|
|
<item>map_event
|
|
|
|
|
<item>unmap_event
|
|
|
|
|
<item>no_expose_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventExpose
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>expose_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventNoExpose
|
|
|
|
|
|
|
|
|
|
<item> GdkEventVisibility
|
|
|
|
|
|
|
|
|
|
<item> GdkEventMotion
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>motion_notify_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventButton
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>button_press_event
|
|
|
|
|
<item>button_release_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventKey
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>key_press_event
|
|
|
|
|
<item>key_release_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventCrossing
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>enter_notify_event
|
|
|
|
|
<item>leave_notify_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventFocus
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>focus_in_event
|
|
|
|
|
<item>focus_out_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventConfigure
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>configure_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventProperty
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>property_notify_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventSelection
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>selection_clear_event
|
|
|
|
|
<item>selection_request_event
|
|
|
|
|
<item>selection_notify_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventProximity
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>proximity_in_event
|
|
|
|
|
<item>proximity_out_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventDragBegin
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>drag_begin_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventDragRequest
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>drag_request_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventDropEnter
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>drop_enter_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventDropLeave
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>drop_leave_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventDropDataAvailable
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>drop_data_available_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventClient
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>client_event
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
<item> GdkEventOther
|
|
|
|
|
<itemize>
|
|
|
|
|
<item>other_event
|
|
|
|
|
</itemize>
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
El tipo de dato <tt/GdkEventType/ es un tipo de dato especial que se
|
|
|
|
|
utiliza por todos los otros tipos de datos como un indicador del tipo
|
|
|
|
|
de dato que se le est<73> pasando al manejador de se<73>al. Como ver<65>
|
|
|
|
|
m<EFBFBD>s adelante, cada una de estructuras de los datos de los eventos
|
|
|
|
|
tienen un miembro de este tipo. Se define como la siguiente
|
|
|
|
|
enumeraci<EFBFBD>n:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
typedef enum
|
|
|
|
|
{
|
|
|
|
|
GDK_NOTHING = -1,
|
|
|
|
|
GDK_DELETE = 0,
|
|
|
|
|
GDK_DESTROY = 1,
|
|
|
|
|
GDK_EXPOSE = 2,
|
|
|
|
|
GDK_MOTION_NOTIFY = 3,
|
|
|
|
|
GDK_BUTTON_PRESS = 4,
|
|
|
|
|
GDK_2BUTTON_PRESS = 5,
|
|
|
|
|
GDK_3BUTTON_PRESS = 6,
|
|
|
|
|
GDK_BUTTON_RELEASE = 7,
|
|
|
|
|
GDK_KEY_PRESS = 8,
|
|
|
|
|
GDK_KEY_RELEASE = 9,
|
|
|
|
|
GDK_ENTER_NOTIFY = 10,
|
|
|
|
|
GDK_LEAVE_NOTIFY = 11,
|
|
|
|
|
GDK_FOCUS_CHANGE = 12,
|
|
|
|
|
GDK_CONFIGURE = 13,
|
|
|
|
|
GDK_MAP = 14,
|
|
|
|
|
GDK_UNMAP = 15,
|
|
|
|
|
GDK_PROPERTY_NOTIFY = 16,
|
|
|
|
|
GDK_SELECTION_CLEAR = 17,
|
|
|
|
|
GDK_SELECTION_REQUEST = 18,
|
|
|
|
|
GDK_SELECTION_NOTIFY = 19,
|
|
|
|
|
GDK_PROXIMITY_IN = 20,
|
|
|
|
|
GDK_PROXIMITY_OUT = 21,
|
|
|
|
|
GDK_DRAG_BEGIN = 22,
|
|
|
|
|
GDK_DRAG_REQUEST = 23,
|
|
|
|
|
GDK_DROP_ENTER = 24,
|
|
|
|
|
GDK_DROP_LEAVE = 25,
|
|
|
|
|
GDK_DROP_DATA_AVAIL = 26,
|
|
|
|
|
GDK_CLIENT_EVENT = 27,
|
|
|
|
|
GDK_VISIBILITY_NOTIFY = 28,
|
|
|
|
|
GDK_NO_EXPOSE = 29,
|
|
|
|
|
GDK_OTHER_EVENT = 9999 /* Anacr<63>nico, utilice en su lugar los
|
|
|
|
|
filtros */
|
|
|
|
|
} GdkEventType;
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El otro tipo de evento que es diferente del resto es el mismo
|
|
|
|
|
<tt/GdkEvent/. <20>sta es una uni<6E>n de todos los otros tipos de
|
|
|
|
|
datos, que permite que se convierta en un tipo de dato de evento
|
|
|
|
|
espec<EFBFBD>fico con un manejador de se<73>al.
|
|
|
|
|
|
|
|
|
|
<!-- Just a big list for now, needs expanding upon - TRG -->
|
|
|
|
|
Por tanto, los tipos de los datos de los eventos se definen como
|
|
|
|
|
sigue:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GdkEventAny
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventExpose
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
GdkRectangle area;
|
|
|
|
|
gint count; /* Si count no es, entonces es el n<>mero de eventos que
|
|
|
|
|
* siguen. */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventNoExpose
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
/* XXX: <20>Hay alguien que necesite los campos major_code y minor_code
|
|
|
|
|
de X ? */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventVisibility
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
GdkVisibilityState state;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventMotion
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
guint32 time;
|
|
|
|
|
gdouble x;
|
|
|
|
|
gdouble y;
|
|
|
|
|
gdouble pressure;
|
|
|
|
|
gdouble xtilt;
|
|
|
|
|
gdouble ytilt;
|
|
|
|
|
guint state;
|
|
|
|
|
gint16 is_hint;
|
|
|
|
|
GdkInputSource source;
|
|
|
|
|
guint32 deviceid;
|
|
|
|
|
gdouble x_root, y_root;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventButton
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
guint32 time;
|
|
|
|
|
gdouble x;
|
|
|
|
|
gdouble y;
|
|
|
|
|
gdouble pressure;
|
|
|
|
|
gdouble xtilt;
|
|
|
|
|
gdouble ytilt;
|
|
|
|
|
guint state;
|
|
|
|
|
guint button;
|
|
|
|
|
GdkInputSource source;
|
|
|
|
|
guint32 deviceid;
|
|
|
|
|
gdouble x_root, y_root;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventKey
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
guint32 time;
|
|
|
|
|
guint state;
|
|
|
|
|
guint keyval;
|
|
|
|
|
gint length;
|
|
|
|
|
gchar *string;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventCrossing
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
GdkWindow *subwindow;
|
|
|
|
|
GdkNotifyType detail;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventFocus
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
gint16 in;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventConfigure
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
gint16 x, y;
|
|
|
|
|
gint16 width;
|
|
|
|
|
gint16 height;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventProperty
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
GdkAtom atom;
|
|
|
|
|
guint32 time;
|
|
|
|
|
guint state;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventSelection
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
GdkAtom selection;
|
|
|
|
|
GdkAtom target;
|
|
|
|
|
GdkAtom property;
|
|
|
|
|
guint32 requestor;
|
|
|
|
|
guint32 time;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Este tipo de evento se utiliza muy raramente. Solamente es
|
|
|
|
|
* importante para los programas que utilizan XInput y que dibujar su
|
|
|
|
|
* propio cursor */
|
|
|
|
|
|
|
|
|
|
struct _GdkEventProximity
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
guint32 time;
|
|
|
|
|
GdkInputSource source;
|
|
|
|
|
guint32 deviceid;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventDragRequest
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
guint32 requestor;
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
guint protocol_version:4;
|
|
|
|
|
guint sendreply:1;
|
|
|
|
|
guint willaccept:1;
|
|
|
|
|
guint delete_data:1; /* No borrar si se ha mandado un enlace,
|
|
|
|
|
s<>lo si se ha mandado el dato */
|
|
|
|
|
guint senddata:1;
|
|
|
|
|
guint reserved:22;
|
|
|
|
|
} flags;
|
|
|
|
|
glong allflags;
|
|
|
|
|
} u;
|
|
|
|
|
guint8 isdrop; /* Este evento gdk puede ser generado por un par de
|
|
|
|
|
eventos X - esto le permite a las aplicaciones
|
|
|
|
|
saber si ha ocurrido realmente el soltado (drop),
|
|
|
|
|
o si s<>lo hemos cambiado el valor de algunos datos
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
GdkPoint drop_coords;
|
|
|
|
|
gchar *data_type;
|
|
|
|
|
guint32 timestamp;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventDragBegin
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
guint protocol_version:4;
|
|
|
|
|
guint reserved:28;
|
|
|
|
|
} flags;
|
|
|
|
|
glong allflags;
|
|
|
|
|
} u;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventDropEnter
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
guint32 requestor;
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
guint protocol_version:4;
|
|
|
|
|
guint sendreply:1;
|
|
|
|
|
guint extended_typelist:1;
|
|
|
|
|
guint reserved:26;
|
|
|
|
|
} flags;
|
|
|
|
|
glong allflags;
|
|
|
|
|
} u;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventDropLeave
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
guint32 requestor;
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
guint protocol_version:4;
|
|
|
|
|
guint reserved:28;
|
|
|
|
|
} flags;
|
|
|
|
|
glong allflags;
|
|
|
|
|
} u;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventDropDataAvailable
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
guint32 requestor;
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
guint protocol_version:4;
|
|
|
|
|
guint isdrop:1;
|
|
|
|
|
guint reserved:25;
|
|
|
|
|
} flags;
|
|
|
|
|
glong allflags;
|
|
|
|
|
} u;
|
|
|
|
|
gchar *data_type; /* tipo MIME */
|
|
|
|
|
gulong data_numbytes;
|
|
|
|
|
gpointer data;
|
|
|
|
|
guint32 timestamp;
|
|
|
|
|
GdkPoint coords;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventClient
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
GdkAtom message_type;
|
|
|
|
|
gushort data_format;
|
|
|
|
|
union {
|
|
|
|
|
char b[20];
|
|
|
|
|
short s[10];
|
|
|
|
|
long l[5];
|
|
|
|
|
} data;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GdkEventOther
|
|
|
|
|
{
|
|
|
|
|
GdkEventType type;
|
|
|
|
|
GdkWindow *window;
|
|
|
|
|
gint8 send_event;
|
|
|
|
|
GdkXEvent *xevent;
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> C<>digo ejemplo
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
A continuaci<63>n tenemos el c<>digo ejemplo que se ha utilizado en el
|
|
|
|
|
texto anterior y que no se ha incluido al completo en otro lugar.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1>Tictactoe
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2>tictactoe.h
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo tictactoe tictactoe.h */
|
|
|
|
|
|
2008-07-01 22:57:50 +00:00
|
|
|
|
/* GTK - The GIMP Toolkit
|
2000-04-23 09:17:36 +00:00
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
|
*/
|
|
|
|
|
#ifndef __TICTACTOE_H__
|
|
|
|
|
#define __TICTACTOE_H__
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <gdk/gdk.h>
|
|
|
|
|
#include <gtk/gtkvbox.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
|
|
#define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
|
|
|
|
|
#define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
|
|
|
|
|
#define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _Tictactoe Tictactoe;
|
|
|
|
|
typedef struct _TictactoeClass TictactoeClass;
|
|
|
|
|
|
|
|
|
|
struct _Tictactoe
|
|
|
|
|
{
|
|
|
|
|
GtkVBox vbox;
|
|
|
|
|
|
|
|
|
|
GtkWidget *botones[3][3];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _TictactoeClass
|
|
|
|
|
{
|
|
|
|
|
GtkVBoxClass parent_class;
|
|
|
|
|
|
|
|
|
|
void (* tictactoe) (Tictactoe *ttt);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
guint tictactoe_get_type (void);
|
|
|
|
|
GtkWidget* tictactoe_new (void);
|
|
|
|
|
void tictactoe_clear (Tictactoe *ttt);
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
|
|
#endif /* __TICTACTOE_H__ */
|
|
|
|
|
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2>tictactoe.c
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo tictactoe tictactoe.c */
|
|
|
|
|
|
2008-07-01 22:57:50 +00:00
|
|
|
|
/* GTK - The GIMP Toolkit
|
2000-04-23 09:17:36 +00:00
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
|
*/
|
|
|
|
|
#include "gtk/gtksignal.h"
|
|
|
|
|
#include "gtk/gtktable.h"
|
|
|
|
|
#include "gtk/gtktogglebutton.h"
|
|
|
|
|
#include "tictactoe.h"
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
TICTACTOE_SIGNAL,
|
|
|
|
|
LAST_SIGNAL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void tictactoe_class_init (TictactoeClass *klass);
|
|
|
|
|
static void tictactoe_init (Tictactoe *ttt);
|
|
|
|
|
static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt);
|
|
|
|
|
|
|
|
|
|
static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
|
|
|
|
guint
|
|
|
|
|
tictactoe_get_type ()
|
|
|
|
|
{
|
|
|
|
|
static guint ttt_type = 0;
|
|
|
|
|
|
|
|
|
|
if (!ttt_type)
|
|
|
|
|
{
|
|
|
|
|
GtkTypeInfo ttt_info =
|
|
|
|
|
{
|
|
|
|
|
"Tictactoe",
|
|
|
|
|
sizeof (Tictactoe),
|
|
|
|
|
sizeof (TictactoeClass),
|
|
|
|
|
(GtkClassInitFunc) tictactoe_class_init,
|
|
|
|
|
(GtkObjectInitFunc) tictactoe_init,
|
|
|
|
|
(GtkArgSetFunc) NULL,
|
|
|
|
|
(GtkArgGetFunc) NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ttt_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tictactoe_class_init (TictactoeClass *class)
|
|
|
|
|
{
|
|
|
|
|
GtkObjectClass *object_class;
|
|
|
|
|
|
|
|
|
|
object_class = (GtkObjectClass*) class;
|
|
|
|
|
|
|
|
|
|
tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
|
|
|
|
|
GTK_RUN_FIRST,
|
|
|
|
|
object_class->type,
|
|
|
|
|
GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
|
|
|
|
|
gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
|
|
|
|
|
|
|
|
|
|
class->tictactoe = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tictactoe_init (Tictactoe *ttt)
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *table;
|
|
|
|
|
gint i,j;
|
|
|
|
|
|
|
|
|
|
table = gtk_table_new (3, 3, TRUE);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER(ttt), table);
|
|
|
|
|
gtk_widget_show (table);
|
|
|
|
|
|
|
|
|
|
for (i=0;i<3; i++)
|
|
|
|
|
for (j=0;j<3; j++)
|
|
|
|
|
{
|
|
|
|
|
ttt->buttons[i][j] = gtk_toggle_button_new ();
|
|
|
|
|
gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j],
|
|
|
|
|
i, i+1, j, j+1);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
|
|
|
|
|
GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
|
|
|
|
|
gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
|
|
|
|
|
gtk_widget_show (ttt->buttons[i][j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GtkWidget*
|
|
|
|
|
tictactoe_new ()
|
|
|
|
|
{
|
|
|
|
|
return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
tictactoe_clear (Tictactoe *ttt)
|
|
|
|
|
{
|
|
|
|
|
int i,j;
|
|
|
|
|
|
|
|
|
|
for (i=0;i<3;i++)
|
|
|
|
|
for (j=0;j<3;j++)
|
|
|
|
|
{
|
|
|
|
|
gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
|
|
|
|
|
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
|
|
|
|
|
FALSE);
|
|
|
|
|
gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
|
|
|
|
|
{
|
|
|
|
|
int i,k;
|
|
|
|
|
|
|
|
|
|
static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
|
|
|
|
|
{ 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
|
|
|
|
|
{ 0, 1, 2 }, { 0, 1, 2 } };
|
|
|
|
|
static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
|
|
|
|
|
{ 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
|
|
|
|
|
{ 0, 1, 2 }, { 2, 1, 0 } };
|
|
|
|
|
|
|
|
|
|
int success, found;
|
|
|
|
|
|
|
|
|
|
for (k=0; k<8; k++)
|
|
|
|
|
{
|
|
|
|
|
success = TRUE;
|
|
|
|
|
found = FALSE;
|
|
|
|
|
|
|
|
|
|
for (i=0;i<3;i++)
|
|
|
|
|
{
|
|
|
|
|
success = success &&
|
|
|
|
|
GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
|
|
|
|
|
found = found ||
|
|
|
|
|
ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (success && found)
|
|
|
|
|
{
|
|
|
|
|
gtk_signal_emit (GTK_OBJECT (ttt),
|
|
|
|
|
tictactoe_signals[TICTACTOE_SIGNAL]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2>ttt_test.c
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo tictactoe ttt_test.c */
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
#include "tictactoe.h"
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
win (GtkWidget *widget, gpointer data)
|
|
|
|
|
{
|
|
|
|
|
g_print ("Yay!\n");
|
|
|
|
|
tictactoe_clear (TICTACTOE (widget));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *ttt;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
|
|
|
|
|
gtk_window_set_title (GTK_WINDOW (ventana), "Aspect Frame");
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_exit), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_container_border_width (GTK_CONTAINER (ventana), 10);
|
|
|
|
|
|
|
|
|
|
ttt = tictactoe_new ();
|
|
|
|
|
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), ttt);
|
|
|
|
|
gtk_widget_show (ttt);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
|
|
|
|
|
GTK_SIGNAL_FUNC (win), NULL);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> GtkDial
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> gtkdial.h
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejmplo gtkdial gtkdial.h */
|
|
|
|
|
|
2008-07-01 22:57:50 +00:00
|
|
|
|
/* GTK - The GIMP Toolkit
|
2000-04-23 09:17:36 +00:00
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
|
*/
|
|
|
|
|
#ifndef __GTK_DIAL_H__
|
|
|
|
|
#define __GTK_DIAL_H__
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <gdk/gdk.h>
|
|
|
|
|
#include <gtk/gtkadjustment.h>
|
|
|
|
|
#include <gtk/gtkwidget.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
|
|
|
|
|
#define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
|
|
|
|
|
#define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _GtkDial GtkDial;
|
|
|
|
|
typedef struct _GtkDialClass GtkDialClass;
|
|
|
|
|
|
|
|
|
|
struct _GtkDial
|
|
|
|
|
{
|
|
|
|
|
GtkWidget widget;
|
|
|
|
|
|
|
|
|
|
/* pol<6F>tica de actualizaci<63>n
|
|
|
|
|
* (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
|
|
|
|
|
guint policy : 2;
|
|
|
|
|
|
|
|
|
|
/* Bot<6F>n actualmente presionado o 0 si no hay ninguno */
|
|
|
|
|
guint8 boton;
|
|
|
|
|
|
|
|
|
|
/* Dimensi<73>n de los componendes del dial */
|
|
|
|
|
gint radius;
|
|
|
|
|
gint pointer_width;
|
|
|
|
|
|
|
|
|
|
/* ID del temporizador de actualizaci<63>n, o 0 si no hay ninguno */
|
|
|
|
|
guint32 timer;
|
|
|
|
|
|
|
|
|
|
/* <20>ngulo actual */
|
|
|
|
|
gfloat angle;
|
|
|
|
|
|
|
|
|
|
/* Viejos valores almacenados del adjustment, para que as<61> no
|
|
|
|
|
* tengamos que saber cuando cambia algo */
|
|
|
|
|
gfloat old_value;
|
|
|
|
|
gfloat old_lower;
|
|
|
|
|
gfloat old_upper;
|
|
|
|
|
|
|
|
|
|
/* El objeto adjustment que almacena los datos para este dial */
|
|
|
|
|
GtkAdjustment *adjustment;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _GtkDialClass
|
|
|
|
|
{
|
|
|
|
|
GtkWidgetClass parent_class;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GtkWidget* gtk_dial_new (GtkAdjustment *adjustment);
|
|
|
|
|
guint gtk_dial_get_type (void);
|
|
|
|
|
GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial);
|
|
|
|
|
void gtk_dial_set_update_policy (GtkDial *dial,
|
|
|
|
|
GtkUpdateType policy);
|
|
|
|
|
|
|
|
|
|
void gtk_dial_set_adjustment (GtkDial *dial,
|
|
|
|
|
GtkAdjustment *adjustment);
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* __GTK_DIAL_H__ */
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect2> gtkdial.c
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo gtkdial gtkdial.c */
|
|
|
|
|
|
2008-07-01 22:57:50 +00:00
|
|
|
|
/* GTK - The GIMP Toolkit
|
2000-04-23 09:17:36 +00:00
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
|
*/
|
|
|
|
|
#include <math.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <gtk/gtkmain.h>
|
|
|
|
|
#include <gtk/gtksignal.h>
|
|
|
|
|
|
|
|
|
|
#include "gtkdial.h"
|
|
|
|
|
|
|
|
|
|
#define SCROLL_DELAY_LENGTH 300
|
|
|
|
|
#define DIAL_DEFAULT_SIZE 100
|
|
|
|
|
|
|
|
|
|
/* declaraciones de funciones */
|
|
|
|
|
|
|
|
|
|
static void gtk_dial_class_init (GtkDialClass *klass);
|
|
|
|
|
static void gtk_dial_init (GtkDial *dial);
|
|
|
|
|
static void gtk_dial_destroy (GtkObject *object);
|
|
|
|
|
static void gtk_dial_realize (GtkWidget *widget);
|
|
|
|
|
static void gtk_dial_size_request (GtkWidget *widget,
|
|
|
|
|
GtkRequisition *requisition);
|
|
|
|
|
static void gtk_dial_size_allocate (GtkWidget *widget,
|
|
|
|
|
GtkAllocation *allocation);
|
|
|
|
|
static gint gtk_dial_expose (GtkWidget *widget,
|
|
|
|
|
GdkEventExpose *event);
|
|
|
|
|
static gint gtk_dial_button_press (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event);
|
|
|
|
|
static gint gtk_dial_button_release (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event);
|
|
|
|
|
static gint gtk_dial_motion_notify (GtkWidget *widget,
|
|
|
|
|
GdkEventMotion *event);
|
|
|
|
|
static gint gtk_dial_timer (GtkDial *dial);
|
|
|
|
|
|
|
|
|
|
static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y);
|
|
|
|
|
static void gtk_dial_update (GtkDial *dial);
|
|
|
|
|
static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
|
|
|
|
|
gpointer data);
|
|
|
|
|
static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
|
|
|
|
|
gpointer data);
|
|
|
|
|
|
|
|
|
|
/* datos locales */
|
|
|
|
|
|
|
|
|
|
static GtkWidgetClass *parent_class = NULL;
|
|
|
|
|
|
|
|
|
|
guint
|
|
|
|
|
gtk_dial_get_type ()
|
|
|
|
|
{
|
|
|
|
|
static guint dial_type = 0;
|
|
|
|
|
|
|
|
|
|
if (!dial_type)
|
|
|
|
|
{
|
|
|
|
|
GtkTypeInfo dial_info =
|
|
|
|
|
{
|
|
|
|
|
"GtkDial",
|
|
|
|
|
sizeof (GtkDial),
|
|
|
|
|
sizeof (GtkDialClass),
|
|
|
|
|
(GtkClassInitFunc) gtk_dial_class_init,
|
|
|
|
|
(GtkObjectInitFunc) gtk_dial_init,
|
|
|
|
|
(GtkArgSetFunc) NULL,
|
|
|
|
|
(GtkArgGetFunc) NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dial_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_class_init (GtkDialClass *class)
|
|
|
|
|
{
|
|
|
|
|
GtkObjectClass *object_class;
|
|
|
|
|
GtkWidgetClass *widget_class;
|
|
|
|
|
|
|
|
|
|
object_class = (GtkObjectClass*) class;
|
|
|
|
|
widget_class = (GtkWidgetClass*) class;
|
|
|
|
|
|
|
|
|
|
parent_class = gtk_type_class (gtk_widget_get_type ());
|
|
|
|
|
|
|
|
|
|
object_class->destroy = gtk_dial_destroy;
|
|
|
|
|
|
|
|
|
|
widget_class->realize = gtk_dial_realize;
|
|
|
|
|
widget_class->expose_event = gtk_dial_expose;
|
|
|
|
|
widget_class->size_request = gtk_dial_size_request;
|
|
|
|
|
widget_class->size_allocate = gtk_dial_size_allocate;
|
|
|
|
|
widget_class->button_press_event = gtk_dial_button_press;
|
|
|
|
|
widget_class->button_release_event = gtk_dial_button_release;
|
|
|
|
|
widget_class->motion_notify_event = gtk_dial_motion_notify;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_init (GtkDial *dial)
|
|
|
|
|
{
|
|
|
|
|
dial->button = 0;
|
|
|
|
|
dial->policy = GTK_UPDATE_CONTINUOUS;
|
|
|
|
|
dial->timer = 0;
|
|
|
|
|
dial->radius = 0;
|
|
|
|
|
dial->pointer_width = 0;
|
|
|
|
|
dial->angle = 0.0;
|
|
|
|
|
dial->old_value = 0.0;
|
|
|
|
|
dial->old_lower = 0.0;
|
|
|
|
|
dial->old_upper = 0.0;
|
|
|
|
|
dial->adjustment = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GtkWidget*
|
|
|
|
|
gtk_dial_new (GtkAdjustment *adjustment)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
dial = gtk_type_new (gtk_dial_get_type ());
|
|
|
|
|
|
|
|
|
|
if (!adjustment)
|
|
|
|
|
adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
|
|
|
|
|
|
|
|
|
gtk_dial_set_adjustment (dial, adjustment);
|
|
|
|
|
|
|
|
|
|
return GTK_WIDGET (dial);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_destroy (GtkObject *object)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (object != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (object));
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (object);
|
|
|
|
|
|
|
|
|
|
if (dial->adjustment)
|
|
|
|
|
gtk_object_unref (GTK_OBJECT (dial->adjustment));
|
|
|
|
|
|
|
|
|
|
if (GTK_OBJECT_CLASS (parent_class)->destroy)
|
|
|
|
|
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GtkAdjustment*
|
|
|
|
|
gtk_dial_get_adjustment (GtkDial *dial)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (dial != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
|
|
|
|
|
|
|
|
|
|
return dial->adjustment;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gtk_dial_set_update_policy (GtkDial *dial,
|
|
|
|
|
GtkUpdateType policy)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (dial != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (dial));
|
|
|
|
|
|
|
|
|
|
dial->policy = policy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
gtk_dial_set_adjustment (GtkDial *dial,
|
|
|
|
|
GtkAdjustment *adjustment)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (dial != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (dial));
|
|
|
|
|
|
|
|
|
|
if (dial->adjustment)
|
|
|
|
|
{
|
|
|
|
|
gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
|
|
|
|
|
gtk_object_unref (GTK_OBJECT (dial->adjustment));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dial->adjustment = adjustment;
|
|
|
|
|
gtk_object_ref (GTK_OBJECT (dial->adjustment));
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
|
|
|
|
|
(GtkSignalFunc) gtk_dial_adjustment_changed,
|
|
|
|
|
(gpointer) dial);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
|
|
|
|
|
(GtkSignalFunc) gtk_dial_adjustment_value_changed,
|
|
|
|
|
(gpointer) dial);
|
|
|
|
|
|
|
|
|
|
dial->old_value = adjustment->value;
|
|
|
|
|
dial->old_lower = adjustment->lower;
|
|
|
|
|
dial->old_upper = adjustment->upper;
|
|
|
|
|
|
|
|
|
|
gtk_dial_update (dial);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_realize (GtkWidget *widget)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
GdkWindowAttr attributes;
|
|
|
|
|
gint attributes_mask;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (widget));
|
|
|
|
|
|
|
|
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
attributes.x = widget->allocation.x;
|
|
|
|
|
attributes.y = widget->allocation.y;
|
|
|
|
|
attributes.width = widget->allocation.width;
|
|
|
|
|
attributes.height = widget->allocation.height;
|
|
|
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
|
|
|
attributes.event_mask = gtk_widget_get_events (widget) |
|
|
|
|
|
GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
|
|
|
|
|
GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
|
|
|
|
|
GDK_POINTER_MOTION_HINT_MASK;
|
|
|
|
|
attributes.visual = gtk_widget_get_visual (widget);
|
|
|
|
|
attributes.colormap = gtk_widget_get_colormap (widget);
|
|
|
|
|
|
|
|
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
|
|
|
|
|
widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
|
|
|
|
|
|
|
|
|
|
widget->style = gtk_style_attach (widget->style, widget->window);
|
|
|
|
|
|
|
|
|
|
gdk_window_set_user_data (widget->window, widget);
|
|
|
|
|
|
|
|
|
|
gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_size_request (GtkWidget *widget,
|
|
|
|
|
GtkRequisition *requisition)
|
|
|
|
|
{
|
|
|
|
|
requisition->width = DIAL_DEFAULT_SIZE;
|
|
|
|
|
requisition->height = DIAL_DEFAULT_SIZE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_size_allocate (GtkWidget *widget,
|
|
|
|
|
GtkAllocation *allocation)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (widget));
|
|
|
|
|
g_return_if_fail (allocation != NULL);
|
|
|
|
|
|
|
|
|
|
widget->allocation = *allocation;
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
if (GTK_WIDGET_REALIZED (widget))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
gdk_window_move_resize (widget->window,
|
|
|
|
|
allocation->x, allocation->y,
|
|
|
|
|
allocation->width, allocation->height);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
dial->radius = MIN(allocation->width,allocation->height) * 0.45;
|
|
|
|
|
dial->pointer_width = dial->radius / 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_expose (GtkWidget *widget,
|
|
|
|
|
GdkEventExpose *event)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
GdkPoint points[3];
|
|
|
|
|
gdouble s,c;
|
|
|
|
|
gdouble theta;
|
|
|
|
|
gint xc, yc;
|
|
|
|
|
gint tick_length;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
|
|
|
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
if (event->count > 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
gdk_window_clear_area (widget->window,
|
|
|
|
|
0, 0,
|
|
|
|
|
widget->allocation.width,
|
|
|
|
|
widget->allocation.height);
|
|
|
|
|
|
|
|
|
|
xc = widget->allocation.width/2;
|
|
|
|
|
yc = widget->allocation.height/2;
|
|
|
|
|
|
|
|
|
|
/* Dibuja las rayitas */
|
|
|
|
|
|
|
|
|
|
for (i=0; i<25; i++)
|
|
|
|
|
{
|
|
|
|
|
theta = (i*M_PI/18. - M_PI/6.);
|
|
|
|
|
s = sin(theta);
|
|
|
|
|
c = cos(theta);
|
|
|
|
|
|
|
|
|
|
tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
|
|
|
|
|
|
|
|
|
|
gdk_draw_line (widget->window,
|
|
|
|
|
widget->style->fg_gc[widget->state],
|
|
|
|
|
xc + c*(dial->radius - tick_length),
|
|
|
|
|
yc - s*(dial->radius - tick_length),
|
|
|
|
|
xc + c*dial->radius,
|
|
|
|
|
yc - s*dial->radius);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dibuja el puntero */
|
|
|
|
|
|
|
|
|
|
s = sin(dial->angle);
|
|
|
|
|
c = cos(dial->angle);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
points[0].x = xc + s*dial->pointer_width/2;
|
|
|
|
|
points[0].y = yc + c*dial->pointer_width/2;
|
|
|
|
|
points[1].x = xc + c*dial->radius;
|
|
|
|
|
points[1].y = yc - s*dial->radius;
|
|
|
|
|
points[2].x = xc - s*dial->pointer_width/2;
|
|
|
|
|
points[2].y = yc - c*dial->pointer_width/2;
|
|
|
|
|
|
|
|
|
|
gtk_draw_polygon (widget->style,
|
|
|
|
|
widget->window,
|
|
|
|
|
GTK_STATE_NORMAL,
|
|
|
|
|
GTK_SHADOW_OUT,
|
|
|
|
|
points, 3,
|
|
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_button_press (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
gint dx, dy;
|
|
|
|
|
double s, c;
|
|
|
|
|
double d_parallel;
|
|
|
|
|
double d_perpendicular;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
|
|
|
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Determinar si la pulsaci<63>n del bot<6F>n fue dentro de la regi<67>n del
|
|
|
|
|
puntero - esto lo hacemos calculando la distancia x e y del punto
|
|
|
|
|
donde se puls<6C> el bot<6F>n rat<61>n de la l<>nea que se ha pasado mediante el
|
|
|
|
|
puntero */
|
|
|
|
|
|
|
|
|
|
dx = event->x - widget->allocation.width / 2;
|
|
|
|
|
dy = widget->allocation.height / 2 - event->y;
|
|
|
|
|
|
|
|
|
|
s = sin(dial->angle);
|
|
|
|
|
c = cos(dial->angle);
|
|
|
|
|
|
|
|
|
|
d_parallel = s*dy + c*dx;
|
|
|
|
|
d_perpendicular = fabs(s*dx - c*dy);
|
|
|
|
|
|
|
|
|
|
if (!dial->button &&
|
|
|
|
|
(d_perpendicular < dial->pointer_width/2) &&
|
|
|
|
|
(d_parallel > - dial->pointer_width))
|
|
|
|
|
{
|
|
|
|
|
gtk_grab_add (widget);
|
|
|
|
|
|
|
|
|
|
dial->button = event->button;
|
|
|
|
|
|
|
|
|
|
gtk_dial_update_mouse (dial, event->x, event->y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_button_release (GtkWidget *widget,
|
|
|
|
|
GdkEventButton *event)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
|
|
|
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
if (dial->button == event->button)
|
|
|
|
|
{
|
|
|
|
|
gtk_grab_remove (widget);
|
|
|
|
|
|
|
|
|
|
dial->button = 0;
|
|
|
|
|
|
|
|
|
|
if (dial->policy == GTK_UPDATE_DELAYED)
|
|
|
|
|
gtk_timeout_remove (dial->timer);
|
|
|
|
|
|
|
|
|
|
if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
|
|
|
|
|
(dial->old_value != dial->adjustment->value))
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_motion_notify (GtkWidget *widget,
|
|
|
|
|
GdkEventMotion *event)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
GdkModifierType mods;
|
|
|
|
|
gint x, y, mask;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
|
|
|
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (widget);
|
|
|
|
|
|
|
|
|
|
if (dial->button != 0)
|
|
|
|
|
{
|
|
|
|
|
x = event->x;
|
|
|
|
|
y = event->y;
|
|
|
|
|
|
|
|
|
|
if (event->is_hint || (event->window != widget->window))
|
|
|
|
|
gdk_window_get_pointer (widget->window, &x, &y, &mods);
|
|
|
|
|
|
|
|
|
|
switch (dial->button)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
mask = GDK_BUTTON1_MASK;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
mask = GDK_BUTTON2_MASK;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
mask = GDK_BUTTON3_MASK;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
mask = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mods & mask)
|
|
|
|
|
gtk_dial_update_mouse (dial, x,y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
gtk_dial_timer (GtkDial *dial)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (dial != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
|
|
|
|
|
|
|
|
|
|
if (dial->policy == GTK_UPDATE_DELAYED)
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
|
|
|
|
|
{
|
|
|
|
|
gint xc, yc;
|
|
|
|
|
gfloat old_value;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (dial != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (dial));
|
|
|
|
|
|
|
|
|
|
xc = GTK_WIDGET(dial)->allocation.width / 2;
|
|
|
|
|
yc = GTK_WIDGET(dial)->allocation.height / 2;
|
|
|
|
|
|
|
|
|
|
old_value = dial->adjustment->value;
|
|
|
|
|
dial->angle = atan2(yc-y, x-xc);
|
|
|
|
|
|
|
|
|
|
if (dial->angle < -M_PI/2.)
|
|
|
|
|
dial->angle += 2*M_PI;
|
|
|
|
|
|
|
|
|
|
if (dial->angle < -M_PI/6)
|
|
|
|
|
dial->angle = -M_PI/6;
|
|
|
|
|
|
|
|
|
|
if (dial->angle > 7.*M_PI/6.)
|
|
|
|
|
dial->angle = 7.*M_PI/6.;
|
|
|
|
|
|
|
|
|
|
dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
|
|
|
|
|
(dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
|
|
|
|
|
|
|
|
|
|
if (dial->adjustment->value != old_value)
|
|
|
|
|
{
|
|
|
|
|
if (dial->policy == GTK_UPDATE_CONTINUOUS)
|
|
|
|
|
{
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gtk_widget_draw (GTK_WIDGET(dial), NULL);
|
|
|
|
|
|
|
|
|
|
if (dial->policy == GTK_UPDATE_DELAYED)
|
|
|
|
|
{
|
|
|
|
|
if (dial->timer)
|
|
|
|
|
gtk_timeout_remove (dial->timer);
|
|
|
|
|
|
|
|
|
|
dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
|
|
|
|
|
(GtkFunction) gtk_dial_timer,
|
|
|
|
|
(gpointer) dial);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_update (GtkDial *dial)
|
|
|
|
|
{
|
|
|
|
|
gfloat new_value;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (dial != NULL);
|
|
|
|
|
g_return_if_fail (GTK_IS_DIAL (dial));
|
|
|
|
|
|
|
|
|
|
new_value = dial->adjustment->value;
|
|
|
|
|
|
|
|
|
|
if (new_value < dial->adjustment->lower)
|
|
|
|
|
new_value = dial->adjustment->lower;
|
|
|
|
|
|
|
|
|
|
if (new_value > dial->adjustment->upper)
|
|
|
|
|
new_value = dial->adjustment->upper;
|
|
|
|
|
|
|
|
|
|
if (new_value != dial->adjustment->value)
|
|
|
|
|
{
|
|
|
|
|
dial->adjustment->value = new_value;
|
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
|
|
|
|
|
(dial->adjustment->upper - dial->adjustment->lower);
|
|
|
|
|
|
|
|
|
|
gtk_widget_draw (GTK_WIDGET(dial), NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
|
|
|
|
|
gpointer data)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (adjustment != NULL);
|
|
|
|
|
g_return_if_fail (data != NULL);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (data);
|
|
|
|
|
|
|
|
|
|
if ((dial->old_value != adjustment->value) ||
|
|
|
|
|
(dial->old_lower != adjustment->lower) ||
|
|
|
|
|
(dial->old_upper != adjustment->upper))
|
|
|
|
|
{
|
|
|
|
|
gtk_dial_update (dial);
|
|
|
|
|
|
|
|
|
|
dial->old_value = adjustment->value;
|
|
|
|
|
dial->old_lower = adjustment->lower;
|
|
|
|
|
dial->old_upper = adjustment->upper;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
|
|
|
|
|
gpointer data)
|
|
|
|
|
{
|
|
|
|
|
GtkDial *dial;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (adjustment != NULL);
|
|
|
|
|
g_return_if_fail (data != NULL);
|
|
|
|
|
|
|
|
|
|
dial = GTK_DIAL (data);
|
|
|
|
|
|
|
|
|
|
if (dial->old_value != adjustment->value)
|
|
|
|
|
{
|
|
|
|
|
gtk_dial_update (dial);
|
|
|
|
|
|
|
|
|
|
dial->old_value = adjustment->value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Scribble
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo scribble-simple scribble-simple.c */
|
|
|
|
|
|
2008-07-01 22:57:50 +00:00
|
|
|
|
/* GTK - The GIMP Toolkit
|
2000-04-23 09:17:36 +00:00
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
|
|
|
*
|
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Library General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
|
|
/* Creamos un backing pixmap para la zona donde dibujamos */
|
|
|
|
|
static GdkPixmap *pixmap = NULL;
|
|
|
|
|
|
|
|
|
|
/* Creamos un nuevo backing pixmap del tama<6D>o apropiado */
|
|
|
|
|
static gint
|
|
|
|
|
configure_event (GtkWidget *widget, GdkEventConfigure *event)
|
|
|
|
|
{
|
|
|
|
|
if (pixmap)
|
|
|
|
|
gdk_pixmap_unref(pixmap);
|
|
|
|
|
|
|
|
|
|
pixmap = gdk_pixmap_new(widget->window,
|
|
|
|
|
widget->allocation.width,
|
|
|
|
|
widget->allocation.height,
|
|
|
|
|
-1);
|
|
|
|
|
gdk_draw_rectangle (pixmap,
|
|
|
|
|
widget->style->white_gc,
|
|
|
|
|
TRUE,
|
|
|
|
|
0, 0,
|
|
|
|
|
widget->allocation.width,
|
|
|
|
|
widget->allocation.height);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Redibujamos la pantalla con el backing pixmap */
|
|
|
|
|
static gint
|
|
|
|
|
expose_event (GtkWidget *widget, GdkEventExpose *event)
|
|
|
|
|
{
|
|
|
|
|
gdk_draw_pixmap(widget->window,
|
|
|
|
|
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
|
|
|
|
|
pixmap,
|
|
|
|
|
event->area.x, event->area.y,
|
|
|
|
|
event->area.x, event->area.y,
|
|
|
|
|
event->area.width, event->area.height);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dibujamos un rect<63>ngulo en la pantalla */
|
|
|
|
|
static void
|
|
|
|
|
draw_brush (GtkWidget *widget, gdouble x, gdouble y)
|
|
|
|
|
{
|
|
|
|
|
GdkRectangle update_rect;
|
|
|
|
|
|
|
|
|
|
update_rect.x = x - 5;
|
|
|
|
|
update_rect.y = y - 5;
|
|
|
|
|
update_rect.width = 10;
|
|
|
|
|
update_rect.height = 10;
|
|
|
|
|
gdk_draw_rectangle (pixmap,
|
|
|
|
|
widget->style->black_gc,
|
|
|
|
|
TRUE,
|
|
|
|
|
update_rect.x, update_rect.y,
|
|
|
|
|
update_rect.width, update_rect.height);
|
|
|
|
|
gtk_widget_draw (widget, &update_rect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
button_press_event (GtkWidget *widget, GdkEventButton *event)
|
|
|
|
|
{
|
|
|
|
|
if (event->button == 1 && pixmap != NULL)
|
|
|
|
|
draw_brush (widget, event->x, event->y);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gint
|
|
|
|
|
motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
|
|
|
|
|
{
|
|
|
|
|
int x, y;
|
|
|
|
|
GdkModifierType state;
|
|
|
|
|
|
|
|
|
|
if (event->is_hint)
|
|
|
|
|
gdk_window_get_pointer (event->window, &x, &y, &state);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
x = event->x;
|
|
|
|
|
y = event->y;
|
|
|
|
|
state = event->state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state & GDK_BUTTON1_MASK && pixmap != NULL)
|
|
|
|
|
draw_brush (widget, x, y);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
quit ()
|
|
|
|
|
{
|
|
|
|
|
gtk_exit (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *drawing_area;
|
|
|
|
|
GtkWidget *vbox;
|
|
|
|
|
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
|
|
|
|
|
gtk_init (&argc, &argv);
|
|
|
|
|
|
|
|
|
|
ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_widget_set_name (ventana, "Test Input");
|
|
|
|
|
|
|
|
|
|
vbox = gtk_vbox_new (FALSE, 0);
|
|
|
|
|
gtk_container_add (GTK_CONTAINER (ventana), vbox);
|
|
|
|
|
gtk_widget_show (vbox);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (ventana), "destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC (quit), NULL);
|
|
|
|
|
|
|
|
|
|
/* Crear la zona de dibujado */
|
|
|
|
|
|
|
|
|
|
drawing_area = gtk_drawing_area_new ();
|
|
|
|
|
gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (drawing_area);
|
|
|
|
|
|
|
|
|
|
/* Las se<73>ales utilizadas para manejar el backing pixmap */
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
|
|
|
|
|
(GtkSignalFunc) expose_event, NULL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
|
|
|
|
|
(GtkSignalFunc) configure_event, NULL);
|
|
|
|
|
|
|
|
|
|
/* Se<53>ales evento */
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
|
|
|
|
|
(GtkSignalFunc) motion_notify_event, NULL);
|
|
|
|
|
gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
|
|
|
|
|
(GtkSignalFunc) button_press_event, NULL);
|
|
|
|
|
|
|
|
|
|
gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
|
|
|
|
|
| GDK_LEAVE_NOTIFY_MASK
|
|
|
|
|
| GDK_BUTTON_PRESS_MASK
|
|
|
|
|
| GDK_POINTER_MOTION_MASK
|
|
|
|
|
| GDK_POINTER_MOTION_HINT_MASK);
|
|
|
|
|
|
|
|
|
|
/* .. Y un bot<6F>n para salir */
|
|
|
|
|
boton = gtk_button_new_with_label ("Quit");
|
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), boton, FALSE, FALSE, 0);
|
|
|
|
|
|
|
|
|
|
gtk_signal_connect_object (GTK_OBJECT (boton), "clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
|
|
|
|
GTK_OBJECT (ventana));
|
|
|
|
|
gtk_widget_show (boton);
|
|
|
|
|
|
|
|
|
|
gtk_widget_show (ventana);
|
|
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<sect> El <em>widget</em> lista
|
|
|
|
|
<!-- ***************************************************************** -->
|
|
|
|
|
<p>
|
|
|
|
|
ATENCI<EFBFBD>N: El <em>widget</em> GtkList ha sido reemplazado por el
|
|
|
|
|
<em>widget</em> GtkCList.
|
|
|
|
|
|
|
|
|
|
El <em>widget</em> GtkList est<73> dise<73>ado para actuar como un
|
|
|
|
|
contenedor vertical de <em>widgets</em> que deben ser del tipo
|
|
|
|
|
GtkListItem.
|
|
|
|
|
|
|
|
|
|
Un <em>widget</em> GtkList tiene su propia ventana para recibir
|
|
|
|
|
eventos y su propio color de fondo, que normalmente es blanco.
|
|
|
|
|
Como es un objeto derivado directamente de GtkContainer puede tratarse
|
|
|
|
|
utilizando la macro GTK_CONTAINER(List), ver el <em>widget</em>
|
|
|
|
|
GtkContainer para obtener m<>s informaci<63>n.
|
|
|
|
|
|
|
|
|
|
Deber<EFBFBD>a familiarizarse con la utilizaci<63>n de un GList y con sus
|
|
|
|
|
funciones relacionadas <tt/g_list_*()/ para ser capaz de explotar el
|
|
|
|
|
<em>widget</em> GtkList hasta su l<>mite.
|
|
|
|
|
|
|
|
|
|
S<EFBFBD>lo hay un campo dentro de la definici<63>n de la estructura del
|
|
|
|
|
<em>widget</em> GtkList que nos es de inter<65>s, y es:
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
struct _GtkList
|
|
|
|
|
{
|
|
|
|
|
...
|
|
|
|
|
GList *selection;
|
|
|
|
|
guint selection_mode;
|
|
|
|
|
...
|
|
|
|
|
};
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
El campo <tt/selection/ de un GtkList apunta a una lista enlazada de
|
|
|
|
|
todos los elementos que est<73>n actualmente seleccionados, o NULL si la
|
|
|
|
|
selecci<EFBFBD>n est<73> vacia. Por lo tanto para saber quien es la actual
|
|
|
|
|
selecci<EFBFBD>n debemos leer el campo <tt/GTK_LIST()->selection/, pero no
|
|
|
|
|
modificarlo ya que los campos de los que est<73> constituido GtkList
|
|
|
|
|
est<EFBFBD>n controlados por las funciones gtk_list_*().
|
|
|
|
|
|
|
|
|
|
El <tt/selection_mode/ de la GtkList determina las posibilidades de
|
|
|
|
|
selecci<EFBFBD>n de una GtkList y por tanto los contenidos del campo
|
|
|
|
|
<tt/GTK_LIST()->selection/. El <tt/selection_mode/ puede tener uno de
|
|
|
|
|
los valores siguientes:
|
|
|
|
|
|
|
|
|
|
<itemize>
|
|
|
|
|
<item> GTK_SELECTION_SINGLE - La selecci<63>n es o NULL o contiene un
|
|
|
|
|
puntero a un GList con un solo elemento seleccionado.
|
|
|
|
|
|
|
|
|
|
<item> GTK_SELECTION_BROWSE - La selecci<63>n es NULL si la lista no
|
|
|
|
|
contiene <em>widgets</em> o si los que contiene no son sensibles, en
|
|
|
|
|
cualquier otro caso contiene un puntero GList a una estructura GList,
|
|
|
|
|
y contendr<64> por tanto un solo elemento.
|
|
|
|
|
|
|
|
|
|
<item> GTK_SELECTION_MULTIPLE - La selecci<63>n es NULL si no hay
|
|
|
|
|
elementos seleccionados o un puntero GList hacia el primer elemento
|
|
|
|
|
seleccionado. ("That in turn") apunta a una estructura GList para
|
|
|
|
|
el segundo elemento seleccionado y as<61>.
|
|
|
|
|
|
|
|
|
|
<item> GTK_SELECTION_EXTENDED - La selecci<63>n siempre es NULL.
|
|
|
|
|
</itemize>
|
|
|
|
|
|
|
|
|
|
El valor por defecto es GTK_SELECTION_MULTIPLE.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Se<53>ales
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void selection_changed( GtkList *list );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se invocar<61> esta se<73>al cuando cambie el campo <tt/selection/ de un
|
|
|
|
|
GtkList. Es decir, cuando un hijo de una GtkList se selecciona o
|
|
|
|
|
deselecciona.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void select_child( GtkList *list,
|
|
|
|
|
GtkWidget *hijo);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se invoca esta se<73>al cuando un hijo de la GtkList est<73> siendo
|
|
|
|
|
seleccionado. Esto ocurre principalmente en llamadas a
|
|
|
|
|
<tt/gtk_list_select_item()/, a <tt/gtk_list_select_child()/, cuando se
|
|
|
|
|
pulsa alg<6C>n bot<6F>n y a veces se lanza indirectamente cuando se a<>ade o
|
|
|
|
|
se elimina un hijo del GtkList.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void unselect_child( GtkList *list,
|
|
|
|
|
GtkWidget *hijo );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Se invoca esta se<73>al cuando un hijo del GtkList est<73> siendo
|
|
|
|
|
deseleccionado. Esto ocurre principalmente cuando ocurre una llamada a
|
|
|
|
|
<tt/gtk_list_unselect_item()/, <tt/gtk_list_unselect_item()/,
|
|
|
|
|
pulsaciones de bot<6F>n y a veces se lanza indirectamente cuando se a<>ade
|
|
|
|
|
o se elimina alg<6C>n hijo de la GtkList.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Funciones
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_list_get_type( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Devuelve el identificador de tipo `GtkList'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_list_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Crea un nuevo objeto GtkList. Se devuelve el nuevo <em/widget/ como un
|
|
|
|
|
puntero a un objeto GtkWidget. Se devuelve NULL en caso de producirse
|
|
|
|
|
alg<EFBFBD>n fallo.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_insert_items( GtkList *list,
|
|
|
|
|
GList *items,
|
|
|
|
|
gint posicion );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Introduce elementos en la lista, comenzando en la posici<63>n
|
|
|
|
|
<tt/posicion/. <tt/items/ es una lista doblemente enlazada donde cada
|
|
|
|
|
puntero de datos de cada nodo se supone que apunta a una nueva
|
|
|
|
|
GtkListItem (recien creada). Los nodos GList de <tt/items/ son
|
|
|
|
|
controlados por la lista.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_append_items( GtkList *list,
|
|
|
|
|
GList *items);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Introduce elementos tal y como lo hace <tt/gtk_list_insert_items()/,
|
|
|
|
|
pero los mete en el final de la lista. Los nodos GList de <tt/items/
|
|
|
|
|
son controlados por la lista.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_prepend_items( GtkList *list,
|
|
|
|
|
GList *items);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Introduce elementos tal y como lo hace <tt/gtk_list_insert_items()/,
|
|
|
|
|
pero los mete al principio de la lista. Los nodos GList de <tt/items/
|
|
|
|
|
son controlados por la lista.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_remove_items( GtkList *list,
|
|
|
|
|
GList *items);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Elimina elementos de la lista. <tt/items/ es una lista doblemente
|
|
|
|
|
enlazada donde cada puntero de datos de cada nodo se supone que apunta
|
|
|
|
|
a un hijo directo de la lista. El ejecutar o no
|
|
|
|
|
<tt/g_list_free(items)/ cuando la funci<63>n termine de ejecutarse es
|
|
|
|
|
responsabilidad del que llama a la misma. Est<73> bajo su responsabilidad
|
|
|
|
|
la destrucci<63>n de los elementos de la lista.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_clear_items( GtkList *list,
|
|
|
|
|
gint start,
|
|
|
|
|
gint end );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Elimina y destruye los elementos de la lista. Esta operaci<63>n afectar<61>
|
|
|
|
|
a todos los <em/widgets/ que se encuentren en la lista y en el rango
|
|
|
|
|
especificado por <tt/start/ y <tt/end/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_select_item( GtkList *list,
|
|
|
|
|
gint item );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Invoca la se<73>al <tt/select_child/ para el elemento especificado
|
|
|
|
|
mediante su posici<63>n actual en la lista.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_unselect_item( GtkList *list,
|
|
|
|
|
gint item);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Invoca la se<73>al <tt/unselect_child/ para un elemento especificado
|
|
|
|
|
mediante su posici<63>n actual en la lista.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_select_child( GtkList *list,
|
|
|
|
|
GtkWidget *hijo);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Invoca la se<73>al <tt/select_child/ para el hijo especificado.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_unselect_child( GtkList *list,
|
|
|
|
|
GtkWidget *hijo);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Invoca la se<73>al <tt/unselect_child/ para el hijo especificado.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint gtk_list_child_position( GtkList *list,
|
|
|
|
|
GtkWidget *hijo);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Devuelve la posici<63>n de <tt/hijo/ en la lista. Se devuelve <20>-1<> en
|
|
|
|
|
caso de producirse alg<6C>n error.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_set_selection_mode( GtkList *list,
|
|
|
|
|
GtkSelectionMode mode );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Pone el modo de selecci<63>n, que puede ser <tt/GTK_SELECTION_SINGLE/,
|
|
|
|
|
<tt/GTK_SELECTION_BROWSE/, <tt/GTK_SELECTION_MULTIPLE/ o
|
|
|
|
|
<tt/GTK_SELECTION_EXTENDED/.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkList *GTK_LIST( gpointer obj );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Convierte un puntero general en `GtkList *'. Para m<>s informaci<63>n *Note
|
|
|
|
|
Standard Macros::.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkListClass *GTK_LIST_CLASS( gpointer class);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Convierte un puntero general en `GtkListClass *'. Para m<>s informaci<63>n
|
|
|
|
|
*Note Standard Macros::.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint GTK_IS_LIST( gpointer obj);
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Determina si un puntero general se refiere a un objeto `GtkList'. Para
|
|
|
|
|
m<EFBFBD>s informaci<63>n, *Note Standard Macros::.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Ejemplo
|
|
|
|
|
<p>
|
|
|
|
|
A continuaci<63>n tenemos un programa ejemplo que muestra los cambios de
|
|
|
|
|
la selecci<63>n de un GtkList, y le deja <20>arrestar<61> elementos de la
|
|
|
|
|
lista en una prisi<73>n, seleccion<6F>ndolos con el bot<6F>n derecho del rat<61>n.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
/* principio del ejemplo list list.c */
|
|
|
|
|
|
|
|
|
|
/* incluye los ficheros de cabecera de gtk+
|
|
|
|
|
* incluye stdio.h, que necesitamos para la funci<63>n printf()
|
|
|
|
|
*/
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
/* <20>sta es nuestra cadena de identificaci<63>n para almacenar datos en la
|
|
|
|
|
* lista de elementos
|
|
|
|
|
*/
|
|
|
|
|
const gchar *list_item_data_key="list_item_data";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* prototipos para los manejadores de se<73>al que vamos a conectar con
|
|
|
|
|
* el widget GtkList
|
|
|
|
|
*/
|
|
|
|
|
static void sigh_print_selection (GtkWidget *gtklist,
|
|
|
|
|
gpointer func_data);
|
|
|
|
|
static void sigh_button_event (GtkWidget *gtklist,
|
|
|
|
|
GdkEventButton *event,
|
|
|
|
|
GtkWidget *frame);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* funci<63>n principal donde se establece el interface con el usuario */
|
|
|
|
|
|
|
|
|
|
gint main (int argc, gchar *argv[])
|
|
|
|
|
{
|
|
|
|
|
GtkWidget *separator;
|
|
|
|
|
GtkWidget *ventana;
|
|
|
|
|
GtkWidget *vbox;
|
|
|
|
|
GtkWidget *scrolled_window;
|
|
|
|
|
GtkWidget *frame;
|
|
|
|
|
GtkWidget *gtklist;
|
|
|
|
|
GtkWidget *boton;
|
|
|
|
|
GtkWidget *list_item;
|
|
|
|
|
GList *dlist;
|
|
|
|
|
guint i;
|
|
|
|
|
gchar buffer[64];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* inicializar gtk+ (y consecuentemente gdk) */
|
|
|
|
|
|
|
|
|
|
gtk_init(&argc, &argv);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* crear una ventana donde meter todos los widgets y conectar
|
|
|
|
|
* gtk_main_quit() con el evento "destroy" de la ventana para
|
|
|
|
|
* poder controlar los eventos de cerrado de ventana del
|
|
|
|
|
* administrador de ventanas
|
|
|
|
|
*/
|
|
|
|
|
ventana=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
|
|
|
gtk_window_set_title(GTK_WINDOW(ventana), "GtkList Example");
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(ventana),
|
|
|
|
|
"destroy",
|
|
|
|
|
GTK_SIGNAL_FUNC(gtk_main_quit),
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* dentro de la ventana necesitamos una caja para alinear los
|
|
|
|
|
* widgets verticalmente */
|
|
|
|
|
vbox=gtk_vbox_new(FALSE, 5);
|
|
|
|
|
gtk_container_border_width(GTK_CONTAINER(vbox), 5);
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(ventana), vbox);
|
|
|
|
|
gtk_widget_show(vbox);
|
|
|
|
|
|
|
|
|
|
/* <20>sta es la ventana con barras de desplazamiento donde meteremos
|
|
|
|
|
* el widget GtkList */
|
|
|
|
|
scrolled_window=gtk_scrolled_window_new(NULL, NULL);
|
|
|
|
|
gtk_widget_set_usize(scrolled_window, 250, 150);
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
|
|
|
|
|
gtk_widget_show(scrolled_window);
|
|
|
|
|
|
|
|
|
|
/* crear el widget GtkList
|
|
|
|
|
* conectar la funci<63>n manipuladora de se<73>al
|
|
|
|
|
* sigh_print_selection() a la se<73>al "selection_changed" del
|
|
|
|
|
* GtkList para imprimir los elementos seleccionados cada vez que
|
|
|
|
|
* cambie la selecci<63>n */
|
|
|
|
|
gtklist=gtk_list_new();
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(scrolled_window), gtklist);
|
|
|
|
|
gtk_widget_show(gtklist);
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(gtklist),
|
|
|
|
|
"selection_changed",
|
|
|
|
|
GTK_SIGNAL_FUNC(sigh_print_selection),
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
/* creamos una "Prisi<73>n" donde meteremos una lista de elementos ;)
|
|
|
|
|
*/
|
|
|
|
|
frame=gtk_frame_new("Prison");
|
|
|
|
|
gtk_widget_set_usize(frame, 200, 50);
|
|
|
|
|
gtk_container_border_width(GTK_CONTAINER(frame), 5);
|
|
|
|
|
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), frame);
|
|
|
|
|
gtk_widget_show(frame);
|
|
|
|
|
|
|
|
|
|
/* conectamos el manipulador de se<73>al sigh_button_event() al
|
|
|
|
|
* GtkList que manejar<61> la lista de elementos "arrestados"
|
|
|
|
|
*/
|
|
|
|
|
gtk_signal_connect(GTK_OBJECT(gtklist),
|
|
|
|
|
"button_release_event",
|
|
|
|
|
GTK_SIGNAL_FUNC(sigh_button_event),
|
|
|
|
|
frame);
|
|
|
|
|
|
|
|
|
|
/* crear un separador
|
|
|
|
|
*/
|
|
|
|
|
separator=gtk_hseparator_new();
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), separator);
|
|
|
|
|
gtk_widget_show(separator);
|
|
|
|
|
|
|
|
|
|
/* crear finalmente un bot<6F>n y conectar su se<73>al "clicked" con la
|
|
|
|
|
* destrucci<63>n de la ventana
|
|
|
|
|
*/
|
|
|
|
|
boton=gtk_button_new_with_label("Close");
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(vbox), boton);
|
|
|
|
|
gtk_widget_show(boton);
|
|
|
|
|
gtk_signal_connect_object(GTK_OBJECT(boton),
|
|
|
|
|
"clicked",
|
|
|
|
|
GTK_SIGNAL_FUNC(gtk_widget_destroy),
|
|
|
|
|
GTK_OBJECT(ventana));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ahora creamos 5 elementos de lista, teniendo cada uno su propia
|
|
|
|
|
* etiqueta y a<>adi<64>ndolos a la GtkList mediante
|
|
|
|
|
* gtk_container_add() tambi<62>n consultaremos la cadena de texto de
|
|
|
|
|
* la etiqueta y la asociaremos con la list_item_data_key para
|
|
|
|
|
* cada elemento de la lista
|
|
|
|
|
*/
|
|
|
|
|
for (i=0; i<5; i++) {
|
|
|
|
|
GtkWidget *etiqueta;
|
|
|
|
|
gchar *string;
|
|
|
|
|
|
|
|
|
|
sprintf(buffer, "ListItemContainer with Label #%d", i);
|
|
|
|
|
etiqueta=gtk_label_new(buffer);
|
|
|
|
|
list_item=gtk_list_item_new();
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(list_item), etiqueta);
|
|
|
|
|
gtk_widget_show(etiqueta);
|
|
|
|
|
gtk_container_add(GTK_CONTAINER(gtklist), list_item);
|
|
|
|
|
gtk_widget_show(list_item);
|
|
|
|
|
gtk_label_get(GTK_LABEL(etiqueta), &string);
|
|
|
|
|
gtk_object_set_data(GTK_OBJECT(list_item),
|
|
|
|
|
list_item_data_key,
|
|
|
|
|
string);
|
|
|
|
|
}
|
|
|
|
|
/* aqu<71>, estamos creando otras 5 etiquetas, esta vez utilizaremos
|
|
|
|
|
* gtk_list_item_new_with_label() para la creaci<63>n
|
|
|
|
|
* no podemos consultar la cadena de texto de la etiqueta ya que
|
|
|
|
|
* no tenemos el puntero de etiquetas y por tanto lo <20>nico que
|
|
|
|
|
* haremos ser<65> asociar el list_item_data_key de cada elemento de
|
|
|
|
|
* la lista con la misma cadena de texto. Para a<>adirlo a la lista
|
|
|
|
|
* de elementos los pondremos en lista doblemente enlazada
|
|
|
|
|
* (GList), y entonces los a<>adimos mediante una simple llamada a
|
|
|
|
|
* gtk_list_append_items()
|
|
|
|
|
* como utilizamos g_list_prepend() para poner los elementos en la
|
|
|
|
|
* lista doblemente enlazada, su orden ser<65> descendente (en vez de
|
|
|
|
|
* ascendente como cuando utilizamos g_list_append())
|
|
|
|
|
*/
|
|
|
|
|
dlist=NULL;
|
|
|
|
|
for (; i<10; i++) {
|
|
|
|
|
sprintf(buffer, "List Item with Label %d", i);
|
|
|
|
|
list_item=gtk_list_item_new_with_label(buffer);
|
|
|
|
|
dlist=g_list_prepend(dlist, list_item);
|
|
|
|
|
gtk_widget_show(list_item);
|
|
|
|
|
gtk_object_set_data(GTK_OBJECT(list_item),
|
|
|
|
|
list_item_data_key,
|
|
|
|
|
"ListItem with integrated Label");
|
|
|
|
|
}
|
|
|
|
|
gtk_list_append_items(GTK_LIST(gtklist), dlist);
|
|
|
|
|
|
|
|
|
|
/* finalmente queremos ver la ventana, <20>verdad? ;)
|
|
|
|
|
*/
|
|
|
|
|
gtk_widget_show(ventana);
|
|
|
|
|
|
|
|
|
|
/* y nos metemos en el bucle de eventos de gtk
|
|
|
|
|
*/
|
|
|
|
|
gtk_main();
|
|
|
|
|
|
|
|
|
|
/* llegaremos aqu<71> despu<70>s de que se llame a gtk_main_quit(), lo
|
|
|
|
|
* que ocurre si se destruye la ventana
|
|
|
|
|
*/
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* <20>ste es el manejador de se<73>al que se conect<63> a los eventos de
|
|
|
|
|
* pulsar/soltar de los botones de la GtkList
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
sigh_button_event (GtkWidget *gtklist,
|
|
|
|
|
GdkEventButton *event,
|
|
|
|
|
GtkWidget *frame)
|
|
|
|
|
{
|
|
|
|
|
/* s<>lo hacemos algo si el tercer bot<6F>n (el bot<6F>n derecho) se
|
|
|
|
|
* levanta
|
|
|
|
|
*/
|
|
|
|
|
if (event->type==GDK_BUTTON_RELEASE &&
|
|
|
|
|
event->button==3) {
|
|
|
|
|
GList *dlist, *free_list;
|
|
|
|
|
GtkWidget *new_prisoner;
|
|
|
|
|
|
|
|
|
|
/* sacar la lista de elementos que est<73>n actualmente
|
|
|
|
|
* seleccionados y que ser<65>n nuestro pr<70>ximos prisioneros ;)
|
|
|
|
|
*/
|
|
|
|
|
dlist=GTK_LIST(gtklist)->selection;
|
|
|
|
|
if (dlist)
|
|
|
|
|
new_prisoner=GTK_WIDGET(dlist->data);
|
|
|
|
|
else
|
|
|
|
|
new_prisoner=NULL;
|
|
|
|
|
|
|
|
|
|
/* buscar por elementos de la lista ya encarcelados, los
|
|
|
|
|
* volveremos a poner en la lista, recordar que hay que
|
|
|
|
|
* eliminar la lista doblemente enlazada que devuelve
|
|
|
|
|
* gtk_container_children()
|
|
|
|
|
*/
|
|
|
|
|
dlist=gtk_container_children(GTK_CONTAINER(frame));
|
|
|
|
|
free_list=dlist;
|
|
|
|
|
while (dlist) {
|
|
|
|
|
GtkWidget *list_item;
|
|
|
|
|
|
|
|
|
|
list_item=dlist->data;
|
|
|
|
|
|
|
|
|
|
gtk_widget_reparent(list_item, gtklist);
|
|
|
|
|
|
|
|
|
|
dlist=dlist->next;
|
|
|
|
|
}
|
|
|
|
|
g_list_free(free_list);
|
|
|
|
|
|
|
|
|
|
/* si tenemos un nuevo prisionero, lo eliminamos de la GtkList
|
|
|
|
|
* y lo ponemos en el marco "Prisi<73>n". Primero tenemos que
|
|
|
|
|
* deseleccionarlo
|
|
|
|
|
*/
|
|
|
|
|
if (new_prisoner) {
|
|
|
|
|
GList static_dlist;
|
|
|
|
|
|
|
|
|
|
static_dlist.data=new_prisoner;
|
|
|
|
|
static_dlist.next=NULL;
|
|
|
|
|
static_dlist.prev=NULL;
|
|
|
|
|
|
|
|
|
|
gtk_list_unselect_child(GTK_LIST(gtklist),
|
|
|
|
|
new_prisoner);
|
|
|
|
|
gtk_widget_reparent(new_prisoner, frame);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* <20>ste es el manipulador de se<73>al que se llama si GtkList emite la
|
|
|
|
|
* se<73>al "selection_changed"
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
sigh_print_selection (GtkWidget *gtklist,
|
|
|
|
|
gpointer func_data)
|
|
|
|
|
{
|
|
|
|
|
GList *dlist;
|
|
|
|
|
|
|
|
|
|
/* sacar la lista doblemente enlazada de los elementos
|
|
|
|
|
* seleccionados en GtkList, <20>recuerde que hay que tratarla como
|
|
|
|
|
* de solo lectura!
|
|
|
|
|
*/
|
|
|
|
|
dlist=GTK_LIST(gtklist)->selection;
|
|
|
|
|
|
|
|
|
|
/* si no hay elementos seleccionados no queda nada por hacer
|
|
|
|
|
* excepto informar al usuario
|
|
|
|
|
*/
|
|
|
|
|
if (!dlist) {
|
|
|
|
|
g_print("Selection cleared\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* Bien, conseguimos una selecci<63>n y la imprimimos
|
|
|
|
|
*/
|
|
|
|
|
g_print("The selection is a ");
|
|
|
|
|
|
|
|
|
|
/* obtenemos la lista de elementos de la lista doblemente enlazada
|
|
|
|
|
* y entonces consultamos los datos asociados con la
|
|
|
|
|
* list_item_data_key que acabamos de imprimir
|
|
|
|
|
*/
|
|
|
|
|
while (dlist) {
|
|
|
|
|
GtkObject *list_item;
|
|
|
|
|
gchar *item_data_string;
|
|
|
|
|
|
|
|
|
|
list_item=GTK_OBJECT(dlist->data);
|
|
|
|
|
item_data_string=gtk_object_get_data(list_item,
|
|
|
|
|
list_item_data_key);
|
|
|
|
|
g_print("%s ", item_data_string);
|
|
|
|
|
|
|
|
|
|
dlist=dlist->next;
|
|
|
|
|
}
|
|
|
|
|
g_print("\n");
|
|
|
|
|
}
|
|
|
|
|
/* fin del ejemplo */
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> El <em/widget/ GtkListItem
|
|
|
|
|
<p>
|
|
|
|
|
El <em/widget/ GtkListItem est<73> dise<73>ado para comportarse como un
|
|
|
|
|
contenedor que tiene un hijo, proporcionando funciones para la
|
|
|
|
|
selecci<EFBFBD>n/deselecci<63>n justo como las necesitan los hijos del
|
|
|
|
|
<em/widget/ GtkList.
|
|
|
|
|
|
|
|
|
|
Un GtkListItem tiene su propia ventana para recibir eventos y tiene su
|
|
|
|
|
propio color de fondo, que normalmente es blanco.
|
|
|
|
|
|
|
|
|
|
Como est<73> derivado directamente de un GtkItem, puede tratarse como tal
|
|
|
|
|
utilizando la macro GTK_ITEM(ListItem), ver el <em/widget/ GtkItem
|
|
|
|
|
para m<>s detalles. Normalmente un GtkListItem s<>lo tiene una etiqueta
|
|
|
|
|
para identificar, por ejemplo, el nombre de un fichero dentro de una
|
|
|
|
|
GtkList -- por lo tanto se proporciona la funci<63>n
|
|
|
|
|
<tt/gtk_list_item_new_with_label()/. Se puede conseguir el mismo
|
|
|
|
|
efecto creando un GtkLabel, poniendo su alineaci<63>n a <tt/xalign=0/ e
|
|
|
|
|
<tt/yalign=0.5/ y seguido de una adici<63>n al contenedor GtkListItem.
|
|
|
|
|
|
|
|
|
|
Nadie le obliga a meter un GtkLabel en un GtkListItem, puede meter un
|
|
|
|
|
GtkVBox o un GtkArrow, etc...
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Se<53>ales
|
|
|
|
|
<p>
|
|
|
|
|
Un GtkListItem no crea por s<> misma nuevas se<73>ales, pero hereda las
|
|
|
|
|
se<EFBFBD>ales de un GtkItem. Para m<>s informaci<63>n *Note GtkItem::.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Funciones
|
|
|
|
|
<p>
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
guint gtk_list_item_get_type( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Devuelve el identificador de tipo `GtkListItem'.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_list_item_new( void );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Crea un nuevo objeto GtkListItem. Se devuelve el nuevo <em/widget/
|
|
|
|
|
como un puntero a un objeto GtkWidget. Se devuelve NULL en caso de
|
|
|
|
|
producirse alg<6C>n error.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkWidget *gtk_list_item_new_with_label( gchar *etiqueta );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Crea un nuevo objeto GtkListItem, con una sola GtkLabel como <20>nico
|
|
|
|
|
hijo. Se devuelve el nuevo <em/widget/ como un puntero a un objeto
|
|
|
|
|
GtkWidget. Se devuelve NULL en caso de producirse alg<6C>n error.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_item_select( GtkListItem *list_item );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n es, b<>sicamente, un recubrimiento de una llamada a
|
|
|
|
|
<tt/gtk_item_select (GTK_ITEM (list_item))/, y emitir<69> la se<73>al
|
|
|
|
|
<tt/select/. Para m<>s informaci<63>n *Note GtkItem::.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
void gtk_list_item_deselect( GtkListItem *list_item );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Esta funci<63>n es, b<>sicamente, un recubrimiento de una llamada a
|
|
|
|
|
<tt/gtk_item_deselect (GTK_ITEM (list_item))/, y emitir<69> la se<73>al
|
|
|
|
|
<tt/deselect/. Para m<>s informaci<63>n *Note GtkItem::.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkListItem *GTK_LIST_ITEM( gpointer obj );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Convierte un puntero general a `GtkListItem *'. Para m<>s informaci<63>n
|
|
|
|
|
*Note Standard Macros::.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Convierte un puntero general a `GtkListItemClass *'. Para m<>s
|
|
|
|
|
informaci<EFBFBD>n *Note Standard Macros::.
|
|
|
|
|
|
|
|
|
|
<tscreen><verb>
|
|
|
|
|
gint GTK_IS_LIST_ITEM( gpointer obj );
|
|
|
|
|
</verb></tscreen>
|
|
|
|
|
|
|
|
|
|
Determina si un puntero general se refiere a un puntero
|
|
|
|
|
`GtkListItem'. Para m<>s informaci<63>n *Note Standard Macros::.
|
|
|
|
|
|
|
|
|
|
<!-- ----------------------------------------------------------------- -->
|
|
|
|
|
<sect1> Ejemplo
|
|
|
|
|
<p>
|
|
|
|
|
Para ver un ejemplo de todo esto, mire el de GtkList, que tambi<62>n
|
|
|
|
|
cubre la utilizaci<63>n un GtkListItem.
|
|
|
|
|
|
|
|
|
|
</article>
|