ProgramacionGTKenC/CapituloIII

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


Contenido

Señales

Como vimos anteriormente, es posible definir funciones arbitrarias al momento de recibir algunos eventos. Como la programacion grafica requiere de interaccion con el usuario, GTK+ recibe y emite señales al momento de comunicarse con la capa grafica (X11). Por ejemplo, al hacer click a un boton, mover una ventana, entre otros.

En el caso del boton, al momento de hacer click en el se genera la señal "clicked", que no esta definida a ninguna funcion.

Revisando el codigo de gtkbutton.h, vemos que la clase posee una señal, clicked

struct _GtkButtonClass
{
	...
	void (* clicked) (GtkButton * button);
	...
}

En la documentacion de GTK+, los argumentos de la funcion de callback son

"clicked" void user_function (GtkButton * button, gpointer user_data);

En el caso generico de cualquier widget, una señal se enlaza a una funcion arbitraria de la siguiente manera

g_signal_connect((GObject *) widget, 
		const gchar signal, 
		(GCallback *) function, 
		gpointer data);


donde

  • widget : es el widget que origina la señal
  • const gchar signal : es el nombre de la señal a recibir
  • function : la funcion que se va a conectar a la señal
  • data : puntero arbitrario de envio de datos de la funcion.

Mientras que la declaracion de la funcion depende de la señal. En el caso de la señal "clicked" en el widget GtkButton es:

"clicked" void user_function (GtkButton * button, gpointer user_data);


Veamos un ejemplo

#include <gtk/gtk.h>

void funcion (GtkButton * button, gpointer data)
{
	g_print("Apretamos el boton y aparece este texto\n");
}

int main (int argc, char * argv[])
{
	GtkWidget * ventana;
	GtkWidget * boton;
	GtkWidget * etiqueta;

	gtk_init(&argc, &argv);

	ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	boton = gtk_button_new();
	etiqueta = gtk_label_new("Etiqueta 1");
	
	gtk_window_set_title((GtkWindow *) ventana, "Ventana con boton");

	gtk_container_add ((GtkContainer *) ventana, boton);
	gtk_container_add ((GtkContainer *) boton, etiqueta);

	g_signal_connect ((GObject *) boton, "clicked", (GCallback) funcion, NULL);

	gtk_widget_show(ventana);
	gtk_widget_show(boton);
	gtk_widget_show(etiqueta);

	gtk_main();

}

Funciones de recepcion de señales

Se fijaron que cuando compilaron los ejemplos anteriores y cerraron la ventana, la aplicacion "siguio corriendo"?. Eso es debido a que al momento de cerrar la ventana principal de una aplicacion, se emite una señal "delete-event" que no es recibida por ninguna funcion.

Veamos los siguientes ejemplos. El primero, es similar al anterior. Esta vez, se imprime "Apretamos el boton..." y la aplicacion se cerrara.

#include <gtk/gtk.h>

void funcion (GtkButton * button, gpointer data)
{
	g_print("Apretamos el boton y aparece este texto\n");
	gtk_main_quit();
}

int main (int argc, char * argv[])
{
	GtkWidget * ventana;
	GtkWidget * boton;
	GtkWidget * etiqueta;

	gtk_init(&argc, &argv);

	ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	boton = gtk_button_new();
	etiqueta = gtk_label_new("Etiqueta 1");
	
	gtk_window_set_title((GtkWindow *) ventana, "Ventana con boton");

	gtk_container_add ((GtkContainer *) ventana, boton);
	gtk_container_add ((GtkContainer *) boton, etiqueta);

	g_signal_connect ((GObject *) boton, "clicked", (GCallback) funcion, NULL);

	gtk_widget_show(ventana);
	gtk_widget_show(boton);
	gtk_widget_show(etiqueta);

	gtk_main();

}


La funcion gtk_main_quit() efectivamente finaliza la aplicacion, entre otras cosas (limpiar buffers, sacar la asignacion de memoria de los widgets, etc).

Ahora, el mismo programa, pero en vez de imprimir un mensaje, automaticamente se cerrara la aplicacion.

#include <gtk/gtk.h>

