Vous êtes sur la page 1sur 18

Chapitre 1

Cr eation dinterfaces graphiques

N
1

ous abordons ici la cr eation dinterfaces graphiques fen etr ees, qui constituent la plus grande partie des applications actuelles. Une fen etre est un el ement graphique, souvent rectangulaire qui peut contenir ` un programme peuvent correspondre de des menus, des boutons, des champs de saisie de texte... A nombreuses fen etres.

Biblioth` eques dinterfaces graphiques

La programmation dune application graphique n ecessite lutilisation dune biblioth` eque en ce sens quune telle pratique simplie enorm ement le d eveloppement. Rien ninterdit ` a un programmeur de dessiner un rectangle ` a l ecran, qui sera appel e fen etre, de dessiner des petits rectangles qui seront appel es boutons, et de faire en sorte que lorsque lutilisateur clique sur ces boutons, leur image soit modi ee de telle fa con quon ait limpression quil senfonce. N eanmoins, entrer dans de tels m eandres rend l ecriture dun programme beaucoup plus longue. Le but ici, est de se concentrer sur ce ` a quoi doit servir le programme, et de laisser les t aches de gestion des el ements graphiques ` a une biblioth` eque qui contient d ej` a tout le code de leur achage. Il existe de nombreuses biblioth` eques pour cr eer des interfaces graphiques, certaines r eserv ees ` a un syst` eme dexploitation particulier (Windows, GNU/Linux...), dautres dont le code est ecrit pour plusieurs syst` emes. De telles biblioth` eques sont dites portables et permettent en th eorie dutiliser le m eme code source pour di erents syst` emes (on obtiendra un programme ex ecutable d edi e` a un syst` eme particulier en compilant le code source pour ce syst` eme), sans avoir ` a le modier. Lutilisation dune biblioth` eque portable est largement conseill ee, et le choix reste assez important : Qt, Gtk, Fltk, Graphapp, WxWindows,... On distingue ces biblioth` eques selon quelles sont pr evues pour tel ou tel type de langage de programmation. Qt et Fltk sont faites pour programmer en C++, par exemple, alors que Gtk et Graphapp sont utilisables en C. On les distingue aussi en fonction de leur richesse, cest ` a dire essentiellement en fonction de la diversit e des el ements graphiques quelles proposent (fen etres, boutons, champs de saisie, menus, etiquettes, editeurs de textes, barres de d element...)1 . Dans la suite nous nous int eresserons ` a la biblioth` eque Graphapp, qui nest pas parmi les plus riches, mais qui reste parmi les plus simples ` a utiliser.

Programmation ev enementielle
1. cr eation des fen etres, des boutons et des autres el ements graphiques ; 2. attente dun ev enement (fermeture dune fen etre, appui sur un bouton, d eplacement de la souris, appui sur une touche du clavier, ...) ; 3. traitement dun ev enement, par une proc edure ecrite ` a cet eet, et nomm ee callback (ou encore fonction r eexe) ; 4. retour ` a l etape 2.

Une application graphique ecrite en C suit g en eralement le sch ema suivant :

Utiliser une biblioth` eque graphique signie que le programmeur devra :


1 Une autre distinction est de savoir si la biblioth` eque conserve le look and feel de la plate-forme sur laquelle elle fonctionne ou non. Les deux philosophies existent.

Compl ements Algo-Prog Gea 2

1. d ecrire linterface en pr ecisant o` u il veut placer tel bouton, telle etiquette et tel champ de saisie 2. ecrire les proc edures callback qui seront appel ees par le syst` eme de gestion des ev enements de la biblioth` eque lorsque lutilisateur agira sur tel ou tel el ement. Nous allons illustrer ici nos propos avec la r ealisation dun convertisseur de monnaie. Notre interface comportera un champ pour entrer une valeur num erique, une liste de choix pour choisir la monnaie de d epart, une liste de choix pour choisir la monnaie darriv ee, une zone pour indiquer le r esultat de la conversion, un bouton pour demander la conversion et un bouton pour quitter :

