Ya hemos visto prácticamente todo lo que hay que saber a cerca de este widget. Existen dos formas diferentes de crear un botón. Se puede usar gtk_button_new_with_label() para conseguir un botón con etiqueta o simplemente gtk_button_new(). Si se quiere se puede añadir una etiqueta a este último empaquetá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ón mediante gtk_container_add.
Estudiemos un ejemplo de gtk_button_new para crear un botón con una imagen y una etiqueta. El código está dividido en dos para que pueda ser reusado.
/* comienzo 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 *box1;
GtkWidget *label;
GtkWidget *pixmapwid;
GdkPixmap *pixmap;
GdkBitmap *mask;
GtkStyle *style;
/* create box for xpm and label */
box1 = gtk_hbox_new (FALSE, 0);
gtk_container_border_width (GTK_CONTAINER (box1), 2);
/* obtenemos el estilo del botón (probablemente para el color de fondo, pero no estoy
seguro)*/
style = gtk_widget_get_style(parent);
/* cargamos el pixmap. Hay una secció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);
label = gtk_label_new (label_text);
gtk_box_pack_start (GTK_BOX (box1),
pixmapwid, FALSE, FALSE, 3);
gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
gtk_widget_show(pixmapwid);
gtk_widget_show(label);
return (box1);
}
/* respuesta */
void callback (GtkWidget *widget, gpointer data)
{
g_print ("Hello again - %s was pressed\n", (char *) data);
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *box1;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
/* It's a good idea to do this for all windows. */
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_exit), NULL);
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (gtk_exit), NULL);
gtk_container_border_width (GTK_CONTAINER (window), 10);
gtk_widget_realize(window);
button = gtk_button_new ();
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
box1 = xpm_label_box(window, "info.xpm", "cool button");
gtk_widget_show(box1);
gtk_container_add (GTK_CONTAINER (button), box1);
gtk_widget_show(button);
gtk_container_add (GTK_CONTAINER (window), button);
gtk_widget_show (window);
gtk_main ();
return 0;
}
/* final del ejemplo */
La función xpm_label_box puede ser usada para empaquetar xpm y etiquetas en cualquier widget que pueda ser un contenedor.
El botón puede responder a las siguientes señales:
Estos botones son muy similares a los normales. La única diferencia es que sólo pueden estar en dos posiciones diferentes alternadas mediante pulsaciones del ratón.
Los botones de selección son la base de otros tipos: los de comprobación y los circulares. Por lo tanto muchas de sus llamadas seran heredadas por estos.
Creamos un nuevo botón de selección:
GtkWidget *gtk_toggle_button_new( void );
GtkWidget *gtk_toggle_button_new_with_label( gchar *label );
Como se ha podido imaginar estas funciones son iguales a las de un botón normal. La primera crea un botón, mientras que la segunda crea un botón con una etiqueta.
Para saber cual es el estado de un botón de selección, comprobación o circular se usa una de las macros del ejemplo siguiente. En éstas se comprueba el estado del botón mediante una respuesta. La señal que queremos recibir es "toggled". Generalmente para comprobar el estado de una señal se establece un controlador de señales y luego se usa la siguiente macro. La función de respuesta debe ser de la forma:
void toggle_button_callback (GtkWidget *widget, gpointer data)
{
if (GTK_TOGGLE_BUTTON (widget)->active)
{
/* Si el control llega aquí el botón se encuentra pulsado */
} else {
/* El botón no está pulsado (sobresale) */
}
}
void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
gint state );
La llamada de arriba puede ser usada para establecer el estado de un botón de selección (o de cualquiera de sus hijos: el circular o el de comprobación). El primer argumento es el botón, el segundo TRUE cuando queremos que el botón no esté pulsado o FALSE para cuando lo esté. Por defecto se establece FALSE.
Hay que destacar que cuando se usa gtk_toggle_button_set_state() y se cambia el estado del botón este emite la señal ``clicked''.
void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
Cambia el estado del botón emitiendo la señal ``toggled''.
Los botones de comprobació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ñ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.
GtkWidget *gtk_check_button_new( void );
GtkWidget *gtk_check_button_new_with_label ( gchar *label );
La función new_with_label crea un botón de comprobación con una etiqueta dentro.
El proceso para comprobar el estado de un botón de este tipo es igual al de los de comprobación.
Estos botones son similares a los de selección con la salvedad de que está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ón circular son:
GtkWidget *gtk_radio_button_new( GSList *group );
GtkWidget *gtk_radio_button_new_with_label( GSList *group,
gchar *label );
El nuevo argumento sirve para especificar el grupo al que pertenecen. La primera llamada debe pasar NULL como primer argumento. A continuación de ésta se puede crear el grupo usando:
GSList *gtk_radio_button_group( GtkRadioButton *radio_button );
Para añadir un nuevo botón a un grupo hay que usar gtk_radio_button_group con el anterior botón como argumento. El resultado se le pasa a gtk_radio_button_new o a gtk_radio_button_new_with_label. Así se consigue enlazar una cadena de botones. (El ejemplo siguiente sirve para aclarar el proceso)
También se puede establecer cúal es el botón pulsado por defecto:
void gtk_toggle_button_set_state( GtkToggleButton *toggle_button,
gint state );
El siguiente ejemplo crea un grupo de tres botones:
/* Comienzo 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 *window = NULL;
GtkWidget *box1;
GtkWidget *box2;
GtkWidget *button;
GtkWidget *separator;
GSList *group;
gtk_init(&argc,&argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC(close_application),
NULL);
gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
gtk_container_border_width (GTK_CONTAINER (window), 0);
box1 = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), box1);
gtk_widget_show (box1);
box2 = gtk_vbox_new (FALSE, 10);
gtk_container_border_width (GTK_CONTAINER (box2), 10);
gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
gtk_widget_show (box2);
button = gtk_radio_button_new_with_label (NULL, "button1");
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
button = gtk_radio_button_new_with_label(group, "button2");
gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
button = gtk_radio_button_new_with_label(group, "button3");
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
gtk_widget_show (button);
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
gtk_widget_show (separator);
box2 = gtk_vbox_new (FALSE, 10);
gtk_container_border_width (GTK_CONTAINER (box2), 10);
gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
gtk_widget_show (box2);
button = gtk_button_new_with_label ("close");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC(close_application),
GTK_OBJECT (window));
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show (window);
gtk_main();
return(0);
}
/* final del ejemplo */
El proceso se puede acortar quitando la variable que contiene a la lista de botones:
button2 = gtk_radio_button_new_with_label(
gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
"button2");