Free online content available in this course.

Got it!

Last updated on 1/8/18

Gestion des évènements : les signaux

Log in or subscribe for free to enjoy all this course has to offer!

Nous allons maintenant voir comment intercepter les actions de l'utilisateur et agir en conséquence. Au programme, explications, exemples et exercices.

Comment ça marche ?

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 :

#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 :

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 :

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 :

func(object, data);

La fonction en question devra toujours avoir le prototype suivant :

void mafonction(GtkWidget *widget, gpointer data);

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 :

void gtk_main(void);

Pour quitter cette boucle, la fonction est :

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 ! :p (à moins que..?)

Exercices

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 ! :p

  • 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.

Voilà enfin cette première partie sur GTK+ terminée, vous avez normalement acquis les bases et êtes prêts à faire des choses plus intéressantes ! Au programme de la seconde partie : du concret ! Découvertes des widgets les plus utilisés, au moins un TP, bref : de quoi vous occuper. :)

Example of certificate of achievement
Example of certificate of achievement