Voici un sc enario dutilisation du convertisseur : Le convertisseur sache ` a l ecran. Lutilisateur entre une valeur num erique ` a convertir (par exemple 150). Lutilisateur clique sur convertir. La valeur convertie (en euros) sache au dessous de 150.0. Lutilisateur s electionne ( (Dollars) ) dans la liste du bas. Le convertisseur ache l equivalent en dollars de 150 francs. Lutilisateur clique sur ( (Quitter) ). Le programme se termine. La gure 1.1 illustre la fa con dont doivent sarticuler les actions de lutilisateur avec les t aches eectu ees par le programme. Dans la colonne de gauche sont repr esent ees les t aches eectu ees par la machine et dans celle de droite les t aches eectu ees par lutilisateur. Le temps s ecoule de haut en bas. Nous voyons que, except e lors du d ebut du programme (achage des el ements graphiques), le programme doit ( (r epondre) ) dune certaine mani` ere aux actions de lutilisateur. Mais le programme ignore ce que va faire lutilisateur, et donc dans quel ordre il devra donner ses r eponses. Enn, il appara t que le programme a deux r eponses possibles : action A : ((Lecture de la valeur dans le champ, calcul du r esultat et achage) ) ou action B : ((Fermeture des fen etres et terminaison du programme) ) Lex ecution de lune de ces deux actions est conditionn ee par l el ement de la fen etre qui a et e activ e par lutilisateur : Laction A devra etre d eclench ee si lutilisateur a cliqu e sur ( (Conversion) ), ou bien a s electionn e une monnaie dans une des deux listes d eroulantes et laction B devra etre d eclench ee si lutilisateur a cliqu e sur ( (Quitter) ). Les actions de lutilisateur sont appel ees les ev enements. Le programme doit donc r epondre aux ev enements. Une fonction qui r epond a ` un ev enement est appel ee fonction callback, et ce type de programmation (donner les actions que le programme doit faire en r eponse ` a une sollicitation de lutilisateur) est appel e programmation ev enementielle. Une biblioth` eque de cr eation dinterfaces graphiques digne de ce nom prend en charge : lachage (au niveau du pixel) des el ements, lattente quun ev enement se produise et enn lappel de la fonction callback associ ee ` a un el ement de linterface graphique lorsque celui-ci est activ e par lutilisateur. Notons au passage un inconv enient de ce type de programmation (si on ne dispose pas doutils evolu es comme les processus l egers) : la ligne temporelle correspondant au programme dans le sch ema pr ec edent est dessin ee en pointill es. Pendant ces pointill es, la machine attend simplement que lutilisateur fasse quelque chose. En revanche, lors de la r ealisation de laction A par exemple, le programme est monopolis e jusqu` a ce quelle se termine. Pendant le court laps de temps de la r ealisation de la t ache A, le programme ne sera donc pas r eactif : lutilisateur aura beau cliquer fr en etiquement, cela ne servira ` a rien. Dans le cas du convertisseur, cela na pas dimportance puisque la t ache A sex ecute tellement rapidement que la ( (non r eactivit e) ) de linterface nest pas perceptible. Si par contre, une des callbacks associ ee ` a un el ement graphique mettait plusieurs secondes, voire plusieurs minutes ` a sex ecuter, lutilisateur aurait pour sa part limpression que le programme est bloqu e : il se plaindra que linterface est ( (gel ee) ), ce qui est particuli` erement p enible. La solution que nous utiliserons pour pallier ce probl` eme dans Graphapp est lutilisation des timers, dont nous reparlerons plus loin. Enn, il faut etre conscient que dans un programme comme celui-ci, la machine ne fait rien la plupart du temps, except e attendre que lutilisateur daigne agir sur linterface. Les calculs sont extr emement rapides, et d` es quune callback est termin ee, la machine attend....

1. Cr eation dinterfaces graphiques

Programme Cr eation et achage des el ements graphiques de la fen etre

Utilisateur

Lutilisateur entre une une valeur num erique (150) Lutilisateur clique sur Cnversion

Lecteur de la valeur dans le champ dentr ee. Calcul du r esultat (en regardant le choix des monnaies). Achage du r esultat

Lutilisateur choisit la conversion en dollars

Lecteur de la valeur dans le champ dentr ee. Calcul du r esultat (en regardant le choix des monnaies). Achage du r esultat

Lutilisateur clique sur quitter

Le programme se termine

Fig. 1.1 Sc enario dutilisation du convertisseur

Compl ements Algo-Prog Gea 2

Utilisation de Graphapp

Une application qui utilise la biblioth` eque Graphapp poss` ede le squelette donn e dans le source 1.1. \#include<stdio.h> \#include<graphapp.h> App * app;

int app_main(int argc, char * argv[])


{ app=new_app(argc, argv); if (app == NULL) { error(app, "Impossible dinitialiser la biblioth` eque"); } main_loop(app); del_app(app); } Src. 1.1: Squelette dun programme Graphapp Notons tout dabord que la fonction app main remplace la classique fonction main pour des raisons techniques. La ligne app=new app(argc, argv) initialise la biblioth` eque et renvoie un pointeur vers une structure de donn ees renfermant des informations sur lapplication (le programme). Nous testons ensuite si cette initialisation a r eussi. Si cest le cas, nous continuons avec la fonction main loop, qui est la boucle de gestion des ev enements, interne ` a Graphapp. Cest cette proc edure qui appellera, au bon moment, les fonctions callback lorsque lutilisateur r ealisera une action. Tout le programme se ( (situe) ) dans cette boucle. Lorque le programme sort de cette boucle, cest que toutes les fen etres de lapplication ont et e ferm ees. Dans ce cas, un appel ` a la fonction del app(app) ( (rend) ) proprement la m emoire allou ee par le programme, qui se termine.

3.1

Fen etres, boutons, champs de saisie et labels

La cr eation dune fen etre se fait par linterm ediaire de la fonction new window : App * app; Window * win; app = new_app(argc, argv); ... win = new_window(app, rect(100,100,200,110), "Convertisseur", STANDARD_WINDOW); show_window(win); ... Le code pr ec edent cr ee une fen etre de largeur 200, de hauteur 110, et dont le coin sup erieur gauche est en position 100,100 sur l ecran. Son titre est ( (Convertisseur) ). Le soruce 1.2 d etaille la cr eation dune fen etre et lajout dun bouton dans cette fen etre. App * app; Window * win; Control * b; app = new_app(argc, argv); ... win = new_window(app, rect(100,100,200,110), "Convertisseur", STANDARD_WINDOW); b = new_button(win, rect(10,70,90,30), "Conversion", calcul); show_window(win); ... Src. 1.2: Ajout dune fen etre et dun bouton

1. Cr eation dinterfaces graphiques

Dans cet exemple, le bouton a son coin sup erieur gauche plac e aux coordonn ees 10,10 dans la fen etre. Il a pour largeur 90 et pour hauteur 30. Le texte inscrit dessus est ( (Conversion) ) et lorsquil sera activ e par lutilisateur, la proc edure calcul sera appel ee. Cette derni` ere devra avoir pour squelette (prototype) :

void calcul(Control *c)


{ // Choses ` a faire ici... } Le param` etre de la fonction (Control * c) est un pointeur vers un contr ole. Un contr ole, dans la biblioth` eque Graphapp, est un el ement g en erique. Ce peut etre un bouton (ce sera le cas ici), une etiquette... Le contr ole pass e en param` etre dune callback est celui qui est ` a la source de l ev enement. Lajout dun champ de saisie est r ealis e ainsi : Window * win; Control * t; ... t = new_field(win, rect(10,10,90,30), "texte"); ... Dans lexemple pr ec edent, le texte ( (texte) ) est ach e dans le champ de saisie. Un champ de saisie ne poss` ede pas de callback dans Graphapp. Son contenu doit donc etre valid e (par un bouton par exemple), pour quune action soit d eclench ee lorsque la valeur est modi ee. Le contenu dun champ de saisie est accessible par la fonction get_control_text(t) qui prend en param` etre un pointeur vers le champ de saisie et renvoie un pointeur sur une cha ne de caract` eres qui contient le texte inscrit dans le champ. Enn, pour terminer notre rapide tour dhorizon des el ements graphiques, nous ajoutons une etiquette (source 1.3). App *app; Window *win; Control *b, *t, *l; app = new_app(argc, argv); ... win = new_window(app, rect(100,100,200,110), "Convertisseur", STANDARD_WINDOW); b = new_button(win, rect(10,70,90,30), "Conversion", calcul); t = new_field(win, rect(10,10,90,30), "texte"); l = new_label(win, rect(10,40,90,30), "", ALIGN_LEFT| VALIGN_CENTER); show_window(win); ... Src. 1.3: Cr eation dune fen etre dun bouton, dun champ et dune etiquette Une etiquette nest pas un el ement actif de linterface. Lutilisateur ne peut pas agir dessus. En revanche, le programme peut changer son texte ainsi : set_control_text(l,"Coucou...");

3.2

R ealisation pratique dun convertisseur

Nous allons voir comment utiliser ce que nous avons vu an de cr eer le convertisseur de monnaie. An de r ealiser le travail proprement, nous allons : cr eer une structure qui contiendra les el ements de linterface (plut ot que davoir une multitude de variables di erentes) ; d eporter la cr eation de linterface dans une fonction s epar ee. Une premi` ere portion de code, consacr ee ` a la cr eation de linterface, est donn ee dans le source 1.4. La structure nomm ee inter, de type myinterface contiendra un pointeur vers lapplication, vers la fen etre et vers chacun des contr oles (le champ de saisie, le label et les deux boutons). La fonction app main est classique et appelle la fonction creation interface qui a pour objet de cr eer les el ements graphiques. Le seul point original de cette derni` ere fonction est lutilisation des deux variables ll et hh pour obtenir le placement des objets graphiques. Cette m ethode permet de facilement modier la taille des el ements graphiques sans avoir ` a refaire la mise en page, comme indiqu e sur la gure 1.2.

Compl ements Algo-Prog Gea 2

#include<stdio.h> #include<stdlib.h> #include<math.h> #include<graphapp.h>


// Structure qui contiendra les el ements de linterface

typedef struct
{

App * app; Window * win; Control * bouton; Control * boutonq; Control * champs; Control * etiquette; } TInterface; // D eclaration de variables globales TInterface inter; // Fonction de cr eation de linterface void creation_interface() { int ll=90; int hh=30; inter.win=new_window(inter.app, rect(100,100,2*ll+20,3*hh+20),\ "Convertisseur",STANDARD_WINDOW); inter.champs=new_field(inter.win,rect(10,10,ll,hh),""); inter.etiquette=new_label(inter.win,rect(10,10+hh,ll,hh),\ "",ALIGN_LEFT | VALIGN_CENTER); inter.bouton=new_button(inter.win,rect(10,10+2*hh,ll,hh),"Conversion",NULL); inter.boutonq=new_button(inter.win,rect(10+ll,10+2*hh,ll,hh),"Quitter",NULL); show_window(inter.win); }

int app_main(int argc, char * argv[])


{ inter.app=new_app(argc,argv); if (inter.app==NULL || inter.app->gui_available==0) { error(inter.app, "Impossible dinitialiser la biblioth` eque"); return 0; } creation_interface(); main_loop(inter.app); del_app(inter.app); return 0; } Src. 1.4: Cr eation de linterface du convertisseur

1. Cr eation dinterfaces graphiques 10 0 10+hh boutonq 10+ll 10+2ll 10+2hh 10+3hh

champ etiquette bouton 10 0

Fig. 1.2 Mise en page de linterface du convertisseur Notons aussi qu` a la place des callbacks associ ees aux boutons gure la valeur NULL, qui signie que nous nassocions pas de callback. En l etat, le programme peut etre compil e et test e. Tout y gure, mais rien ne marche encore, car nous navons pas indiqu e quoi faire en cas de lappui sur un bouton. Modions les deux lignes de cr eation des boutons en : inter.bouton=new_button(inter.win,rect(10,10+2*hh,ll,hh),\ "Conversion",calcul); inter.boutonq=new_button(inter.win,rect(10+ll,10+2*hh,ll,hh),\ "Quitter",quitter); Nous devons ` a pr esent ecrire les deux callbacks calcul et quitter (cf. source 1.5).

void quitter(Control * c)
{ ask_ok(inter.app,"Merci", "Au revoir"); hide_window(inter.win); }

void calcul(Control * c)
{

double valeur; char chaine[20];


valeur=atof(get_control_text(inter.champs)); valeur=valeur/6.55957; sprintf(chaine,"%08.2f",valeur); set_control_text(inter.etiquette,chaine);

} Src. 1.5: Callbacks utilis ees par le convertisseur Le premi` ere fonction est tr` es simple, elle ache une bo te de dialogue ayant pour titre ( (Merci) ), pour contenu ( (Au revoir)) et un bouton ( (OK) ). La fonction ask ok ne se nira que lorsque lutilisateur aura cliqu e sur le bouton ( (OK) ). Puis, la fen etre principale est cach ee. Une fois la fonction quitter termin ee, la biblioth` eque Graphapp reprend etre ont disparu. Puisque cest le cas, le la main avec sa boucle main loop, qui se termine lorsque toutes les fen programme se termine. La seconde fonction est un peu plus longue : get control text(inter.champs) renvoie une cha ne de caract` eres contenant ce qui est inscrit dans un champ de saisie. atof(get control text(inter.champs)) renvoie donc un float contenant cette valeur (suppos ee num erique), et cete valeur est stock ee dans la variable valeur. Puis, la valeur est divis ee par 6.55957. La ligne : sprintf(chaine,"%08.2f",valeur) ; a pour eet d( ( ecrire) )

Compl ements Algo-Prog Gea 2

valeur sur 8 chires, dont 2 apr` es la virgule, dans la cha ne de caract` eres chaine. Cette cha ne est pass ee en etiquette (le label). param` etre de set control text qui lache dans l En r esum e, la fonction void calcul(Control * c) regarde la valeur dans le champ de saisie, la divise par 6.55957 et ache le r esultat dans le label. On obtient donc une conversion de francs en euros. Nous voulons ` a pr esent pouvoir changer la monnaie de d epart et la monnaie darriv ee. Pour permettre le choix des monnaies, nous allons utiliser des drop down lists (listes d eroulantes) comportant le choix des unit es. Le contenu nes de caract` eres termin ee des listes se fait en donnant en param` etre ` a la fonction new drop list une liste de cha par NULL. Par exemple : Control * dl; char * monnaie[]={"Francs","Euros","Dollars",NULL}; dl=new_drop_list(inter.win,rect(10,10,90,30),monnaie,calcul); Nous obtiendrons une liste d eroulante contenant les el ements Francs, Euros et Dollars. De plus, lorsque lutilisateur fera un choix dans cette liste, la callback calcul sera appel ee. Modions la d enition de notre interface comme indiqu e dans le source 1.6.

typedef struct
{ App * app; Window * win; Control * bouton; Control * boutonq; Control * champs; Control * etiquette; Control * liste1; Control * liste2; } TInterface; // Declaration des variables globales TInterface inter; char * monnaie[]={"Francs","Euros","Dollars",NULL};

void creation_interface()
{

int ll=90; int hh=30;


inter.win=new_window(inter.app, rect(100,100,2*ll+20,3*hh+20),\ "Convertisseur",STANDARD_WINDOW); inter.champs=new_field(inter.win,rect(10,10,ll,hh),""); inter.liste1=new_drop_list(inter.win,rect(10+ll,10,ll,hh),monnaie,calcul); inter.etiquette=new_label(inter.win,rect(10,10+hh,ll,hh),\ "",ALIGN_LEFT|VALIGN_CENTER); inter.liste2=new_drop_list(inter.win,rect(10+ll,10+hh,ll,hh),\ monnaie,calcul); inter.bouton=new_button(inter.win,rect(10,10+2*hh,ll,hh),\ "Conversion",calcul); inter.boutonq=new_button(inter.win,rect(10+ll,10+2*hh,ll,hh),\ "Quitter",quitter); show_window(inter.win);

} Src. 1.6: Interface du convertisseur avec listes d eroulantes ` pr A esent, notre programme peut etre compil e et test e, sauf que la s election dun el ement dans une des listes ne modiera en rien le r esultat (mais le recalculera puisque la callback calcul est appel ee). Nous devons donc pouvoir, a partir de la s ` election des monnaies, r ecup erer les taux. La fonction qui permet de conna tre l element s electionn e dune liste est get control value(inter.liste1) qui renvoie un entier contenant lindice de l el ement s electionn e

1. Cr eation dinterfaces graphiques

(en partant de 0). Cet indice pourra nous permettre dacc eder ` a un tableau contenant les taux, si nous modions notre programme : // Declaration des variables globales myinterface inter; char * monnaie[]={"Francs","Euros","Dollars",NULL}; float taux[]={6.55,1.0,1.2}; ` pr A esent, nous pouvons r ecup erer le taux (par rapport ` a leuro) de la monnaie s electionn ee comme monnaie de d epart, en indiquant : taux[get_control_value(inter.liste1)] La conversion de la monnaie de d epart vers la monnaie darriv ee se fait en : divisant la valeur entr ee par le taux de la monnaie de d epart ; puis en multipliant le r esultat par le taux de la monnaie darriv ee. Nous navons donc plus qu` a modier en cons equence notre fonction calcul (cf. source 1.7)

void calcul(Control * c)
{

double valeur; char chaine[20];


valeur=atof(get_control_text(inter.champs)); valeur=valeur/taux[get_control_value(inter.liste1)]*\ taux[get_control_value(inter.liste2)]; sprintf(chaine,"%08.2f",valeur); set_control_text(inter.etiquette,chaine);

} Src. 1.7: Callback calcul du convertisseur utilisant la monnaie choisie

Tour dhorizon de la biblioth` eque Graphapp

La source dinformation la plus compl` ete sur la biblioth` eque Graphapp reste sa documentation, ainsi que les nombreux exemples fournis avec. Vous etes encourag es ` a consulter cette documentation le plus souvent possible. Nous allons n eanmoins ici faire un rapide tour dhorizon des possibilit es.

4.1

Objets simples

Parmi les objets ( ( el ementaires) ) g er es par Graphapp, on trouve les Points, les Rectangles, les Couleurs, les Images et les Curseurs. 4.1.1 Points

Un objet de type Point est une structure regroupant deux entiers x et y. Ce type de donn ees permet de repr esenter un point ` a l ecran. Rappelons ` a cet eet que le syst` eme de coordonn es ( (informatique) ) place lorigine dans le coin sup erieur gauche des objets, et laxe des ordonn ees vers le bas. Enn, en r` egle g en erale, les coordonn ees sont relatives ` a lobjet que lon d esigne : on parle de coordonn ees ` a l ecran pour une fen etre, de coordonn ees dans la fen etre pour un el ement graphique qui lui appartient, et de coordonn ees dans un el ement graphique pour un point dessin e sur cet el ement. Voici un exemple de code qui utilise des variables de type Point : Point p,p1; p=pt(5,8); p1.x=5; p1.y=p.y+10;

10 4.1.2 Rectangles

Compl ements Algo-Prog Gea 2

Un objet de type Rectangle est une structure regroupant 4 entiers : x, y, width et height, repr esentant respectivement les coordonn ees du coin sup erieur gauche dun rectangle, sa largeur et sa hauteur. De tels rectangles ont leurs ar etes parall` eles aux c ot es de l ecran. De nombreuses manipulations sont possibles sur les rectangles, comme tester leur egalit e, tester sils ont une intersection, si un rectangle est inclus dans un autre, ... Voici un exemple de code qui manipule des variables de type Rectangle : Rectangle r,r1; Point p; r=rect(10,10,100,50); r1=rect(20,20,40,10)); p=pt(12,12); // Teste si r1 est inclus dans r if (rect_in_rect(r1,r)) { ... } // Teste si le point est inclus dans r1 if (point_in_rect(p,r1)) { ... }

4.1.3

Couleurs

Les couleurs dans Graphapp sont d enies par leurs trois composante rouge, vert, bleu (comme cest lhabitude), ainsi que par leur composante alpha (cest le niveau de transparence). Une composante alpha ` a 0 correspond ` a une couleur compl` etement opaque, alors quune composante alpha ` a 255 correspond ` a une couleur compl` etement transparente. Une couleur est donc une structure comprenant quatre champs de type byte (ce type est aussi d eni par Graphapp et correspond ` a des entiers positifs compris entre 0 et 255) : alpha, red, green et blue. Notons cependant que la transparence, bien que support ee par le type de donn ees, nest pas implant ee dans la biblioth` eque. Nous nous contenterons donc de couleurs opaques : Colour c,c1; c=rgb(255,0,0); // Rouge c1=rgb(255,255,0); // Jaune

4.1.4

Images, curseurs

Nous ne d etaillerons pas ici le fonctionnement des images et des curseurs. Sachez n eanmoins quil est possible de copier une partie de l ecran vers une image, de d eposer une image sur une partie de l ecran, de cr eer une image ` a partir dun chier etc. Les objets relatifs ` a ces manipulations sont : Image, ImageList, ImageReader ou Bitmap. En ce qui concerne les curseurs, la structure ` a utiliser se nomme Cursor et Graphapp contient bon nombre de curseurs pr ed enis, comme lhabituelle ` eche, le curseur de texte, la croix, la main, ...

4.2

Fen etres et el ements graphiques

Nous avons d ej` a vu dans la section pr ec edente comment ouvrir une fen etre et ajouter boutons, labels, champs de saisie et listes d eroulantes dedans. Nous allons rapidement faire un tour dhorizon des autres possibilit es en nous attardant un peu sur le type Window. 4.2.1 Fen etre

Le type de donn ees se nomme Window. Nous pouvons entre autres cacher (hide window), acher (show window), d eplacer (move window) et retailler (size window) une fen etre.

1. Cr eation dinterfaces graphiques

11

Les ev enements associ es ` a une fen etre sont la fermeture (lutilisateur a cliqu e sur la croix), la modication de sa taille, ou la n ecessit e de la redessiner (par exemple parce quelle etait masqu ee par une autre fen etre et vient d etre a nouveau d ` ecouverte). Il est aussi possible de r epondre ` a la pression dune touche, et aux actions de la souris. La m ethode g en erale, pour enregistrer les callbacks, est de faire appel ` a une fonction pr ecise correspondant au type d ev enement souhait e, et ` a lui donner le nom de la fonction qui traitera ces ev enements. Si nous souhaitons par exemple tracer un point dans la fen etre lorsque lutilisateur clique, nous devons : 1. ouvrir une fen etre ; 2. indiquer le nom de la proc edure qui traitera l ev enement ( (clic souris) ); 3. ecrire cette proc edure. etre un pointeur Le point 2 correspond ` a un appel ` a la fonction on window mouse down en lui donnant en param` vers la fen etre (de type Window *) et un pointeur vers la fonction callback (de type WindowMouseFunc). Ce dernier type de donn ees est d eni dans Graphapp ainsi (voir documentation) :

