c
TD X-Window numero 2: un afficheur de graphes
A faire avant de commencer:
- Recopier le squelette du TD chez vous. Créez un directory
xlib/td2 sous votre $HOME (ou ailleurs) et recopierz dedans tous
les fichiers qui se trouvent dans le répertoire
/u/profs/devernay/www/cours/IHM/td2/ .
- Etudier le Makefile.
- Etudier les fichiers sources qui vous sont fournis. Certains
sont prêts à l'emploi comme graphe.h et grapheIO.c, d'autres sont à
complèter comme graphe.c et display.c
- Etudier les fichiers sample.g et sample2.g qui sont des
fichiers ASCII contenant des descriptions de graphes.
But du TD:
Nous allons écrire ensemble un petit programme graphique permettant
de lire des graphes, de les visualiser et de les manipuler
interactivement.
Vous pouvez tester, avant de commencer, le programme binaire
graphe_corrige afin d'avoir une idée plus précise de ce que vous
devez réaliser.
Le source corrigé sera disponible à la fin du TD.
Pour essayer le binaire fourni :
Lancer la commande :
graphe_corrige < sample2.g <return>
Important:
- Comme d'habitude, référez-vous au cours
Xlib pour y voir plus clair!
- Utilisez les manuels! Pour chaque fonction que vous ne
connaissez pas, consultez le man, soit dans un xterm, soit en
utilisant le mode man de emacs (ESC-X man), soit avec xman,
enfin... utilisez un peu ce que vous voulez mais apprenez à
utiliser les manuels !.
- Si vraiment vous ne trouvez pas ce que vous cherchez dans les
manuels, essayez de regarder dans /usr/include/X11/Xlib.h, dans
/usr/include/X11/X.h ou bien appelez-moi!
Différentes étapes dans ce TD:
- Prendre le temps d'étudier les sources et les fichiers de
description des graphes qui sont fournis. Il est nécessaire que
vous ayez une idée générale de ce que vous allez devoir
réaliser.
- Ecrire petit à petit les parties de code manquantes
dans le fichier graphe.c, puis dans le fichier display.c
Code à écrire dans le fichier graphe.c :
- Pour l'ouverture du display, référez-vous au TD précédent et/ou
à la partie du cours sur le
Display.
- Le chargement d'une police de caractères se fait à l'aide de la
fonction XLoadQueryFont(), voir la
partie du cours concernant l'affichage de texte. Penser à
traiter le cas où le serveur ne trouve pas la fonte de caractères
spécifiée.
- Le calcul de la taille des noeuds du graphe en fonction de la
police de caractères chargée se fera en appelant la fonction
FixGraphLabelDimensions() qui se trouve dans le fichier
display.c
- Créer une fenêtre d'affichage. Voir le TD précédent et la partie du cours sur les
fenêtres. Etudiez l'exécution du programme graphe_corrige et
déduisez les événements minimums que la fenêtre devra gérer (aide:
il y en a 4).
- Créer trois contextes graphiques
(GC).
- Le premier, que j'ai appelé fill_gc servira pour les
appels à XfillRectangle()
qui seront utilisés pour dessiner les noeuds du graphe;
- Le second draw_gc servira à dessiner le texte et le
cadre des noeuds;
- Le troisième, xor_gc servira lorsqu'on déplacera la
noeuds à la souris pour effacer les anciennes parties du graphe. Il
faudra positionner le champ function de la structure
XGCValues que j'ai appelée gcv dans le source.
- Gérer les événements :
- Appui du bouton 1 de la souris (fonction =
séléctionner un noeud du graphe pour le déplacer) :
- Trouver le noeud dans lequel le click souris a eu lieu. Cela se
fait en appelant la fonction FindNode() qui se trouve dans le
fichier display.c. tester la valeur de retour car il se peut que le
click n'ait pas eu lieu dans un noeud.
- Si le click a bien eu lieu dans un noeud, appeler la fonction
RelatedEdges(graph, node) qui se trouve dans le fichier graphIO.c.
Cette fonction retourne la liste des arcs (edges) reliés au noeud
(node) passé en paramètre. Cette liste sera utilisée pour
redessiner ces arcs pendant le déplacement du noeud.
- Déplacement de la souris bouton 1 appuyé
(fonction = déplacer un noeud et les arcs qui lui sont reliés avec
un effet "élastique") :
- Je vous laisse vous débrouiller ! Aide : utilisez les fonctions
DisplayNode() et DisplayEdges() qui se trouvent dans le fichier
display.c et utilisez à bon escient les contextes graphiques
disponibles.
- Relâche du bouton 1 : (fonction = redessiner
le graphe s'il y a eu un déplacement de noeud)
- Tester la valeur de la variable selected_node pour voir s'il
faut redessiner le graphe.
- Effacer la fenêtre.
- Afficher le graphe (utiliser la fonction DisplayGraph(graph,
dpy, win, draw_gc, fill_gc) qui se trouve dans le fichier
display.c).
- Libérer la liste des arcs reliés au noeud séléctionné en
utilisant la fonction FreeEdges(related_edges) qui se trouve dans
graphIO.c
- Appui du bouton 2 de la souris (fonction =
print_graph) :
- Appeler la fonction PrintGraph(graph, stdout) qui se trouve
dans le fichier graphIO.c. Cette fonction affiche dans un xterm le
contenu du fichier de description du graphe.
- Appui du bouton 3 de la souris : fin du
programme.
Code à écrire dans le fichier display.c :
- DisplayGraph(graph, dpy, window, draw_gc, fill_gc) :
- Pas bien difficile. Regardez comment s'appellent les fonctions
suivantes dans le fichier! Deux lignes suffisent !
typedef struct _Graph {
char *title; /* symbolic */
Node nodes; /* null-terminated list */
Edge edges; /* null-terminated list */
} *Graph;
- DisplayNode(node, dpy, window, draw_gc, fill_gc) :
typedef struct _Node {
int id; /* unique identifier (number) */
int x; /* position */
int y;
int width; /* to be calculated */
int height; /* to be calculated */
char *label; /* text to be displayed */
int baseline_x;
int baseline_y;
struct _Node *next; /* next node in graph */
} *Node;
- DisplayEdge(edge, dpy, window, gc) :
- Pas de commentaires ! Un arc c'est une l.... ! Etudiez la
structure Edge pour obtenir les coordonnées des extrêmités de l'arc
passé en paramètre.
typedef struct _Edge {
int id; /* unique identifier (number) */
int from_id; /* nodes connected by id */
int to_id;
Node from; /* the nodes themselves */
Node to;
struct _Edge *next; /* next edge in graph */
} *Edge;
- Node FindNode(graph, x, y) :
- Retourner le premier node dont la bounding box contient le
point (x,y). Utilisez la macro NodeContains(nodes, x, y) qui est
définie dans le fichier display.c
Source du squelette du TD et Makefile :
Squelette du TD :
michel.buffa@essi.fr