Le widget de type Form


Dernière modification le 4/11/96

Table des matières

Introduction

Après le RowColumn relativement simple à utiliser, le widget de type Form est l'autre widget "container" proposé par Motif.

Par rapport au RowColumn, le widget de type Form permet un contrôle plus précis et plus puissant du positionnement géométrique des widgets fils, au prix d'une certaine complexité d'utilisation. Avec un Form, les widgets fils peuvent avoir des tailles différentes et on peut leur donner des attachements relatifs les uns par rapport aux autres.

Le positionnement des widgets fils dans un Form Widget peut être réalisé de plusieurs manières. Examinons tout d'abord trois petits programmes form1.c, form2.c et form3.c qui utilisent trois approches différentes pour produire le même résultat :

Attachement simple des widgets fils

Remarque : lorsqu'un widget est créé dans une Form, il hérite de nouveaux attributs qu'il ne possède pas naturellement.

Ces attributs concernent son positionnement à l'intérieur de la Form. Parmi ceux-ci, certains attributs servent à attacher le widget à ses widgets voisins dans la Form, ou bien directement aux bords de la Form.

Les ressources concernant l'attachement sont les suivantes :

Les valeurs possibles sont :

Dans l'exemple suivant les widgets fils sont placés dans une Form en précisant pour chaque widget son attachement soit à un ou plusieurs côtés de la Form, soit à d'autres widgets.

Le programme form1.c

On créé quatre boutons dans une Form :



#include <Xm/Xm.h> 
#include <Xm/PushB.h> 
#include <Xm/Form.h> 

main (int argc, char **argv)  
{ 
  XtAppContext app;
  Widget top_widget, form, button1, button2, button3, button4;
  int n=0;
  Arg args[10];  
        
  top_widget = XtVaAppInitialize(&app, "form1", NULL, 0, 
                                 &argc, argv, NULL, NULL);

  n=0;
  form = XmCreateForm(top_widget, "form", args, n);
  XtManageChild(form);

  n=0;
  /* bouton 1 : bords haut et gauche attachés à la Form */
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  button1 = XmCreatePushButton(form, "button1", args, n);
  XtManageChild(button1);

  n=0;
  /* bouton 2: bords haut  attaché au bouton 1, bas et gauche 
     à la Form */
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(args[n], XmNtopWidget, button1); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  button2 = XmCreatePushButton(form, "button2", args, n);
  XtManageChild(button2);

  n=0;
  /* bouton 3: bords gauche  attaché au bouton 1, haut et 
     droite à la Form */
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(args[n], XmNleftWidget, button1); n++;
  button3 = XmCreatePushButton(form, "button3", args, n);
  XtManageChild(button3);

  n=0;
  /* bouton 4: bords haut attaché au bouton 3, gauche au bouton 2, 
     bas et droite à la Form */
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(args[n], XmNtopWidget, button3); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(args[n], XmNleftWidget, button2); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  button4 = XmCreatePushButton(form, "button4", args, n);
  XtManageChild(button4);

  XtRealizeWidget(top_widget);
  XtAppMainLoop(app);
}


Remarque : pour compiler sans erreur il faut inclure le fichier <Xm/Form.h>.

Attachement à des positions prédéfinies dans la Form

Il est possible de positionner un widget à un endroit particulier dans une Form sans l'attacher à un autre widget. En effet, MOTIF suppose qu'une Form est découpée en segments verticaux et horizontaux formant une grille régulière. La position d'un widget pourra ainsi être spécifiée en indiquant un nombre de segments à partir du coin en haut à gauche de la Form.

Par défaut une Form possède 100 divisions horizontales et verticales. On peut changer cette valeur à l'aide de la ressource XmNfractionBase.

La position d'un côté particulier d'un widget dans une Form sera précisée à l'aide des ressources d'attachement vues précédemment XmNtopAttachment, XmNbottomAttachment, etc..., simplement on leur donnera une nouvelle valeur : XmATTACH_POSITION.

Il faudra ensuite positionner la ressource correspondante XmNtopPosition, XmNbottomPosition, etc... à la valeur désirée (un entier).

Le programme form2.c

Dans cet exemple nous allons indiquer la position des différents boutons de la manière suivante :