typedef void (*WindowMouseFunc) (Window *w, int buttons, Point xy);


Ceci nous apprend que la fonction callback doit n ecessairement prendre 3 param` etres (un pointeur vers la fen etre, un entier et un point) et ne rien renvoyer. Le source 1.8 donne un exemple qui ache dans un terminal les coordonn ees cliqu ees (ainsi quun code correspondant aux boutons press es). 4.2.2 Autres el ements graphiques

Graphapp comprend de nombreux autres el ements graphiques. La gure 1.3 les repr esente presque tous, an que chacun puisse se faire une id ee de ce qui est possible. Le programme permettant dacher ces el ements graphiques se nomme alldemo.exe et se trouve sur vos machines.

Fig. 1.3 Divers el ements graphiques

4.3

Dessiner avec Graphapp

La biblioth` eque Graphapp poss` ede quelques fonctions de dessin permettant de r ealiser des petits programmes de visualisation. Tout trac e se fait dans un objet de type Graphics *. On peut obtenir un tel objet ` a partir dun Control, par exemple, ou dune Image (nous reparlerons du type Image plus tard). Un contexte dachage est obtenu comme indiqu e dans le source 1.9. En possession dun objet de type Graphics *, nous pouvons : choisir une couleur : set rgb(Graphics *g, Colour col) ; tracer un point : int draw point(Graphics *g, Point p) ; tracer une ligne : int draw line(Graphics *g, Point p1, Point p2) ;

