Ormai abbiamo visto tutto quello che c'è da vedere riguardo all'oggetto ``bottone''. E' piuttosto semplice, ma ci sono due modi per crare un bottone. Potete usare gtk_button_new_with_label() per creare un bottone con una etichetta, o usare gtk_button_new() per creare un bottone vuoto. In tal caso è poi vostro compito impacchettare un'etichetta o una pixmap sul bottone creato. Per fare ciò, create una nuova scatola, e poi impacchettateci i vostri oggetti usando la solita gtk_box_pack_start, e infine usate la funzione gtk_container_add per impacchettare la scatola nel bottone.
Ecco un esempio di utilizzo di gtk_button_new per creare un bottone con un'immagine ed un'etichetta su di sè. Ho separato il codice usato per creare la scatola in modo che lo possiate usare nei vostri programmi.
/* buttons.c */
#include <gtk/gtk.h>
/* crea una nuova hbox contenente un'immagine ed un'etichetta
* e ritorna la scatola creata. */
GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
{
GtkWidget *box1;
GtkWidget *label;
GtkWidget *pixmapwid;
GdkPixmap *pixmap;
GdkBitmap *mask;
GtkStyle *style;
/* creare una scatola per una xpm ed una etichetta */
box1 = gtk_hbox_new (FALSE, 0);
gtk_container_border_width (GTK_CONTAINER (box1), 2);
/* ottengo lo stile del bottone. Penso che sia per avere il colore
* dello sfondo. Se qualcuno sa il vero motivo, è pregato di dirmelo. */
style = gtk_widget_get_style(parent);
/* e ora via con le faccende dell'xpm stuff. Carichiamo l'xpm*/
pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
&style->bg[GTK_STATE_NORMAL],
xpm_filename);
pixmapwid = gtk_pixmap_new (pixmap, mask);
/* creiamo l'etichetta per il bottone */
label = gtk_label_new (label_text);
/* impacchettiamo la pixmap e l'etichetta nella scatola */
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);
}
/* la nostra solita funzione di callback */
void callback (GtkWidget *widget, gpointer data)
{
g_print ("Hello again - %s was pressed\n", (char *) data);
}
int main (int argc, char *argv[])
{
/* GtkWidget è il tipo per contenere gli oggetti */
GtkWidget *window;
GtkWidget *button;
GtkWidget *box1;
gtk_init (&argc, &argv);
/* creiamo una nuova finestra */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
/* E' una buona idea fare questo per tutte le finestre. */
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);
/* assegnamo lo spessore del bordo della finestra */
gtk_container_border_width (GTK_CONTAINER (window), 10);
gtk_widget_realize(window);
/* creiamo un nuovo bottone */
button = gtk_button_new ();
/* Ormai dovreste esservi abituati a vedere la maggior parte di
* queste funzioni */
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
/* questa chiama la nostra funzione di creazione di scatole */
box1 = xpm_label_box(window, "info.xpm", "cool button");
/* impacchetta e mostra tutti i nostri oggetti */
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);
/* mettiti in gtk_main e aspetta che cominci il divertimento! */
gtk_main ();
return 0;
}
La funzione xpm_label_box può essere usata per impacchettare delle xpm
e delle etichette su qualsiasi oggetto che può essere un contenitore.
I bottoni a commutazione sono molto simili ai bottoni normali, tranne che per il fatto che essi si trovano sempre in uno di due stati, che si alternano ad ogni click. Possono trovarsi nello stato ``premuto'', e quando li si ripreme, tornano ad essere sollevati. Ri-clickandoli, torneranno giù.
I bottoni a commutazione sono la base per i bottoni di controllo (check button) e per i radio-bottoni, e quindi molte delle chiamate disponibili per i bottoni a commutazione vengono ereditati dai radio-bottoni e dai bottoni di controllo. Ma vedremo questi aspetti nel momento in cui li incontreremo.
Creare un nuovo bottone a commutazione:
GtkWidget* gtk_toggle_button_new (void);
GtkWidget* gtk_toggle_button_new_with_label (gchar *label);
Come potete immaginare, queste funzioni lavorano in modo identico che per i bottoni normali. La prima crea un bottone a commutazione vuoto e la seconda un bottone con un'etichetta.
Per ottenere lo stato dei widget a commutazione, compresi i radio-bottoni e i bottoni di controllo, si può usare una macro come mostrato nell'esempio più sotto. In questo modo lo stato dell'oggetto commutabile viene valutato in una funzione di ritorno. Il segnale emesso dai bottoni a commutazione (toggle button, il radio button o il check button) che ci interessa è il segnale ``toggled''. Per controllare lo stato di questi bottoni, create un gestore di segnali che catturi il ``toggled'', e usate la macro per determinare il suo stato. La funzione di callback avrà un aspetto più o meno così:
void toggle_button_callback (GtkWidget *widget, gpointer data)
{
if (GTK_TOGGLE_BUTTON (widget)->active)
{
/* Se il programma si è arrivato a questo punto, il bottone
* a commutazione è premuto */
} else {
/* il bottone è sollevato */
}
}
void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
gint state);
La chiamata qui sopra può essere usata per fare l'assegnazione dello stato del bottone a commutazione e dei suoi figli, il radio-bottone e il bottone di controllo. Passando come primo argomento a questa funzione il vostro bottone e come secondo argomento il valore TRUE o FALSE, si può specificare se il bottone deve essere sollevato (rilasciato) o abbassato (premuto). Il valore di difetto è sollevato, cioè FALSE.
Notate che quando usate la funzione gtk_toggle_button_set_state(), e lo stato viene cambiato, si ha il risultato che il bottone emette il segnale ``clicked''.
void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);
Questa funzione semplicemente commuta il bottone, ed emette il segnale ``toggled''.
I bottoni di controllo ereditano molte proprietà e funzioni dal bottone a commutazione, ma hanno un aspetto un po' diverso. Invece di essere bottoni contenenti del testo, si tratta di quadratini con del testo alla propria destra. Questi bottoni sono spesso usati nelle applicazioni per commutare fra lo stato attivato e disattivato delle opzioni.
Le due funzioni di creazione sono analoghe a quelle del bottone normale..
GtkWidget* gtk_check_button_new (void);
GtkWidget* gtk_check_button_new_with_label (gchar *label);
La funzione new_with_label crea un bottone di controllo con una etichetta a fianco di esso.
Per controllare lo stato del check button si opera in modo identico al bottone a commutazione.
I radio-bottoni sono simili ai bottoni di controllo, tranne che per il fatto che sono sempre raggruppati in modo che solo uno alla volta di essi può essere selezionato (premuto). Tornano utili quando nella propria applicazione si ha bisogno di selezionare una opzione da una breve lista.
La creazione di un nuovo radio-bottone si fa con una di queste chiamate:
GtkWidget* gtk_radio_button_new (GSList *group);
GtkWidget* gtk_radio_button_new_with_label (GSList *group,
gchar *label);
Avrete notato l'argomento in più che c'è in queste chiamate. Queste hanno infatti bisogno dela specificazione di un ``gruppo'' per svolgere il loro compito. Per il primo bottone di un gruppo si deve passare come primo argomento il valore NULL. Dopodiché potete creare un gruppo usando la funzione:
GSList* gtk_radio_button_group (GtkRadioButton *radio_button);
La cosa importante da ricordare è che gtk_radio_button_group va chiamata ogni volta che si aggiunge un nuovo bottone al gruppo, con il preceente bottone passato come argomento. Il risultato viene poi passato nella chiamata a gtk_radio_button_new o a gtk_radio_button_new_with_label. Ciò permette di creare una catena di bottoni. L'esempio più sotto dovrebbe chiarire questo punto.
E' poi una buona idea stabiire quale dev'essere il bottone premuto per difetto, usando:
void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
gint state);
Questa funzione è descritta nella sezione sui bottoni a commutazione, e funziona nello stesso identico modo.
Nel seguente esempio creiamo un gruppo di tre radio-bottoni.
/* radiobuttons.c */
#include <gtk/gtk.h>
#include <glib.h>
void close_application( GtkWidget *widget, 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);
}
La cosa può essere accorciata un po' usando la seguente sintassi, che elimina la necessità di una variabile per contenere la lista di bottoni:
button2 = gtk_radio_button_new_with_label(
gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
"button2");