#include <Xm/Xm.h> 
#include <Xm/PushB.h> 
#include <Xm/Form.h> 
 
  
main (int argc, char **argv)  
{ 
  XtAppContext app;
  Widget top_widget, form, button1, button2, button3, button4;
  int n=0;
  Arg args[10];  
        
  top_widget = XtVaAppInitialize(&app, "form1", NULL, 0, 
                                 &argc, argv, NULL, NULL);

  n=0;
  form = XmCreateForm(top_widget, "form", args, n);
  XtManageChild(form);

  n=0;
  /* bouton 1 : bords haut et gauche attachés à la Form, 
     bords droit et bas a la position 50/100 */
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNrightPosition, 50); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNbottomPosition, 50); n++;
  button1 = XmCreatePushButton(form, "button1", args, n);
  XtManageChild(button1);

  n=0;
  /* bouton 2: bords bas et gauche attachés à  la Form, 
     droit et haut à la position 50/100  */
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNrightPosition, 50); n++;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtopPosition, 50); n++;
  button2 = XmCreatePushButton(form, "button2", args, n);
  XtManageChild(button2);

  n=0;
  /* bouton 3: bords haut et droit attachés à la Form, 
     bas et gauche à la position 50/100 */
     
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNleftPosition, 50); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNbottomPosition, 50); n++;
  button3 = XmCreatePushButton(form, "button3", args, n);
  XtManageChild(button3);

  n=0;
  /* bouton 4: bas et droit attachés à la Form, 
     haut et gauche à la position 50/100 */
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNleftPosition, 50); n++;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtopPosition, 50); n++;
  button4 = XmCreatePushButton(form, "button4", args, n);
  XtManageChild(button4);

  XtRealizeWidget(top_widget);
  XtAppMainLoop(app);
}


Remarque : essayez de modifier à l'aide du window manager la taille de la fenêtre correspondant aux programmes form1 et form2 obtenus à partir des sources présentées ici.

Les exécutables se trouvent dans :

    /home/profs/cours/minfo/motif/forms/form1 et 
    /home/profs/cours/minfo/motif/forms/form2

Attachements opposés

L'attachement opposé est un autre moyen d'attacher les bords d'un widget.

On réalise un tel attachement en positionnant comme auparavant les ressources XmntopAttachment, XmNbottomAttachment, etc... mais cette fois-ci on leur donne la valeur XmATTACH_OPPOSITE_WIDGET. On précisera le widget auquel on s'attache à l'aide de la ressource XmNwidget déjà étudiée.

Remarque : avec ce type d'attachement "opposé", on attache les côtés "similaires". Au lieu de dire "Je vais attacher le bord droit de mon widget au bord gauche du widget voisin", on va dire "J'attache le bord droit de mon widget au bord droit d'un autre widget de manière à ce qu'ils soient alignés.

Le programme form3.c

Cet exemple produit exactement le même résultat que le programme form2.c. Seules les ressources des widgets button2 et button4 ont été modifiées. Pour button2 on a indiqué que l'on voulait son bord droit aligné avec celui de button1. Pour button4, on a indiqué que l'on voulait son bord gauche aligné avec celui de button3.



#include <Xm/Xm.h> 
#include <Xm/PushB.h> 
#include <Xm/Form.h> 
 
  
main (int argc, char **argv)  
{ 
  XtAppContext app;
  Widget top_widget, form, button1, button2, button3, button4;
  int n=0;
  Arg args[10];  
        
  top_widget = XtVaAppInitialize(&app, "form1", NULL, 0, 
                                 &argc, argv, NULL, NULL);

  n=0;
  form = XmCreateForm(top_widget, "form", args, n);
  XtManageChild(form);

  n=0;
  /* bouton 1 : bords haut et gauche attachés à la Form, 
     bords droit et bas a la position 50/100 */
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNrightPosition, 50); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNbottomPosition, 50); n++;
  button1 = XmCreatePushButton(form, "button1", args, n);
  XtManageChild(button1);

  n=0;
  /* bouton 2: bords bas et gauche attachés à  la Form, 
     droit et haut à la position 50/100  */
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(args[n], XmNrightWidget, button1); n++;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtopPosition, 50); n++;
  button2 = XmCreatePushButton(form, "button2", args, n);
  XtManageChild(button2);

  n=0;
  /* bouton 3: bords haut et droit attachés à la Form, 
     bas et gauche à la position 50/100 */
     
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNleftPosition, 50); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNbottomPosition, 50); n++;
  button3 = XmCreatePushButton(form, "button3", args, n);
  XtManageChild(button3);

  n=0;
  /* bouton 4: bas et droit attachés à la Form, 
     haut et gauche à la position 50/100 */
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
  XtSetArg(args[n], XmNleftWidget, button3); n++;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtopPosition, 50); n++;
  button4 = XmCreatePushButton(form, "button4", args, n);
  XtManageChild(button4);

  XtRealizeWidget(top_widget);
  XtAppMainLoop(app);
}


Un exemple plus complet

Nous terminerons l'étude des widgets de type Form avec cet exemple. Nous allons créer une Form contenant deux types de widgets différents. Nous allons également utiliser des fonctions de callbacks.