12

Compl ements Algo-Prog Gea 2

/* ============================================================== Fichier clic.c Indique dans un terminal les coordonn ees du point cliqu e ================================================================= */

#include<stdio.h> #include<stdlib.h> #include<math.h> #include<graphapp.h> #ifndef WIN32 #endif typedef struct


{ App * app; Window * win; } TInterface; TInterface inter; #define app_main main

void affiche_coord(Window * win, int buttons, Point xy)


{

char buf[500];
sprintf(buf,"Coordonn ees %d %d (%d)\n",xy.x,xy.y,buttons); ask_ok(inter.app,"Clic",buf);

} {

void creation_interface()
inter.win=new_window(inter.app, rect(100,100,200,200),\ "Dessin",STANDARD_WINDOW); on_window_mouse_down(inter.win,affiche_coord); show_window(inter.win); }

int app_main(int argc, char * argv[])


{ inter.app=new_app(argc,argv); if (inter.app==NULL||inter.app->gui_available==0) { error(inter.app, "Impossible dinitialiser la biblioth` eque"); return 0; } creation_interface(); main_loop(inter.app); del_app(inter.app); return 0; } Src. 1.8: Gestion de la souris avec Graphapp

1. Cr eation dinterfaces graphiques Graphics *g; Control *c; ... g=get_control_graphics(c); .... del_graphics(g); Src. 1.9: Obtenir et rendre un contexte dachage avec Graphapp ...

