C. RECANATI

Interfaces Graphiques

ILOG 2,  septembre 2004

 

 

 

 

 

TP n°4 : fin Xlib et début Motif

 

Exercice 1: Finir l’exercice 2 du TP précédent (programme Menu.c), et me l’envoyer par mail, en binôme ou en solo, à

 cathy@lipn.univ-paris13.fr. Faites figurer vos noms dans le mail, et en tête du fichier C.

 

Exercice 2: (programme editeur.c)

1) Créez une fenêtre blanche et une fille de même fond que vous placerez dans la mère de sorte qu’elle occupe la moitié inférieure. Modifiez l’attribut cursor de la fille pour que la souris change de forme quand elle entre dans cette fenêtre.

(#include <X11/cursorfont.h> pour utiliser un nom de curseur en argument de XCreateFontCursor).

2) Dans la partie supérieure (la mère), vous afficherez un titre au centre avec XDrawImageString, une fonte assez large et les deux couleurs de votre choix.

 3) Dans la partie inférieure (la fille), vous éditerez sur une ligne en noir les caractères lus au clavier. Le caractère Return effacera la ligne courante et les caractères Delete et Backspace permettront de reculer.

F   A chaque entrée d’un caractère, on efface la ligne courante (effacer = afficher en inverse video), et on met à jour le tampon qui mémorise la ligne, puis on réaffiche intégralement la ligne correctement mise à jour. Cela évite d’avoir à positionner les caractères un à un.

 

Exercice 3: (exercice pushButton.c)

Tester le premier programme du cours MOTIF. Compilation : gcc exo.c –lXm –lXt –lX11

 

Exercice 4: (exercice rowColumn.c + fichiers de ressources)

Faire un programme qui crée 6 ToggleButton à l’intérieur d’un RowColumn (lui-même placé dans le widget de plus haut niveau). Essayer le programme tel quel, puis charger des fichiers de ressources à l’aide de la commande xrdb pour modifier les ressources des widgets du programme (sans le recompiler !), de façon à :

         1) positionner les 6 boutons sur deux colonnes (modifier les ressources numColumns et packing du RowColumn dans un fichier de ressource).

         2) modifier la fonte d’un des boutons (avec 9x15 par exemple).

         3) modifier le deuxième bouton pour qu’il affiche un Pixmap au lieu d’une chaîne. (cf. labelPixmap et labelType hérités de Label).

F   Pour la ressource labelPixmap, on peut donner l’adresse complète d’un fichier au format bitmap.  (Dans /usr/include/X11/bitmaps il y a des fichiers au format bitmap, et vous pouvez en créer avec bitmap).

         4) afficher tous les boutons horizontalement.

         5) modifier les ressources du RowColumn pour que ces boutons aient un comportement de boutons radios. (cf. radioBehavior et radioAlwaysOne).

 

---------------------

Exercice 2 du TP 3: (programme Menu.c)

Dans une fenêtre initiale, on veut faire apparaître un popup menu proposant un choix d’items. Le nom de la fonte utilisée pour écrire les items pourra être passée en argument au programme, ou on utilisera la fonte par défaut. La taille du menu sera fonction de cette fonte. Le menu n’est pas affiché initialement, mais apparaît sous la souris quand on clique dans la fenêtre principale. Une fois le menu apparu, on peut maintenir le bouton de la souris enfoncé, et la faire glisser sur les différents items. L’item sur lequel se trouve la souris est alors peint en inverse video (en réalité on dessine un rectangle plein en inverse video - ce qui fait à la fois apparaître le fond et le texte en inverse - mais il n’y a pas réécriture à proprement parler du texte de l’item). Quand on relâche la souris sur un item, le texte correspondant à l’item ainsi « sélectionné » est imprimé à la console. Si on relâche la souris à l’extérieur du menu, on n’imprime rien. Dans les deux cas, une fois la souris relâchée, le menu disparaît.

 

 Indications : 1) La hauteur des items et celle de la fenêtre menu sont paramétrées par la hauteur de la fonte et le nombre d’items. On commence par charger la fonte et les informations  sur la fonte. Une fois la hauteur de fonte déterminée, on peut calculer la hauteur du menu en fonction du nombre d’items. Pour sa largeur, on calculera la largeur maximum des différentes chaînes d’items dans cette fonte (avec XTextWidth).

 

