Le Widget de type MainWindow, les Menus


Dernière modification le 12/11/96

Table des matières


Introduction

Dans cette section nous allons étudier un autre type de "container", le widget de type MainWindow. Nous étudierons particulièrement les relations entre les widgets de ce type et les différents menus. Nous verrons qu'il est également possible de mettre d'autre types de widgets dans une MainWindow.

Le widget de type MainWindow

Généralités

D`après le Motif Style Guide, le widget de type MainWindow sert à décrire la fenêtre principale d'une application. On crée en général une seule MainWindow par application, comme unique fils du widget retourné par XtAppInitialize(). la fonction d'initialisation du Toolkit. Le widget retourné par cette dernière fonction est de la classe ApplicationShell, et comme tous les Shells, correspond à une fenêtre manipulable par le Window Manager.

Une MainWindow est prévue pour contenir :

Toutes ces parties sont optionnelles et il est très possible d'avoir une application sans zone de messages ni zone de commandes. La MainWindow assure juste une maintenance plus simple de ces composants s`ils existent.

Remarque importante : pour certaines applications très simple, on peut très bien se passer de MainWindow, comme dans l'exemple du premier chapitre : Premiers pas avec Motif.

Exemple d'application bâtie sur une MainWindow

L`exemple ci-dessous montre une MainWindow comportant une barre de menu, une ScrolledList dans la zone de travail (work area), un command widget et une zone de messages d'une ligne en bas de la fenêtre.

Source disponible : main_window.c

#include <Xm/MainW.h>
#include <Xm/Label.h>
#include <Xm/List.h>
#include <Xm/RowColumn.h>
#include <Xm/Command.h>
#include <stdio.h>

#define list_items "Ceci, Est, Une, ScrolledList, dans la, WorkArea, de la, Main Window"

main(int argc, char **argv)
{
    Widget toplevel, main_w, list_w, menubar, menu, message_area, command_w;
    XmString file, quit;
    XtAppContext app;
    Pixmap pixmap;
    /* A mettre systematiquement */
    XtSetLanguageProc(NULL, NULL, NULL);

   /* Initialisation du toolkit */
   toplevel = XtVaAppInitialize(&app, "Demos",
        NULL, 0, &argc, argv, NULL, NULL);

    /* La main window */
    main_w = XtVaCreateManagedWidget("main_window",
        xmMainWindowWidgetClass,   toplevel,
        NULL);

    /* Une ScrolledList que l'on met dans la work area */
    list_w = XmCreateScrolledList(main_w, "main_list", NULL, 0);
    XtVaSetValues(list_w,
                  XtVaTypedArg, XmNitems, XmRString,
                  list_items, strlen(list_items),
                  XmNitemCount, 8,
                  XmNvisibleItemCount, 5,
                  NULL);
    XtManageChild(list_w);


    /* Barre de menu avec un seul menu deroulant */
    file = XmStringCreateLocalized("File");
    menubar = XmVaCreateSimpleMenuBar(main_w, "menubar",
                                      XmVaCASCADEBUTTON, file, 'F',
                                      NULL);
    XmStringFree(file);
    XtManageChild(menubar);

    /* Un seul bouton dans le menu deroulant */
    quit = XmStringCreateLocalized("Quit");
    menu = XmVaCreateSimplePulldownMenu(menubar, "file_menu", 0, exit,
                                        XmVaPUSHBUTTON, quit, 'Q', NULL, NULL,
                                        NULL);
    XmStringFree(quit);


    /* Un label dans la zone de messages */
    message_area = 
      XtVaCreateManagedWidget("Ceci est la zone de messages",
                              xmLabelWidgetClass, main_w,
                              XmNalignment,  XmALIGNMENT_BEGINNING,
                              NULL);

    /* Un Command widget dans la command area */
    file = XmStringCreateLocalized("Entrez une commande :");
    command_w = XtVaCreateManagedWidget("command_w", xmCommandWidgetClass, 
                                        main_w, XmNpromptString, file,
                                        NULL);
    XmStringFree(file);

    /* Positionnement des attributs de la Main Window pour lui indiquer quels 
       widgets sont dans les differentes zones, et quelles sont leurs 
       positions rezpectives */
    XtVaSetValues(main_w,
                  XmNmenuBar,    menubar,
                  XmNworkWindow, XtParent(list_w),
                  XmNmessageWindow, message_area,
                  XmNcommandWindow,  command_w,
                  XmNcommandWindowLocation, XmCOMMAND_BELOW_WORKSPACE,
                  NULL);
    
    XtRealizeWidget(toplevel);
    XtAppMainLoop(app);
}

Plusieurs remarques concernant ce petit bout de code :

La classe MainWindow hérite de la classe ScrolledWindow !

On pourra utiliser avec un widget de type MainWindow tous les attributs, toutes les ressources disponibles pour la classe ScrolledWindow. Par exemple, si le contenu de la zone de travail est plus grand que cette dernière, on pourra indiquer à la MainWindow de faire apparaître automatiquement des ScrollBars.

Exemple de MainWindow se comportant comme une ScrolledWindow :

Le source est disponible : main_window_scroll.c

#include <Xm/MainW.h>
#include <Xm/Label.h>

#define msg_label \
"Ceci est un texte trop grand\n\
Pour rentrer dans la MainWindow, alors des barres de\n\
scrolling sont apparues !"

main(int argc, char **argv)
{
    Widget toplevel, main_w, label;
    XtAppContext app;

    XtSetLanguageProc(NULL, NULL, NULL);

    toplevel = XtVaAppInitialize(&app, "Demos",
        NULL, 0, &argc, argv, NULL, NULL);

    /* La main window */
    main_w = XtVaCreateManagedWidget("main_window",
                                     xmMainWindowWidgetClass,   toplevel,
                                     XmNscrollingPolicy, XmAUTOMATIC,
                                     XmNscrollBarDisplayPolicy, XmAS_NEEDED,
                                     NULL);

   /* Un label dans la work area  */
    label = 
      XtVaCreateManagedWidget(msg_label, 
                              xmLabelWidgetClass, main_w,
                              XmNalignment,  XmALIGNMENT_BEGINNING,
                              NULL);

    /* Positionnement des attributs de la Main Window pour lui indiquer quels 
       widgets sont dans les differentes zones, et quelles sont leurs 
       positions rezpectives */
    XmMainWindowSetAreas(label, NULL, NULL, NULL, NULL, NULL);
    
    XtRealizeWidget(toplevel);
    XtAppMainLoop(app);
}

Quelques remarques sur cet exemple :

Les menus

Généralités

Les menus Motif proposent un mécanisme offrant à l'utilisateur la possibilité d'effectuer des choix qui vont déclencher des actions.

Motif propose trois types de menus

Motif fournit trois types de menus : Popup, Pulldown et Option.

Remarques diverses

Composants des menus

Des widgets de base sont nécessaires pour composer des menus :

Menus déroulants standards, accrochés à une barre de menu

Le widget MenuBar

Mise en garde

La barre de menu est un widget de type MenuBar.

Il s'agit en fait d'une RowColumn horizontale particulière: lors de la création avec XmCreateMenuBar() ou XmVaCreateSimpleMenuBar(), étudiés dans cette section, Motif initialise plusieurs ressources de la classe RowColumn à notre insu.

Création d'un MenuBar

La création d'un véritable menu comme on en retrouve dans la plupart des applications est une tâche relativement complexe. C'est pourquoi nous allons découper l'étude des menus en deux étapes.

Les boutons que va contenir une barre de menu ou un menu déroulants sont d'un type particulier : le type CascadeButton. Vous comprendrez bien vite pourquoi on les a nommé de la sorte.

Etudions maintenant un petit exemple.

Le programme menu_cascade.c

Le source est disponible : menu_cascade.c


#include <Xm/Xm.h>
#include <Xm/MainW.h>
#include <Xm/CascadeB.h>
#include <Xm/RowColumn.h>

void quit_call(), help_call(); /* callbacks */

/*---------------------------*/
main(int argc, char *argv[])
/*---------------------------*/
{   
  Widget top_wid, main_win, menu_bar, quit, help;
  XtAppContext app;
  int n=0;
  Arg args[10];  
    
  /* Initialisation du toolkit */
  top_wid = XtVaAppInitialize(&app, "menu_cascade",
                              NULL, 0, &argc, argv, NULL, NULL);
  /* Creation de la MainWindow */
  n=0;
  main_win = XmCreateMainWindow(top_wid, "main_window", args, n);
  XtManageChild(main_win);

  /* Creation de la barre de menu */
  n=0;
  menu_bar = XmCreateMenuBar(main_win, "main_list", args, n);
  XtManageChild(menu_bar);

    
  /* Bouton quit + callback */
  n=0;
  XtSetArg(args[n], XmNmnemonic, 'Q'); n++;
  quit = XmCreateCascadeButton(menu_bar, "Quit", args, n); n++;
  XtManageChild(quit);
  XtAddCallback(quit, XmNactivateCallback, quit_call, NULL);

  /* Creation du bouton help + callback */      
  n=0;
  XtSetArg(args[n], XmNmnemonic, 'H'); n++;
  help = XmCreateCascadeButton(menu_bar, "Help", args, n); n++;
  XtManageChild(help);
    
  XtAddCallback(help, XmNactivateCallback, help_call, NULL);
    
  /* On indique a la barre de menu de mettre le bouton Help a droite */
  XtVaSetValues(menu_bar(XmNmenuHelpWidget, help, NULL);
        
  XtRealizeWidget(top_wid);
  XtAppMainLoop(app);
}

/*---------------*/
void quit_call()
/*---------------*/

{   
  printf("On sort du programme!\n");
  exit(0);
}

/*---------------*/
void help_call()
/*---------------*/

{   
  printf("Désolé je ne peux pas vous aider\n");
}


Les premières lignes de ce programme devraient maintenant vous être familières.

Dans la fenêtre top_level nous mettons une MainWindow (variable main_win), nous mettons aussi une MenuBar (variable menu_bar) comme enfant de main_win et finalement nous ajoutons deux CascadeButton (quit et help) dans la MenuBar.

Remarque : pour varier les plaisirs, la création des divers widgets a été cette fois-ci réalisée à l'aide des fonctions Motif standards de type XmCreate<nom du widget>(). Les ressources ont été positionnées dans le code à l'aide du mécanisme standard proposé par la librairie Xt :

En général, un widget de type CascadeButton sert à déclencher l'affichage d'un menu déroulant. Lorsqu'on clique dessus le menu se déroule en cascade, c'est pourquoi on les appelle des CascadeButton. Ils se conduisent exactement comme des PushButton et peuvent avoir des callbacks (ressource XmNactivateCallback).

Un CascadeButton peut très bien ne pas avoir de menu déroulant associé. Il se conduit alors exactement comme un bouton poussoir. C'est le cas dans le programme menu_cascade.c. Dans cet exemple, nous avons créé deux boutons auxquels nous avons attaché des callbacks très simples.

Raccourcis clavier : nous avons installé pour chacun des boutons un raccourcis clavier équivalent à un click souris sur le bouton. Dans l'exemple, si on tape meta-q on sort du programme comme si on avait cliqué sur le bouton quit. Idem pour le bouton help : l'appui de meta-h est équivalent à clicker dessus.

Nous avons utilisé pour celà la Ressource XmNmnemonic. Son utilisation est très simple (voir menu_cascade.c).

Autre exemple d'école

On va tout d'abord créer une MainWindow contenant une MenuBar et un widget de type Frame dans la WorkArea.



#include <Xm/Xm.h>
#include <Xm/RepType.h>

#include <Xm/MainW.h>
#include <Xm/CascadeB.h>
#include <Xm/RowColumn.h>
#include <Xm/Frame.h>

/*---------------------------*/
main(int argc, char *argv[])
/*---------------------------*/
{   
  XtAppContext app_context;
  Widget topLevel, mainWindow, menuBar, frame;
  Widget fileButton, fileMenu, quit, help, helpButton, helpMenu, helpBox;
  
  /* On indique que l'on desire utiliser le langage par defaut
     (anglais). Cette fonction initialise le support international de
     l'application. Les parametres inidiquent que l'on prend les
     valeurs par defaut */
  XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);

  topLevel = XtVaAppInitialize(&app_context, "XMainWIndow",
                              NULL, 0, &argc, argv, NULL, NULL);

  /* On cree la main window */
  mainWindow = XtVaCreateManagedWidget("mainWindow", 
                                       xmMainWindowWidgetClass,
                                       topLevel, 
                                       NULL);

  /* On cree la barre de menus. On utilise une fonction Xm ici car 
     la fonction XmCreateMenuBar effectue des operations qui n'ont pas
     d'equivalent avec Xt */
  menuBar = XmCreateMenuBar(mainWindow, "menuBar", NULL, 0);
  XtManageChild(menuBar);

    
  /* On cree une frame dans la work area de la main window */
  frame = XtVaCreateManagedWidget("frame", 
                                  xmFrameWidgetClass,
                                  mainWindow, 
                                  NULL);

  /* On positionne les parties de la main window */
  XmMainWindowSetAreas(mainWindow, menuBar, NULL, NULL, NULL, frame);

  XtRealizeWidget(topLevel);
  XtAppMainLoop(app_context);
}


Exercice: créér le fichier de ressources pour cette application tel que la MainWindow soit large de 200 pixels, et la Frame fasse 300 x 300 pixels. La work area de la MainWindow étant en fait une ScrolledWindow, on pourra positionner la ressource scrollingPolicy de la MainWindow pour faire apparaître des ScrollBars.

Nous étudierons plus en détails les ScrolledWindows et les ScrollBars dans la suite du cours.

On va maintenant ajouter des menus à cette application.

Création d'un menu déroulant

Un menu déroulant est un widget de la classe PulldownMenu. Il s'agit en réalité d'un RowColumn vertical. Même remarque que pour les MenuBars : ne pas utiliser de fonctions de création de la librairie Xt !

La création d'un menu se fait en quatre étapes

  1. Créer un CascadeButton comme fils de la MenuBar. C'est le bouton qui va déclencher l'apparition du menu.
  2. Créer un PulldownMenu vide, fils de la MenuBar, qui va contenir les différents items. On utilisera la fonction XmCreatePulldownMenu().

    Attention: il ne faut pas le manager puisque le menu apparaît à la demande. C'est le CascadeButton qui s'occupera de ce travail pour nous! Pour information, un PulldownMenu est en réalité une RowColumn, tout comme la MenuBar.
  3. Créer des PushButtons, des ToggleButtons, des Labels ou des Separators comme fils du Pulldown.
  4. Indiquer au CascadeButton le menu qu'il doit dérouler. Cette action est réalisée en positionnant la ressource XmNsubMenuId du CascadeButton avec l'identificateur du PullDownMenu.

Exemple de création de menus déroulants

Le source est disponible xmainwindow.c



#include <Xm/Xm.h>
#include <Xm/RepType.h>

#include <Xm/MainW.h>
#include <Xm/CascadeB.h>
#include <Xm/RowColumn.h>
#include <Xm/Frame.h>
#include <Xm/PushB.h>

void QuitCB(Widget w, XtPointer client_data, 
            XmPushButtonCallbackStruct *cbs);

/*---------------------------*/
main(int argc, char *argv[])
/*---------------------------*/
{   
     .
     .
     .
     .
  /* Creation du menu: 
     1) On cree un cascade bouton File dans la menubar */
  fileButton = XtVaCreateManagedWidget("fileButton",
                                       xmCascadeButtonWidgetClass,
                                       menuBar,
                                       NULL);

  /* 2) Creation du PullDownMenu vide. ATTENTION: on utilise une 
     fonction Xm! Remarquez que le menu n'est pas manage !*/
  fileMenu = XmCreatePulldownMenu(menuBar,
                                  "fileMenu",
                                  NULL,
                                  0);
  
  /* 3) Creation d'un bouton quit dans le menu File */
  quit = XtVaCreateManagedWidget("quit",
                                 xmPushButtonWidgetClass,
                                 fileMenu,
                                 NULL);

  /* 4) On indique au CascadeButton le menu qu'il doit derouler */
  XtVaSetValues(fileButton,
                XmNsubMenuId, fileMenu,
                NULL);

  /* On cree un callback pour le bouton quit */
  XtAddCallback(quit, XmNactivateCallback, QuitCB, 0);
  

  XtRealizeWidget(topLevel);
  XtAppMainLoop(app_context);
}


/*----------------------------------------------*/
void QuitCB(Widget w, XtPointer client_data, 
            XmPushButtonCallbackStruct *cbs)
/*----------------------------------------------*/
{   
  exit(0);
}


Exercices :

Un exemple un peu plus compliqué

Nous allons étudier le programme menu_pull.c proposant deux menus déroulants. Le premier, "Quitter", contient un seul item (une seule entrée) qui nous permettra de sortir du programme.

Le second menu, "Couleur" propose 5 items permettant de changer la couleur du fond du Label widget attaché à la MainWindow.

Le début du programme ressemble à l'exemple précédent : on crée un top_level, on crée une MainWindow dans le top_level, une MenuBar dans la MainWindow, des CascadeButton dans la MenuBar, et ensuite, plein de trucs nouveaux ! Alors etudiez-bien ce petit bout de code sans vous affoler, et rendez-vous après ces quelques lignes de source C !

Le source est disponible : pull_down.c



#include <Xm/Xm.h>
#include <Xm/MainW.h>
#include <Xm/Label.h>
#include <Xm/RowColumn.h>

Widget top_wid, label, main_w;

String colours[] = { "Black",  "Red", "Green", "Blue", "Grey"};

Display *display; /* Le display, on va en avoir besoin pour dessiner */

Colormap cmap;


/*---------------*/
main(int argc, char **argv)
/*---------------*/
{
  Widget  menubar, menu, quit_w, widget;
  XtAppContext app;


  XColor back, fore, spare;
  XmString  quit, colour, red, green, blue, black, grey, label_str;
  void quit_call(), colour_call();
    
  int n = 0;
  Arg args[20];

  /* Initialisation du toolkit */
  top_wid = XtVaAppInitialize(&app, "Pull_down", NULL, 0, 
                              &argc, argv, NULL, NULL);

        
  /* La MainWindow contient un MenuBar et un Label */
  n=0;
  XtSetArg(args[n], XmNwidth, 300); n++;
  XtSetArg(args[n], XmNheight, 300); n++;
  main_w = XmCreateMainWindow(top_wid, "main_window", args, n);
  XtManageChild(main_w);


  /* Creation d'une simple MenuBar contenant 3 menus */
  quit = XmStringCreateSimple("Quit");
  colour = XmStringCreateSimple("Colour");
    

  menubar = XmVaCreateSimpleMenuBar(main_w, "menubar",
                                    XmVaCASCADEBUTTON, quit, 'Q',
                                    XmVaCASCADEBUTTON, colour, 'C',
                                    NULL);
        
        
  XmStringFree(colour); /* On libere la chaine */
   
  /* Premier menu = quit. callback = quit_call() */
  quit_w = XmVaCreateSimplePulldownMenu(menubar, "quit_menu", 
                                        0, quit_call,
                                        XmVaPUSHBUTTON, quit, 'Q', NULL, NULL,
                                        NULL);
  XmStringFree(quit);


  /* Le second menu contient les couleurs. Meme callback pour toutes les
     entrees : la fonction colour_call() */
  black = XmStringCreateSimple(colours[0]);
  red = XmStringCreateSimple(colours[1]);
  green = XmStringCreateSimple(colours[2]);
  blue = XmStringCreateSimple(colours[3]);
  grey = XmStringCreateSimple(colours[4]);

    
  menu = XmVaCreateSimplePulldownMenu(menubar, "edit_menu", 
        1, colour_call,
        XmVaRADIOBUTTON, black, 'k', NULL, NULL,
        XmVaRADIOBUTTON, red, 'R', NULL, NULL,
        XmVaRADIOBUTTON, green, 'G', NULL, NULL,
        XmVaRADIOBUTTON, blue, 'B', NULL, NULL,
        XmVaRADIOBUTTON, grey, 'e', NULL, NULL,
        /* Ressourc de la RowColumn */
        XmNradioBehavior, True,     
        /* comportement radiobox dans le menu */
        XmNradioAlwaysOne, True,    
        NULL);

  XmStringFree(black);
  XmStringFree(red);
  XmStringFree(green);
  XmStringFree(blue);


  /* On initialise le menu pour que "black soit
     la selection par defaut */
  if (widget = XtNameToWidget(menu, "button_0"))
    XtVaSetValues(widget, XmNset, True, NULL);

  XtManageChild(menubar);
    
  /* Label dans la work area. C'est lui qui va changer de couleur ! */
  label_str = XmStringCreateLocalized("Colorez-moi");
    
  label = XtVaCreateManagedWidget("main_window",
                                  xmLabelWidgetClass,   main_w,
                                  XmNlabelString, label_str,
                                  NULL);
        
  XmStringFree(label_str);

  /* Label = work area */
  XtVaSetValues(main_w,
                XmNmenuBar,    menubar,
                XmNworkWindow, label,
                NULL);

       
  /* background et foreground */
  cmap = DefaultColormapOfScreen(XtScreen(label));
  display = XtDisplay(label);
    
  XAllocNamedColor(display, cmap, colours[0], &back, &spare);
  XAllocNamedColor(display, cmap, "white", &fore, &spare);
    
  /* Ci-dessous, on ferait mieux d'utiliser XtVaSetValues() */
  n=0;
  XtSetArg(args[n],XmNbackground, back.pixel);      
  ++n;
  XtSetArg(args[n],XmNforeground, fore.pixel);      
  ++n;
  XtSetValues(label, args, n);
    
  XtRealizeWidget(top_wid);
  XtAppMainLoop(app);
}

/*-------------------------*/
void quit_call(w, item_no, call_data)
/*-------------------------*/
/* N'importe quelle entree dans le menu file appelle cette fonction.
   Si l'entree est la premiere (item_no == 0), elle fait exit() */
*/
Widget w;               /* entree du menu qui a declenche le callback */
int item_no;            /* index de l'entree dans le menu (part de 0) */
XtPointer call_data;
{  
  if (item_no == 0)     /* L'entree "quit" */
    exit(0);
}

/*--------------------------*/
void colour_call(w, item_no, call_data)
/*--------------------------*/
/* Appelee lorsqu'une entree du menu Color est selectionnee  
   Change la couleur du label de la work area
   Note: Pour modifier dynamiquement la couleur on utilisera la fonction
         XtSetArg() avec XtSetValues.
*/
Widget w;              
int item_no;
XtPointer call_data;           
{   
  int n =0;
  Arg args[1];
    
  XColor xcolour, spare; 
        
  if (XAllocNamedColor(display, cmap, colours[item_no], 
                       &xcolour, &spare) == 0)
    return;

  n=0; 
  XtSetArg(args[n],XmNbackground, xcolour.pixel);      
  ++n;
  XtSetValues(label, args, n);
}


Bon. Respirez-un grand coup... Hmmmmmffffff ! Pas de panique !

Beaucoup de nouveautés ici, des fonctions bizarres qui ressemblent à celles déjà étudiées mais légèrement différentes, de la couleur (oui, de la couleur !), des chaînes de caractères utilisées de manière bizarre, etc.... Nous allons étudier tout ceci calmement...

La fonction XmVaCreateSimpleMenuBar()

Dans cet exemple, nous avons créé la MenuBar à l'aide de la fonction XmVaCreateSimpleMenuBar() qui est plus simple à utiliser que la fonction XmCreateMenuBar() de l'exemple précédent. Elle permet d'indiquer les CascadeButtons que l'on veut mettre dans la barre de menu, dès la création de cette dernière.

Comme XtVaSetValues() et XtVaCreateManagedWidget() cette fonction possède un nombre d'arguments variables. En plus des paires Ressource/Valeur déjà rencontrées, elle accepte des arguments spécifiques permettant d'indiquer quels éléments on va insérer dans la MenuBar.

Les ressources que l'on peut spécifier sont les mêmes que pour un RowColumn puisque le widget MenuBar est un RowColumn déguisé.

Paramètres de la fonction XmVaCreateSimpleMenuBar() :

Comment modifier le label d'un CascadeButton de la MenuBar dans le fichier de ressources ?

Puisqu'on ne crée plus les boutons poussoirs à l'aide des fonctions standards (XmCreateCascadeButton(), XtVaCreateManagedWidget(), etc...), on ne sait pas quels noms leurs sont associés. Puisque les boutons sont crées séquentiellement, un nom de type "bouton_n" est alloué automatiquement au n-ième bouton n, le premier bouton ayant comme indice 0.

Important : il faut prendre l'habitude de libèrer systématiquement la place occupée par une XmString dès qu'on en a plus besoin. Cette opération est réalisée en appelant la fonction XmStringFree().

La fonction XmVaCreateSimplePulldownMenu()

Cette fonction permet en un seul appel d'effectuer 3 des 4 opérations nécessaires à la création d'un menu déroulant. Avec XmVaCreateSimplePulldownMenu() on créée le PulldownMenu avec tous ses éléments, on spécifie une fonction de callback (la même pour toutes les éléments), et on spécifie même les raccourcis clavier !

Regardons comment nous avons créé le menu déroulant Quit :



  quit_w = XmVaCreateSimplePulldownMenu(menubar, "quit_menu", 
                              0, quit_call,
                              XmVaPUSHBUTTON, quit, 'Q', NULL, NULL,
                              NULL);


Paramètres de la fonction XmVaCreateSimplePulldownMenu()

Comme pour XmVaCreateSImpleMenuBar(), cette fonction accepte un nombre variable d'arguments :

ATTENTION : Les menus ne sont pas censés évoluer dynamiquement. Une fois crées, on ne rajoute rien dedans (sauf cas exceptionnel). En tout cas, on ne rajoute rien dans les menus crées avec les fonctions XmVaCreateSimple....

Le menu Colour est créé de manière similaire si ce n'est qu'il possède cinq choix au lieu d'un seul dans le menu Quit.

Les callbacks des menus crées par XmVaCreateSimplePulldownMenu()

Il reste à étudier une dernière chose : comment traiter les choix faits par l'utilisateur lors de l'exécution de notre programme ?

Chaque PullDown menu possède sa propre fonction de callback. La fonction de callback possède trois paramètres :

Le paramètre client_data de la fonction de callback contient l'indice de l'élément du menu qui a déclenché l'action.

Le champ reason de la structure de callback servira à faire la différence entre ToggleButtons et PushButtons si le menu contient ces deux sortes d'éléments. En effet, pour le PushButton, reason vaudra CR_ACTIVATE, pour le ToggleButton CR_VALUE_CHANGED.

Ainsi, dans la fonction de callback du menu Quit, quit_call(), une seule sélection est possible (la variable item_no doit être égale à zéro).

Dans la fonction de callback du menu Colour, colour_call(), la valeur du choix va provoquer une action (changer la couleur du fond de widget de type Label qui se trouve dans la work area de la MainWindow).

Ne vous affolez pas à propos de la couleur, reportez-vous au cours.correspondant. Pour comprendre l'exemple, il suffit de savoir que la structure de données xcolour, de type XColor stocke la valeur de la couleur que nous désirons dans le champ xcolour.pixel après allocation par l'appel de XAllocNamedColor(). Il suffit ensuite de positionner la ressource XmNbackgound du widget de type Label à l'aide des fonctions XtSetArg() et XtSetValues()

Option Menus

A compléter...

PopUpMenus

A compléter


michel.buffa@essi.fr