13

Le contexte dachage doit etre lib er e par : del graphics(Graphics *g) ; Lextrait de programme donn e dans le source 1.10 cr ee un contr ole, obtient un contexte graphique, trace 10 lignes de couleurs al eatoires et de positions al eatoires puis rend le contexte dachage. Control *c; Graphics *g; Window *w; int i; c=new_control(w,rect(0,0,100,100)); g=get_control_graphics(c); for (i=0;i<10;i++) { set_rgb(g,rgb(rand()%256,rand()%256,rand()%256)); draw_line(g,pt(rand()%100,rand()%100),pt(rand()%100,rand()%100)); } del_graphics(g); Src. 1.10: Tracer des lignes dans un Control Lorsque le contr ole est cach e (par une autre fen etre par exemple) puis ` a nouveau d ecouvert, le syst` eme de fen etrage doit le retracer. Cette t ache incombe ` a Graphapp (cest lui qui redessine ses contr oles). Si la biblioth` eque sait retracer des boutons, des barres de d element... elle ne sait pas retracer un objet contenant des dessins quelconques. Cest donc au programmeur de donner une fonction qui retracera le contenu du contr ole. Cette fonction est indiqu ee par : on control redraw(Control *c, DrawFunc redraw). La fonction redraw doit donc etre ecrite par le programmeur :