2) On utilise trois variables de type Window : une pour la fenêtre principale (win), une pour le fond de la fenêtre du menu (menu), et une autre variable (w) pour définir de petites fenêtres de classe InputOnly permettant de repérer les mouvements de la souris sur les items. Ces fenêtres « transparentes » sont positionnées au dessus des items et permettent de savoir quand la souris pénètre sur un item. Elles permettent de sélectionner des événements d’entrée/sortie de la souris, mais on ne dessine pas dedans. Tous les dessins seront effectués directement dans la fenêtre menu. Quand la fenêtre menu est exposée initialement, on y dessine tous les textes d’items. Quand la souris entre ou sort d’une sous-fenêtre w délimitant un item, on peindra dans la fenêtre menu un rectangle en inverse video à la hauteur concernée.

 

Les fenêtres InputOnly seront créées dans une boucle utilisant toujours la même variable w. Un contexte d’association (XContext) permet de sauvegarder après chaque création (et avant la suivante) : 1. la position initiale en y de cette fenêtre, et  2. l’item correspondant. Pour mémoriser et associer ces informations à chaque fenêtre, on utilisera un tableau de structures contenant de telles paires.  Ainsi, dans la boucle de création, on associe à chaque fenêtre (via le contexte) l’adresse de la structure correspondante [oubien simplement un entier qui serait l’indice correspondant aux données de cette fenêtre dans le tableau].

 

Dans la boucle de gestion des événements, connaissant la fenêtre qui a reçu un événement de type EnterNotify ou LeaveNotify, on peut récupérer, grâce au contexte d’association, les informations permettant d’identifier l’item et sa position dans le menu. On peut alors repeindre un rectangle en inverse video, pour sélectionner l’item ou pour le désélectionner.

 

Le programme a donc l’allure suivante :

char * items[] = { « premier item »,

                            « deuxième »,

                                    …,

                            « dernier »} ;

#define NITEM sizeof(items)/sizeof(char*)

typedef struct {

       int pos_y ;

       char* string ;

} infos ;

infos tab[NITEM] ;

 

void main(argc, argv) {

       Window win, menu, root, w ;

// charger et récupérer les infos sur la fonte

// XLoadQueryFont (ou XLoadFont et XQueryFont)

// puis déterminer la largeur et la hauteur de la fenêtre menu

 

// créer un contexte graphique  gc ayant cette fonte

// et un contexte graphique  gc_invert permettant

// de faire de l’inverse video

 

// créer un contexte d’association (XContext)  context

// pour gérer les données associées aux sous-fenêtres  w

 

// ENSUITE SEULEMENT !

// créer win et menu

// sélectionner  ButtonPress sur win (pour afficher le menu)

// sélectionner Expose sur menu (pour écrire les items)

 

// création des sous-fenêtres InputOnly

       for (i=0 ; i<NITEM ; i++) {

              w = XCreateWindow(…,x, yi , …) ;

              // selectionner les ev. EnterNotify et LeaveNotify

              XSelectInput(dpy, w,  …) ;

              tab[i].pos_y = yi ; // sauvegarde la position en y

              tab[i].string =  item[i] ; // et la chaîne associée

              XSaveContext(dpy, context, w, …);

       }

 

// afficher win et les sous-fenêtres de menu

// mais ne pas afficher menu

 

       events() ;     

}

 

F   Attention : sur un clic de souris, il y a un monopole (grab) automatique de la souris pour la fenêtre qui a sélectionné l’événement  ButtonPress. Il faut donc ici empêcher cette saisie automatique au niveau de l’application (en ajoutant OwnerGrabButtonMask à  ButtonPressMask), car sinon les sous-fenêtres w ne recevront pas les événements souris d’entrée/sortie. En effet, en l’absence de OwnerGrabButtonMask la fenêtre win monopolise la souris et les autres fenêtres ne reçoivent plus d’événements.