int main (int argc, char * argv[])
{
	GtkWidget * ventana;
	GtkWidget * boton;
	GtkWidget * etiqueta;

	gtk_init(&argc, &argv);

	ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	boton = gtk_button_new();
	etiqueta = gtk_label_new("Etiqueta 1");
	
	gtk_window_set_title((GtkWindow *) ventana, "Ventana con boton");

	gtk_container_add ((GtkContainer *) ventana, boton);
	gtk_container_add ((GtkContainer *) boton, etiqueta);

	g_signal_connect ((GObject *) boton, 
			  "clicked", 
			  (GCallback) 
			  gtk_main_quit, NULL);

	gtk_widget_show(ventana);
	gtk_widget_show(boton);
	gtk_widget_show(etiqueta);

	gtk_main();

}

La diferencia entre estas dos es al conectar la señal "clicked".

Pero aun no resolvemos el problema que al cerrar la ventana (hacer click en la X de la derecha sonrisa ) efectivamente se cierre.

Como dije anteriormente, la señal "delete-event" se emite cuando la ventana padre se cierra. El manejador por defecto debiera ser una funcion que destruya a esta ventana.

Entonces, podemos resolver el problema conectando "delete-event" con gtk_main_quit():

g_signal_connect((GObject *) ventana,
		"delete-event",
		(GCallback ) gtk_main_quit,
		NULL);


Este es un ejemplo bastante mas complejo que los anteriores, asi que paciencia para entenderlo:

#include <gtk/gtk.h>

// esto es de buena costumbre

void funcion1 (GtkButton * boton, gpointer data);
void funcion2 (GtkButton * boton, gpointer data);
void cerrar_ventana (GtkWidget * widget,gpointer data);


// ahora las funciones
void cerrar_ventana (GtkWidget * widget,gpointer data)
{
	gtk_widget_destroy((GtkWidget *) data);
}


void funcion1 (GtkButton * boton, gpointer data)
{
	GtkWidget * ventana1;
	GtkWidget * boton1;

	// esta funcion al apretar el boton invoca el cerrado de la ventana

	ventana1 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	boton1 = gtk_button_new_with_label("Cerrar ventana");

	gtk_window_set_title((GtkWindow *) ventana1,
			     "Nueva ventana hija");
	
	gtk_container_add((GtkContainer *) ventana1,
			  boton1);

	g_signal_connect((GObject *) boton1,
			 "clicked",
			 (GCallback) cerrar_ventana,
			 (gpointer) ventana1);
	
	gtk_widget_show_all(ventana1);
}

void funcion2 (GtkButton * boton, gpointer data)
{
	gtk_main_quit();
}

int main (int argc, char * argv[])
{
	GtkWidget * ventana;
	GtkWidget * boton1;
	GtkWidget * boton2;
	GtkWidget * vbox;
	
	
	// inicializar GTK+
	gtk_init(&argc, &argv);

	
	// crear los controles
	ventana = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	boton1 = gtk_button_new_with_label("Nueva ventana");
	boton2 = gtk_button_new_with_label("Cerrar aplicacion");
	vbox = gtk_vbox_new(TRUE,5);

	
	// modificar las propiedades
	gtk_window_set_title((GtkWindow *) ventana, 
			 "Ejemplo mas completo");       

	// empaquetamiento
	gtk_box_pack_start((GtkBox *) vbox, 
			   boton1,
			   TRUE,
			   TRUE,
			   2);

	gtk_box_pack_start((GtkBox *) vbox,
			   boton2, 
			   TRUE,
			   TRUE,
			   2);
		      
	gtk_container_add((GtkContainer *) ventana, vbox);


	// conectar las señales
	g_signal_connect((GObject *) boton1,
			 "clicked",
			 (GCallback ) funcion1,
			 NULL);


	g_signal_connect((GObject *) boton2,
			 "clicked",
			 (GCallback) funcion2,
			 NULL);

	
	// atencion aqui!

	g_signal_connect((GObject *) ventana,
			 "delete-event",
			 (GCallback) gtk_main_quit,
			 NULL);
	
	// desplegar los controles
	gtk_widget_show_all(ventana);

	// GTK+ main loop
	gtk_main();
	return 0;
}
Herramientas personales
Espacios de nombres

Variantes
Acciones
Navegación
Herramientas