void redraw(Control *c, Graphics *g)


{ ... } o` u g est le contexte graphique correspondant ` a la portion du contr ole ` a redessiner. Il est donc n ecessaire, lorsquon utilise un contr ole dans lequel des graphismes sont trac es, de m emoriser le dessin ` a acher. En r` egle g en erale, on ne trace donc pas directement dans le contr ole, mais dans une image. Chaque fois quun r eachage est n ecessaire, limage est recopi ee sur le contr ole. La cr eation dune image est simple : Image *img; img=new_image(100,100,32); Le code pr ec edent cr ee une image de taille 100 par 100, et de profondeur 32 bits par pixel (couleurs r eelles). Le trac e dans une image se fait de la m eme mani` ere que pour un contr ole. Lobtention dun contexte graphique est r ealis ee par : Graphics * get image graphics(Image *img) ; Le code suivant, en supposant que le contr ole et limage sont de m emes dimensions, recopie cette derni` ere sur le premier :

void redraw(Control *c, Image *img)


{

14

Compl ements Algo-Prog Gea 2

Graphics *g; g=get_control_graphics(c); draw_image(g,rect(0,0,c->area.width,c->area.height),img,get_image_area(img)); del_graphics(g); } Pour terminer, notons quil existe une assez grande vari et e de fonctions graphiques, permettant de dessiner des rectangles, des rectangles remplis, des lignes, des ellipses, des arcs de cercle, des lignes bris ees ou du texte (consulter la documentation)...

4.4

Timers

Un timer permet de faire ex ecuter une certaine fonction ` a intervalles r ep et es. D` es que notre programme contient une t ache ` a ex ecuter un peu longue, qui ne doit pas bloquer linterface utilisateur, nous devons utiliser des timers. La d enition dun timer se fait ainsi : Timer *t; App * app; ... t=new_timer(app,fonc_timer,100); La fonction new timer cr ee un nouveau timer, qui appellera automatiquement la fonction fonc timer toutes les 100 millisecondes. La fonction fonc timer doit avoir pour squelette :

