Vous vous apprêtez à lire un tutoriel rédigé par un membre de ce site. Malgré tout le soin que ce membre a pu apporter au tutoriel, nous ne pouvons pas garantir que les informations contenues sur cette page sont exactes à 100%. Merci de garder cela en tête lorsque vous lirez cette page ;o)
Nous allons maintenant voir comment intercepter les actions de l'utilisateur et agir en conséquence. Au programme, explications, exemples et exercices.
Nous allons traiter ici ce qu'on appelle
la programmation évènementielle ! Cela consiste à intercepter les actions de l'utilisateur pour les traiter : clic sur un bouton, validation d'une zone de texte, etc.. Sans ça, votre programme ne fera rien ! En fait, c'est cette gestion qui fera le "gros" du programme, tous se passe dedans !
Principe
Vos programmes ne suivront désormais plus du tout le même plan. Je m'explique :
- Avant, vos programmes étaient dis linéaires : votre code s'exécutait dans l'ordre où vous l'aviez écrit (du haut vers le bas), vous étiez d'ailleurs assez limités par cette contrainte. De plus, l'utilisateur n'avait aucune liberté, il ne pouvait rien faire d'autre que ce que vous lui proposiez.
- Maintenant, c'est une toute autre façon de penser. Dans votre programme, vous définissez votre interface, les boutons et tout ça, on lance le tout, puis on passe la main à l'utilisateur. C'est lui qui choisi ce qu'il fait, quand, et comment.
Cette méthode de programmation est dite
évènementielle, elle suit le principe
action -> réaction.
Le principe est vraiment simple : lorsqu'un évènement a lieu avec un widget, celui ci émet ce qu'on appelle
un signal (celui-ci sera différent pour chaque action que le widget gère), l'objectif du jour est de savoir faire réagir notre application à la réception de ces signaux.
GTK s'occupe de tout, donc la partie technique ne nous regarde pas; cependant il faut bien comprendre comment ça fonctionne.
Il n'y a qu'une seule chose à faire. On va utiliser une fonction qui dira à GTK :
- De quel widget on veut traiter un évènement.
- Le signal (l'évènement) que l'on veut traiter.
- Le nom d'une fonction (faite par vous), à appeler lorsque cet évènement survient. Ce type de fonction est appelé fonction callback.
En gros, on peut résumer avec un petit schéma :
ACTION UTILISATEUR
|
ÉMISSION SIGNAL
|
RÉCEPTION SIGNAL
|
FONCTION CALLBACK
Passons maintenant à la pratique ! Voilà le code de base sur lequel nous allons travailler. Créez un projet et collez ce code dedans :
Code : C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | #include <stdlib.h>
#include <gtk/gtk.h>
void mafonction(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
int main(int argc, char **argv)
{
/* Variables */
GtkWidget * MainWindow = NULL;
/* Initialisation de GTK+ */
gtk_init(&argc, &argv);
/* Création de la fenêtre */
MainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(MainWindow), "delete-event", G_CALLBACK( mafonction ), NULL);
/* Affichage et boucle événementielle */
gtk_widget_show(MainWindow);
gtk_main();
/* Fermeture de GTK+ */
gtk_exit(EXIT_SUCCESS);
return EXIT_SUCCESS;
}
|
Observons ce code, et essayons de le comprendre. La seule nouveauté est la petite fonction en haut, normalement vous devriez vous dire :
À quoi sert-elle ?
Quand est-elle appelée ? Comment ?
Qu'est-ce qu'on doit mettre dedans ? Etc ..
À quoi sert la fonction g_signal_connect au milieu du code ?
Autant de questions auxquelles je vais tenter de répondre.
Gérer une action
Penchons-nous déjà sur cette ligne :
Code : C1 | g_signal_connect(G_OBJECT(MainWindow), "delete-event", G_CALLBACK( mafonction ), NULL);
|
L'appel de cette fonction permet de
gérer un évènement. Voyons les paramètres :
- MainWindow : Ce premier paramètre doit être le widget dont on veut gérer un évènement, en le mettant dans la macro G_OBJECT.
Ici, on gère un évènement de la fenêtre.
- "delete-event" : On écrit le nom du signal que l'on souhaite intercepter dans une chaine de caractères. Il existe un nom de signal pour chaque signal existant. En l'occurrence, "delete-event" est émis lorsque on clique sur la croix d'une fenêtre.
- mafonction : Il faut mettre ici le nom d'une fonction callback qui sera appelée lors de l'évènement, en le mettant dans la macro G_CALLBACK.
- NULL : Pour finir, on donne un paramètre passé automatiquement à la fonction donnée juste avant. On s'en sert pour passer des données à la fonction. Ici, on met NULL.
Sachant que le prototype est :
Code : C1 | gulong g_signal_connect(gpointer *object, const gchar *name, GCallback func, gpointer func_data );
|
On peut dire que : Quand
object émet le signal
name, GTK+ appelle la fonction
func avec les paramètres
object et
data. Donc à ce moment là, GTK génère cet appel et l'exécute :
Code : C
La fonction en question devra toujours avoir le prototype suivant :
Code : C1 | void mafonction(GtkWidget *widget, gpointer data);
|
En fait, ce prototype pourra changer pour certains évènements, mais ce sont des cas particuliers. Nous en parlerons en temps voulu.
Ainsi, on a accès au widget qui à émis le signal par le premier paramètre, et à une donnée quelconque par le deuxième.
Maintenant, reprenez votre code, vous êtes maintenant en mesure de le comprendre : le programme est quitté lorsqu'on clique sur la croix de la fenêtre.
La boucle principale
Pour gérer les évènements, GTK+ utilise une
boucle évènementielle. C'est une boucle
infinie (enfin presque, faut bien qu'on puisse quitter) dans laquelle GTK+ s'occupe d'émettre les signaux, et d'appeler les fonctions callback nécessaires.
Pour lancer cette boucle (le plus souvent, pour "lancer le programme" en quelque sorte), on appelle la fonction
gtk_main :
Code : C
Pour quitter cette boucle, la fonction est :
Code : C1 | void gtk_main_quit(void);
|
Vous savez maintenant tout ce qu'il faut savoir pour bien aborder la gestion des évènements. Assurez-vous d'avoir bien compris, je vous conseille de relire l chapitre plusieurs fois si besoin. Je sais que tout cela peut vous paraitre un peu flou, mais après tout c'est quand même plus simple que les pointeurs !

(à moins que..?)
Maintenant que vous avez (plus ou moins) compris comment on traitait les événements, voilà deux exercices. Il serait vraiment essentiel de les réussir, et pour vous y aider je ne donne pas de solution : l'important, c'est que ca marche !
Pour bien commencer, prenez le code de la partie précédente. N'oubliez pas que
tout se passe dans la fonction qui est en haut !
Exercice 1
Faites un programme qui fait ceci lorsque on clique sur la croix :
- Ecrire le titre de la fenêtre dans la console, en inversant l'ordre des lettres !

- Quitter le programme.
Assez facile, pensez à activer la console si elle n'apparait pas ! (Projet > Options)
Exercice 2
Pas beaucoup plus dur, mais plus marrant !
- Ecrivez un programme qui ouvre une deuxième fenêtre quand on clique sur la croix de la première.
- Quitter le programme quand on clique sur la croix de la deuxième.
- La deuxième fenêtre contiendra le titre de la première dans un label.
Attention, ici on a deux signaux à gérer, un pour chaque fenêtre !
Exercice 3
Vous devriez y arriver, mais il est plus difficile.
- Créez une fenêtre, avec la première lettre de votre prénom dedans (dans un label).
- Quand on clique sur la croix de la fenêtre, on change la lettre affichée par la suivante.
- Quand on est arrivé à la fin du nom, on quitte.