Ce petit programme s'appelle arrows.c. Il crée quatre widgets de type ArrowButton autour d'un PushButton labellé "Quit" :

Lorsqu'on clique sur les boutons ils affichent simplement un message sur stdout.

Ce petit programme utilise une astuce : la ressource XmNfractionBase de la Form est positionnée à 3. Ceci crée une grille de 3 x 3 cases qui est plus facile à manipuler dans ce cas précis.

Le programme arrows.c



#include <Xm/Xm.h> 
#include <Xm/PushB.h> 
#include <Xm/ArrowB.h> 
#include <Xm/Form.h> 
 
void north(), south(), east(), west(), quitb();
  
/*------------------------------------------*/
main (int argc, char **argv)  
/*------------------------------------------*/
{ 
  XtAppContext app;
  Widget top_widget, form, arrow1, arrow2, arrow3, arrow4, quit;
  int n=0;
  Arg args[10];  
        
  top_widget = XtVaAppInitialize(&app, "form1", NULL, 0, 
                                 &argc, argv, NULL, NULL);

  n=0;
  XtSetArg(args[n], XmNfractionBase, 3); n++;
  form = XmCreateForm(top_widget, "form", args, n);
  XtManageChild(form);

  n=0;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtop, 0); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNbottomPosition, 1); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNleftPosition, 1); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNrightPosition, 2); n++;
  XtSetArg(args[n], XmNarrowDirection,   XmARROW_UP); n++;
  arrow1 = XmCreateArrowButton(form, "arrow1", args, n);
  XtAddCallback(arrow1, XmNactivateCallback, north, NULL);
  XtManageChild(arrow1);


  n=0;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtopPosition, 1); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNbottomPosition, 2); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNleftPosition, 0); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNrightPosition, 1); n++;
  XtSetArg(args[n], XmNarrowDirection,   XmARROW_LEFT); n++;
  arrow2 = XmCreateArrowButton(form, "arrow2", args, n);
  XtAddCallback(arrow2, XmNactivateCallback, west, NULL);
  XtManageChild(arrow2);

  n=0;
  /* bouton 3: bords haut et droit attachés à la Form, 
     bas et gauche à la position 50/100 */
     
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtopPosition, 1); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNbottomPosition, 2); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNleftPosition, 2); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNrightPosition, 3); n++;
  XtSetArg(args[n], XmNarrowDirection,   XmARROW_RIGHT); n++;
  arrow3 = XmCreateArrowButton(form, "arrow3", args, n);
  XtAddCallback(arrow3, XmNactivateCallback, east, NULL);
  XtManageChild(arrow3);

  n=0;
  /* bouton 4: bas et droit attachés à la Form, 
     haut et gauche à la position 50/100 */
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtopPosition, 2); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNbottomPosition, 3); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNleftPosition, 1); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNrightPosition, 2); n++;
  XtSetArg(args[n], XmNarrowDirection,   XmARROW_DOWN); n++;
  arrow4 = XmCreateArrowButton(form, "arrow4", args, n);
  XtAddCallback(arrow4, XmNactivateCallback, south, NULL);
  XtManageChild(arrow4);

  n=0;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtopPosition, 1); n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNbottomPosition, 2); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNleftPosition, 1); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNrightPosition, 2); n++;
  quit = XmCreatePushButton(form, "quit", args, n);
  XtAddCallback(quit, XmNactivateCallback, quitb, NULL);
  XtManageChild(quit);

  XtRealizeWidget(top_widget);
  XtAppMainLoop(app);
}

/* CALLBACKS */
/*------------------------------------------*/
void north(Widget w, XtPointer client_data, 
           XmPushButtonCallbackStruct *cbs)
/*------------------------------------------*/
{ 
  printf("Going North\n");
}

/*------------------------------------------*/
void west(Widget w, XtPointer client_data, 
          XmPushButtonCallbackStruct *cbs)
/*------------------------------------------*/
{ 
  printf("Going West\n");
}

/*------------------------------------------*/
void east(Widget w, XtPointer client_data, 
          XmPushButtonCallbackStruct *cbs)
/*------------------------------------------*/
{ 
  printf("Going East\n");
}

/*------------------------------------------*/
void south(Widget w, XtPointer client_data, 
           XmPushButtonCallbackStruct *cbs)

/*------------------------------------------*/
{ 
  printf("Going South\n");
}

/*------------------------------------------*/
void quitb(Widget w, XtPointer client_data, 
           XmPushButtonCallbackStruct *cbs)
/*------------------------------------------*/

{ 
  printf("quit button pressed\n");
  exit(0);
}




michel.buffa@essi.fr