void fonc_timer(Timer *t)


{ ... } Supposons que nous voulions faire un petit programme de visualisation style ( (oscilloscope) ), cest ` a dire compos e dun spot, qui repr esente une certaine grandeur, et qui parcourt l ecran. Supposons de plus que cette grandeur soit sinuso dale et que nous d esirions pouvoir utiliser deux boutons pour modier la vitesse ` a laquelle se d eplace le spot. Le d eplacement du spot ` a l ecran doit ( (apparemment) ) se d erouler en m eme temps que Graphapp scrute les ev enements en provenance de linterface :

Nous voudrions que le programme fonctionne comme indiqu e sur la gure 1.4. Or ce nest pas possible, car le programme ne peut pas g erer en m eme temps linterface graphique et le spot. La solution consiste ` a appliquer le principe de la gure 1.5. Le programme utilise alors son temps dattente (les pointill es) pour de temps ` a autre ex ecuter une fonction qui fera l eg` erement bouger le spot. La fonction fonc timer ressemblera donc ` a celle don e dans le source 1.11.

1. Cr eation dinterfaces graphiques Spot ` a l ecran Le spot se d eplace continuellement ` a l ecran en utilisant la valeur de la fr equence cournate Programme Cr ation et achage des el ements graphiques de la fen etre Utilisateur

15

Lutilisateur clique sur V++

Lintervalle Dt est divis e par 1.2

Lutilisateur clique sur V--

Lintervalle Dt est multipli e par 1.2

Lutilisateur clique sur quitter

Le programme se termine

Fig. 1.4 Fonctionnement id eal

void fonc_timer(Timer * t)
{

int valx,valy;
Graphics *g; valy=sin(temps)*100+150; valx=temps/6.28*300; g=get_control_graphics(inter.c); set_rgb(g,rgb(0,0,0)); fill_rect(g,rect(0,0,300,300)); set_rgb(g,rgb(30,255,50)); fill_ellipse(g,rect(valx-2,valy-2,4,4)); del_graphics(g); temps=temps+deltat; if (temps>6.28) temps=temps-6.28;

} Src. 1.11: Utilisation dun timer avec Graphapp (premi` ere partie)

