Programmation GTK/Bonjour tout le monde pas à pas


Maintenant que nous connaissons la théorie, clarifions un peu en progressant à travers le programme « Bonjour tout le monde ».

Voici la fonction de rappel appelée lorsque le bouton est « clicked ». Dans notre exemple, on ignore le widget et les données mais il n'est pas difficile de faire quelque chose avec. Le prochain exemple utilisera le paramètre des données pour nous dire quel bouton a été pressé.

 void hello (GtkWidget *widget, gpointer *data)
 {
     g_print ("Bonjour tout le monde\n");
 }

Cette fonction de rappel est un peu spéciale. L'événement "delete_event" survient lorsque le gestionnaire de fenêtres l'envoie à l'application. On doit choisir ce qu'il faut faire de ces événements. On peut les ignorer, leur donner une réponse, ou simplement quitter l'application.

La valeur que l'on retourne dans cette fonction de rappel permet à GTK de savoir ce qu'il a à faire. En retournant FALSE, on l'informe que l'on ne veut pas que le signal "destroy" soit émis, afin de laisser notre application tourner. En retournant TRUE, on lui demande d'émettre "destroy" qui appellera à son tour notre gestionnaire du signal "destroy".

 gint delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
     g_print ("le signal delete_event est survenu.\n");
 
     return (FALSE); 
 }

Voici une autre fonction de rappel qui ne fait que quitter l'application en appelant gtk_main_quit(). Il n'y a pas grand chose de plus à dire car elle est plutôt triviale :

 void destroy (GtkWidget *widget, gpointer *data)
 {
     gtk_main_quit ();
 }

