2011 juin 27
Initiation aux interfaces graphiques en langage C avec EZ-Draw
12:23 - Par Edouard Thiel - Pédagogie - Lien permanent
Par Edouard Thiel
Dans cette note, je vous présente une petite boîte à outil graphique qui s'appelle EZ-Draw et qui vient de sortir en version 1.0 ; c'est un logiciel libre sous licence LGPL.
J'ai eu l'idée de développer ce logiciel en discutant avec des collègues qui enseignent le langage C en première année de la Licence Informatique à Luminy ; ils souhaitaient faire un miniprojet de fin d'année avec une interface graphique, par exemple un jeu de dame ou de sudoku.
J'ai moi-même enseigné pendant plus de dix ans en première année de Deug MIAS et MASS, avant le passage au LMD (le nouveau système de diplômes européen Licence-Master-Doctorat) ; à l'époque le premier langage était le Pascal, et grâce à Turbo Pascal ou à Delphi, on pouvait facilement faire du graphisme, et ce genre de mini-projet graphique de fin d'année avait le don de motiver beaucoup les étudiants.
Actuellement, parmi d'autres choses, j'enseigne la programmation d'interfaces graphiques en GTK en fin de deuxième année. GTK est la librairie graphique qui anime le bureau GNOME ; c'est joli, pro, complet, écrit en C, mais nécessite d'écrire des montagnes de code pour créer une fenêtre, faire vivre un bouton, faire un dessin, etc : bref, ce n'est absolument pas du niveau débutant.
Il existe bien d'autres toolkits graphiques utilisables en C, mais leur emploi n'est guère plus simple et donc on en revient au même : nécessité de quelque chose de simple pour grands débutants en langage C.
D'où cette idée d'écrire EZ-Draw : j'ai gardé le strict essentiel, en conservant les 3 ou 4 notions de base, et en supprimant tout ce qui est secondaire (on veut juste des fenêtres, pouvoir dessiner dedans et gérer des évènements simples).
Pendant que j'y étais, j'ai fait en sorte que EZ-Draw fonctionne sur tous les systèmes, que ce soit Linux (toutes les salles de TP sont sous Debian), Mac OS (un certain nombre d'étudiants ont un Mac), et bien sûr Windows (la plupart des étudiants on accès à un PC sous Windows chez eux, avant que d'investir dans un portable, puis installer Ubuntu dans l'immense majorité des cas).
Pour installer le logiciel, rien de plus simple, il suffit de suivre les instructions dans le fichier README, il n'y a (presque) pas de configuration, ça marche tout de suite. Le coeur de EZ-Draw tient dans seulement 2 fichiers (ez-draw.c et ez-draw.h), le reste est constitué de démos pour illustrer le tutorial pas à pas, et de quelques jeux avec du code plus conséquent pour tester le tout : ça m'a permis de voir s'il ne manquait rien et si c'était réellement pratique à utiliser. Par exemple, un jeu de labyrinthe en 3D "fil de fer", il y a des captures d'écran ici.
Pour avoir une idée précise de EZ-Draw, je vous invite naturellement à consulter le tutorial et le manuel de référence, mais auparavant voici un exemple simple d'utilisation : nous allons ouvrir une fenêtre et afficher une croix ; chaque fois que l'utilisateur cliquera dans la fenêtre, la croix sera redessinée à la position de la souris ; en tapant sur la lettre 'q', l'utilisateur pourra quitter le programme.
On va avoir besoin d'écrire 3 fonctions. La première est la fonction main, qui est le programme principal.
#include "ez-draw.h"
int main ()
{
Window win1;
if (ez_init() < 0) exit(1);
win1 = ez_window_create (400, 300, "Essai 1", win1_event);
ez_main_loop ();
exit(0);
}
Il suffit d'inclure ez-draw.h pour bénéficier de toutes les définitions de EZ-Draw.
On commence par déclarer une variable win1 de type Window ; cette variable contiendra le numéro de la fenêtre que l'on va créer.
Ensuite on initialise EZ-Draw avec ez_init ; si cette initialisation échoue (résultat négatif), alors on abandonne le programme avec exit(1) (le 1 pour dire que la programme a échoué).
Pour créer une fenêtre, une seule ligne suffit : on appelle ez_window_create avec 4 paramètres : la largeur et hauteur de la fenêtre en pixels, son titre, et un 4e paramètre win1_event sur lequel je vais revenir dans un instant.
Enfin on appelle ez_main_loop : cette fonction s'appelle la "boucle d'évènements" ; il s'agit d'une boucle sans fin, qui attend les événements (clic souris, touche clavier, etc) et fait les opérations nécessaires. Cette fonction fait apparaitre la ou les fenêtres créées, puis se termine lorsque toutes les fenêtres ont été fermées ou lorsque on appelle la fonction ez_quit.
La seconde fonction est la fonction win1_event ; c'est elle qu'on a passé en 4e paramètre à ez_window_create. De quoi s'agit-il ? Eh bien c'est la fonction que ez_main_loop va appeler chaque fois que il y aura un évènement sur la fenêtre win1. On appelle ça la callback de la fenêtre.
void win1_event (Ez_event *ev) /* Appelée a chaque événement sur win1 */
{
switch (ev->type) {
case Expose : /* Il faut tout redessiner */
win1_redessiner (ev->win);
break;
case ButtonPress : /* Un bouton de la souris a été enfoncé */
clic_x = ev->mx;
clic_y = ev->my;
ez_send_expose (ev->win);
break;
case KeyPress : /* Une touche a été pressée */
switch (ev->key_sym) {
case XK_q : ez_quit (); break;
}
break;
}
}
Cette fonction est appelée avec un évènement ev en paramètre (pour les amateurs de Pascal, l'écriture EZ_event *ev signifie var ev : Ez_event, ce dernier étant un type record).
Dans cet évènement il y a un champ ev->type qui décrit le type (codé par un entier) de l'évènement. On fait donc un branchement avec le switch selon ce type d'évènement. Je vous présente ici 3 évènements.
- L'évènement
Exposesignifie que l'on doit entièrement redessiner l'intérieur de la fenêtre. C'est le seul moment où l'on peut dessiner. - L'évènement
ButtonPresssignifie que l'un des boutons de la souris a été enfoncé. On récupère ici les coordonnées de la sourisev->mxetev->mydans des variables globalesclic_xetclic_y, puis on demande à ce que la fenêtre soit redessinée avecez_send_expose, qui comme son nom l'indique va envoyer un évènementExposeà la fenêtre. - L'évènement
KeyPresssignifie que une touche du clavier a été enfoncée. Chaque touche a un numéro, représenté par une constante préfixée parXK_. Par exempleXK_qdésigne la touche 'q',XK_spacereprésente la barre d'espace, etc. Comme vous le voyez ici, presser la touche 'q' provoquera la fin du programme.
Venons-en à la 3e et dernière fonction win1_redessiner, chargée de dessiner l'intérieur de la fenêtre. Souvenez-vous que le seul endroit où vous avez le droit d'appeler cette fonction est lors de l'évènement Expose.
int clic_x = 200, clic_y = 150;
void win1_redessiner (Window win)
{
ez_set_color (ez_magenta);
ez_set_thick (5);
ez_draw_line (win, clic_x - 20, clic_y, clic_x + 20, clic_y);
ez_draw_line (win, clic_x, clic_y - 20, clic_x, clic_y + 20);
}
La fonction reçoit en paramètre la fenêtre win dans laquelle elle va dessiner. Elle sélectionne la couleur et l'épaisseur des prochains dessins, puis trace deux traits en forme de croix, centrée autour de la position clic_x, clic_y, qui avait été mémorisée lors du précédent clic souris. Pour simplifier on a mémorisé cette position dans des variables globales clic_x, clic_y, mais il existe aussi un moyen d'éviter les variables globales (voir ici).
Après avoir recopié les trois fonctions dans le fichier essai1.c, il reste à le compiler pour produire un exécutable. Sous Unix (Linux, Mac OS, Solaris, etc) taper :
gcc -Wall essai1.c ez-draw.c -o essai1 -L/usr/X11R6/lib -lX11 -lXext
puis
./essai1
pour l'exécuter.
Sous Window (toutes versions, de Seven à Windows 98 !)
gcc -Wall essai1.c ez-draw.c -o essai1.exe -lgdi32
puis
essai1
dans un terminal pour l'exécuter, ou encore double-cliquez sur l'icone de essai1.
Et voila c'est fini. Si EZ-Draw vous plait, n'hésitez pas à partager votre retour d'expérience.
Commentaires
Une super bibliothèque facile à mettre en oeuvre que j'utilise avec mes élèves de première. Merci pour ce travail.
L'évolution qui serait souhaitée (mais ce n'est qu'une remarque, car je sais que ça demande un travail énorme) serait la gestion de boutons.
Encore merci.
Le dimanche, novembre 6 2011, 16:14 par jlpadiolleau
Que voilà une excellente idée!
Merci pour ce travail. J'ai le projet de faire une initiation à la programmation par langage C à Bressuire. Nul doute, qu'EZ-Draw va contribuer à rendre, le moment venu, cette présentation plus vivante...
Je vais diffuser l'info. sur EZ-Draw à mes copains de GEBULL (notre association dans le 79). Encore merci
Le lundi, septembre 10 2012, 11:05 par Alain LEAPER