16

Compl ements Algo-Prog Gea 2

Programme Cr ation et achage des el ements graphiques de la fen etre D eplacer le spot D eplacer le spot

Utilisateur

Lutilisateur clique sur V++ Lintervalle Dt est divis e par 1.2 D eplacer le spot D eplacer le spot D eplacer le spot Lutilisateur clique sur quitter Le programme se termine

Fig. 1.5 Fonctionnement r eel

1. Cr eation dinterfaces graphiques

17

Cette fonction est assez simple ` a comprendre. Elle utilise deux variables globales temps et deltat repr esentant respectivement le temps et laugmentation de largument de la fonction sinus ` a chaque appel de fonc timer. Par cons equent, il sut daugmenter deltat pour avoir limpression que le point se d eplace plus vite, et inversement. Le reste du programme est donn e dans le source 1.12.

4.5
4.5.1

Bo tes de dialogues
Bo tes standard

Graphapp contient quelques bo tes de dialogues pr ed enies, pour faciliter le travail du programmeur. Ces bo tes eponse armative ou n egative (ask yes no), de permettent dacher un message (ask ok), de demander une r demander une cha ne de caract` eres (ask string), ou de s electionner un chier (ask file open et ask file save). Deux de ces bo tes sont repr esent ees dans la gure 1.6.

char * tmp; tmp=ask strings(inter.app,"Question ?","Entrez votre nom",0);

char * tmp; tmp=ask file open(inter.app,"Ouvrir un fichier","Ouvrir","/");

Fig. 1.6 Exemples de bo tes de dialogues

4.5.2

Console de debuggage

Lutilisation de Graphapp sous Windows ne permet pas de disposer de la fonction printf qui permet dans bien des cas de trouver des erreurs dans les programmes en achant les valeurs de variables ou des messages indicatifs. Ce probl` eme peut etre contourn e en utilisant la console de debuggage2 . La fonction open debug(inter.app) ouvre la console de debuggage. On dispose alors dune fonction nomm ee ` la n dun debugprintf, qui fonctionne exactement comme printf mais ache dans la fen etre de debuggage. A programme, il faut refermer la fen etre de debuggage ainsi : ... main_loop(inter.app); close_debug(); del_app(inter.app);

Graphapp et Dev-C++

Pour compiler un programme utilisant Graphapp avec Dev-C++, il faut disposer des chiers den-t ete app.h, debug window.h et graphapp.h, ainsi que de la version statique de la biblioth` eque libgraphapp.a Si les chiers ne sont pas ` a lemplacement standard (par exemple les r epertoires c :/Dev-Cpp/include et c :/Dev-Cpp/lib) le param etrage de Dev-C++ doit etre fait comme indiqu e dans les bo tes 1 et 2 de lannexe. Dans la bo te 3 de la m eme annexe, la ligne -lgraphapp doit gurer dans la partie Editeur de liens.

2 La

console de debuggage ne gure pas dans le manuel, car elle a et e d evelopp ee localement.

18

Compl ements Algo-Prog Gea 2

typedef struct
{ App * app; Window * win; Control *c; // Zone de trac e Control * pp; // Bouton ++ Control * pm; // Bouton -} Tinterface; TInterface inter; // Les deux variables globales float temps; float deltat; // Callback appel ee lors de lappui sur un des deux boutons // Notez comment sy prendre pour regarder lequel des deux boutons a // provoqu e l ev` enement void deltat_cb(Control * c) { if (c==inter.pp) deltat*=1.2; else deltat/=1.2; }

void creation_interface()
{ inter.win=new_window(inter.app, rect(100,100,300,330),\ "Oscillo",STANDARD_WINDOW); inter.c=new_control(inter.win,rect(0,0,300,300)); inter.pp=new_button(inter.win,rect(0,302,150,25),"V++",deltat_cb); inter.pm=new_button(inter.win,rect(150,302,150,25),"V--",deltat_cb); show_window(inter.win); }

int app_main(int argc, char * arg[])


{ Timer *t; inter.app=new_app(argc,argv); if (inter.app==NULL||[]inter.app->gui_available==0) { error(inter.app, "Impossible dinitialiser la biblioth` eque"); return 0; } creation_interface(); temps=0; deltat=0.01; // Le timer est d emarr e avec une p eriode dappel de 10ms t=new_timer(inter.app,fonc_timer,10); main_loop(inter.app); del_app(inter.app); return 0; } Src. 1.12: Utilisation dun timer avec Graphapp (deuxi` eme partie)