Je suppose que vous connaissez la fonction main()... oui, comme les autres programmes C, toutes les applications GTK en ont une.

 int main (int argc, char *argv[]) 
 {

La partie qui suit déclare deux pointeurs sur des structures de type GtkWidget. Ceux-ci sont utilisés plus loin pour créer une fenêtre et un bouton.

     GtkWidget *window;
     GtkWidget *button;

Et revoici notre gtk_init(). Comme précédemment, il initialise le toolkit et analyse les paramètres de la ligne de commande. Il supprime chaque paramètre reconnu de la liste et modifie argc et argv pour faire comme si ces paramètres n'avaient jamais existé, laissant notre application analyser les paramètres restants.

     gtk_init (&argc, &argv);

Création d'une nouvelle fenêtre. C'est plutôt classique. La mémoire est allouée pour une structure GtkWidget et window pointe donc sur celle-ci. Cela configure une nouvelle fenêtre, mais celle-ci ne sera pas affichée tant que l'on n'a pas appelé gtk_widget_show(window) vers la fin de notre programme.

     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

Voici maintenant un exemple de connexion d'un gestionnaire de signal à un objet : la fenêtre. Le signal "destroy" est capturé. Il est émis lorsqu'on utilise le gestionnaire de fenêtres pour tuer la fenêtre (et que l'on retourne TRUE dans le gestionnaire "delete_event"), ou lorsqu'on utilise l'appel gtk_widget_destroy() en lui passant le widget window comme objet à détruire. Ici, on appelle juste la fonction destroy() définie ci-dessus avec le paramètre NULL, ce qui quitte GTK pour nous.

GTK_OBJECT et GTK_SIGNAL_FUNC sont des macros qui réalisent les conversions et les vérifications de types pour nous. Elles rendent aussi le code plus lisible.

     gtk_signal_connect (GTK_OBJECT (window), "destroy",
                         GTK_SIGNAL_FUNC (destroy), NULL);

La fonction suivante sert à configurer un attribut d'un objet container. Elle configure simplement la fenêtre pour qu'elle ait une zone vide autour d'elle de 10 pixels de large où aucun widget ne pourra se trouver. Il existe d'autres fonctions similaires que nous verrons dans la section sur la Configuration des attributs des widgets

À nouveau, GTK_CONTAINER est une macro réalisant la conversion de type.

     gtk_container_border_width (GTK_CONTAINER (window), 10);

Cet appel crée un nouveau bouton. Il alloue l'espace mémoire pour une nouvelle structure GtkWidget, l'initialise et fait pointer button vers elle. Ce bouton portera le label « Bonjour tout le monde » lorsqu'il sera affiché.

     button = gtk_button_new_with_label ("Bonjour tout le monde");

Maintenant, prenons ce bouton et faisons lui faire quelque chose d'utile. On lui attache un gestionnaire de signal pour que, lorsqu'il émettra le signal "clicked", notre fonction hello() soit appelée. On ignore les paramètres et on ne passe donc que la valeur NULL à la fonction de rappel hello(). Évidemment, le signal "clicked" est émis lorsqu'on clique sur le bouton avec la souris.

     gtk_signal_connect (GTK_OBJECT (button), "clicked",
                         GTK_SIGNAL_FUNC (hello), NULL);

On utilisera aussi ce bouton pour quitter notre programme, ce qui permettra d'illustrer la façon dont le signal "destroy" peut venir soit du gestionnaire de fenêtres, soit de notre programme. Quand le bouton est "clicked" comme cela est décrit plus haut, il appelle d'abord la fonction de rappel hello() puis celle-ci dans l'ordre dans lequel elles sont configurées. On peut avoir autant de fonctions de rappel que l'on désire, elles seront exécutées selon leur ordre de connexion. Puisque la fonction gtk_widget_destroy() n'accepte que GtkWidget *widget comme paramètre, on utilise ici la fonction gtk_signal_connect_object() à la place de gtk_signal_connect().

     gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                                GTK_SIGNAL_FUNC (gtk_widget_destroy),
                                GTK_OBJECT (window));

Voici un appel de placement, qui sera expliqué en détail plus tard, mais qui est plutôt facile à comprendre. Il indique simplement à GTK que le bouton doit être placé dans la fenêtre où il s'affichera.

  gtk_container_add (GTK_CONTAINER (window), button);

Maintenant, nous avons tout configuré comme on le souhaitait : les gestionnaires de signaux sont en place et le bouton est mis dans la fenêtre où il doit se trouver. On demande alors à GTK de « montrer » les widgets à l'écran. Le widget window est affiché en dernier afin que la fenêtre entière surgisse d'un coup plutôt que voir d'abord la fenêtre s'afficher puis ensuite le bouton apparaître à l'intérieur. Il faut dire qu'avec des exemples simples comme celui-ci, vous ne ferez pas la différence.

     gtk_widget_show(button);
     gtk_widget_show (window);

Bien sûr, on appelle gtk_main() qui attendra les événements venant du serveur X et demandera aux widgets d'émettre les signaux lorsque ces événements surviendront.

     gtk_main ();

Enfin, le return final. Il est exécuté lorsque gtk_quit() est appelé.

     return 0;

Lorsque l'on clique sur un bouton GTK, le widget émet un signal "clicked". Afin de pouvoir utiliser cette information, notre programme configure un gestionnaire pour capturer ce signal. Ce gestionnaire appelle la fonction de notre choix. Dans notre exemple, lorsque le bouton que l'on a créé est "clicked", la fonction hello() est appelée avec le paramètre NULL, puis le gestionnaire suivant de ce signal est à son tour appelé. Il appelle la fonction gtk_widget_destroy() en lui passant le widget window comme paramètre, ce qui provoque la destruction de celui-ci. Ceci force la fenêtre à envoyer un signal "destroy", qui est capturé à son tour et appelle notre fonction de rappel destroy() qui ferme simplement GTK.

Une autre façon de procéder consiste à utiliser le gestionnaire de fenêtres pour détruire la fenêtre. Cela provoquera l'émission du signal "delete_event" qui sera pris en charge par notre gestionnaire delete_event(). S'il retourne FALSE, la fenêtre restera telle quelle et rien ne se passera. Retourner TRUE forcera GTK à émettre le signal "destroy" qui, bien sûr, appelera la fonction de rappel destroy() provoquant la sortie du GTK.

On remarquera que ces signaux ne sont pas les mêmes que les signaux systèmes Unix et ne sont pas implantés en utilisant ceux-ci, bien que la terminologie employée soit presque identique.