Tutoriel CDK Partie 2
Signature : | Mis en ligne le : 27/05/2009
Catégorie(s) :
  • GNU/Linux Magazine
  • | Domaine :
    Commentez creative commons

    Retrouvez cet article dans : Linux Magazine 108

    Nous reprenons la suite de notre tutoriel sur CDK [1]. Dans la première partie, nous avons vu les bases de la programmation avec CDK, quelques widgets de base et le mécanisme des fonctions de callback. Pour l’instant, nous sommes capables de générer des interfaces " séquentielles " posant successivement des questions à l’utilisateur de notre programme. Nous allons voir dans cette partie comment gérer des formulaires complets et des menus déroulants nous permettant de créer des interfaces plus ergonomiques. Mais, avant cela, nous allons commencer par examiner une nouvelle famille de widgets particulièrement utile.

    Rappelons avant de commencer qu’on trouvera à l’adresse suivante [2] un tarball contenant tous les programmes d’exemple de cet article, ainsi que la version de CDK utilisée qui est la version 5.0 du 7 mai 2006.

    1 Les listes

    Nous allons maintenant aborder une famille de widgets très utiles, permettant de choisir un ou plusieurs éléments dans une liste.

    1.1 Scrolling list et Radio list

    Le widget le plus simple de cette famille porte mal son nom, puisqu’il ne contient pas " list ". Il s’agit du widget CDKScroll qui affiche une liste déroulante d’items éventuellement en liste à puce numérotée ; après activation, la navigation se fait avec les flèches et la sélection par la touche [Entrée]. La sortie écran générée se trouve en figure 1.

    #include <cdk/cdk.h>

    int main() {

    CDKSCREEN *cdkscreen;

    WINDOW *cursesWin;

    CDKSCROLL *liste;

    char *titre="</48>Selectionnez un legume dans la liste";

    char temp[256],*mesg[10];

    int choix;

    char *leglist[] = {"Carotte","Navet","Choux-fleur",

    "Brocoli","Pomme de terre","Courgette","Aubergine",

    "Poivron","Rutabaga"};

    /* Initialisation */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    /* Initialisation des couleurs CDK */

    initCDKColor();

    liste = newCDKScroll(cdkscreen,

    CENTER, /* coordonnée sur x : colonne de debut*/

    CENTER, /* coordonnée sur y : ligne de début en partant du haut */

    RIGHT, /* position de la scrollbar (RIGHT,LEFT,NONE) */

    8, /* Hauteur de la liste */

    30, /* Largeur de la liste */

    titre, /* Titre du widget */

    leglist, /* La liste des items */

    9, /* Nombre d’items */

    FALSE, /* si TRUE liste à puce numérotée */

    A_REVERSE, /* Attribut ncurses de l’item sélectionné */

    TRUE, /* Dessiner une boite autour? */

    FALSE); /* Dessiner une ombre autour? */

    /* On affiche */

    refreshCDKScreen (cdkscreen);

    while(liste->exitType != vNORMAL) /* On ne sort pas par Echap */

    {

    choix = activateCDKScroll (liste, 0);

    }

    sprintf(temp,"<C>Résultat de votre sélection : %i",choix);

    mesg[0]=copyChar(temp);

    sprintf(temp,"<C>%s",leglist[choix]);

    mesg[1]=copyChar(temp);

    popupLabel(cdkscreen,mesg,2);

    /* on nettoie avant de quitter */

    destroyCDKScroll(liste);

    destroyCDKScreen (cdkscreen);

    endCDK();

    }

    liste copie copie.TIF

    Figure 1 : Liste CDKScroll

    Une variante de ce widget est le widget CDKRadio. Pour faire une analogie avec les interfaces graphiques, il s’agit d’un mélange de liste déroulante et de boutons radio. Après activation, la navigation se fait avec les flèches. On choisit l’élément de la liste avec la barre d’espace et la validation finale se fait avec la touche [Entrée]. Je ne reporte ici que la partie création du widget, son utilisation étant parfaitement identique à celle du widget CDKScroll. La sortie écran correspondante se trouve en figure 2.

    legumes = newCDKRadio(cdkscreen,

    CENTER, /* coordonnée sur x : colonne de debut*/

    CENTER, /* coordonnée sur y : ligne de début en partant du haut */

    LEFT, /* Position de la scrollbar RIGHT,LEFT,NONE */

    9, /* Hauteur de la liste */

    20, /* Largeur de la liste */

    "<C></48>Choisissez un legume pour le diner", /* Titre */

    leglist, /* Tableau de chaine contenant la liste */

    9, /* Nombre d’item à afficher */

    ‘#’, /* Caractère de choix */

    0, /* index de l’item par défaut */

    A_REVERSE, /* Attribut ncurses de l’item courant */

    TRUE, /* Dessiner une boite? */

    FALSE); /* Dessiner une ombre? */

    radio copie copie.tif

    Figure 2 : Liste CDKRadio

    1.2 Alpha list

    Le widget CDKAlphalist est un widget composite, composé d’une saisie utilisateur et d’une liste déroulante classée alphabétiquement (d’où son nom). Après activation, les flèches permettent de se déplacer dans la liste. L’item courant est reporté dans la saisie utilisateur. Si l’on entre un caractère dans le champ de saisie, dans notre exemple un " C ", l’item courant va se positionner sur le premier item commençant par " C ". Un appui sur la touche [Tab] va effectuer une complétion automatique si possible ou bien afficher une liste popup avec les choix possibles, comme on peut le voir en figure 3.

    #include <cdk/cdk.h>

    int main() {

    CDKSCREEN *cdkscreen;

    WINDOW *cursesWin;

    CDKALPHALIST *liste;

    char *titre="</48>Selectionnez un legume dans la liste";

    /*char **itemlist;*/

    char temp[256],*mesg[10];

    char *label="</24>Legume :";

    char *choix;

    char *leglist[] = {"Carotte","Navet",

    "Choux-fleur","Brocoli","Pomme de terre",

    "Courgette","Aubergine","Poivron","Rutabaga"};

    /* Initialisation */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    /* Initialisation des couleurs CDK */

    initCDKColor();

    liste = newCDKAlphalist(cdkscreen,

    CENTER, /* coordonnée sur x : colonne de debut*/

    CENTER, /* coordonnée sur y : ligne de début en partant du haut */

    10, /* Hauteur de la liste */

    40, /* Largeur de la liste >= strlen(titre) */

    titre, /* Titre du widget */

    label, /* Texte devant la saisie */

    leglist, /* La liste des items */

    9, /* Nombre d’items */

    ‘_’|COLOR_PAIR(24), /* Caractère de remplissage de la saisie */

    A_REVERSE|COLOR_PAIR(24), /* Attribut de l’élément courant */

    TRUE, /* Dessiner une boite autour? */

    FALSE); /* Dessiner une ombre autour? */

    /* On affiche */

    refreshCDKScreen (cdkscreen);

    while(liste->exitType != vNORMAL) /* On ne sort pas par Echap */

    {

    choix = activateCDKAlphalist (liste, 0);

    }

    sprintf(temp,"<C>Résultat de votre sélection : %s",choix);

    mesg[0]=copyChar(temp);

    popupLabel(cdkscreen,mesg,1);

    /* on nettoie avant de quitter */

    destroyCDKAlphalist(liste);

    destroyCDKScreen (cdkscreen);

    endCDK();

    }

    alphalist1 copie copie.tif

    Figure 3 : Complétion dans CDKAlphalist

    1.3 Sélection

    Pour finir cette famille de widgets, le widget CDKSelection, par rapport aux interfaces graphiques, est un mélange de checkbox et de liste déroulante. Ce widget affiche une liste avec la possibilité pour chaque item de modifier un tag pouvant prendre un certain nombre d’états (dans notre exemple [ ], [Y] et [N]). Cet état se change de manière circulaire avec la barre d’espace. La sortie écran correspondante se trouve en figure 4. Pour la récupération des informations, un accès direct à la structure est nécessaire, comme il est fait dans cet exemple.

    #include <cdk/cdk.h>

    int main() {

    CDKSCREEN *cdkscreen;

    WINDOW *cursesWin;

    CDKSELECTION *legumes;

    CDKLABEL *tleg;

    /*char **itemlist;*/

    char *itemlist[30];

    char *mesg[10];

    char temp[256];

    char *choix[] = {"[ ]","[Y]","[N]"};

    char *leglist[] = {"Carotte","Navet","Choux-fleur","Brocoli","Pomme de terre",

    "Courgette","Aubergine","Poivron","Rutabaga"};

    int i,lcount;

    /* Initialisation */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    /* Initialisation des couleurs CDK */

    initCDKColor();

    mesg[0]="<C></48>Legumes";

    mesg[1]="</48>[ ] = indifférent";

    mesg[2]="</48>[Y]=j’adore! [N]=Je déteste";

    tleg = newCDKLabel(cdkscreen,

    CENTER, /* coordonnée sur x : colonne de debut*/

    3, /* coordonnée sur y : ligne de début en partant du haut */

    mesg, /* le tableau de caractere contenant le label */

    3, /* le nombre de lignes à afficher */

    FALSE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    legumes = newCDKSelection(cdkscreen,

    CENTER, /* coordonnée sur x : colonne de debut*/

    7, /* coordonnée sur y : ligne de début en partant du haut */

    LEFT, /* Position de la scrollbar RIGHT,LEFT,NONE */

    7, /* Hauteur de la liste */

    20, /* Largeur de la liste */

    "", /* Titre */

    leglist,/* Tableau de chaine contenant la liste */

    9, /* Nombre d’item à afficher */

    choix, /* Tableau de chaine contenant les différents choix */

    3, /* Nombre de choix */

    A_REVERSE, /* Attribut ncurses de l’item sélectionné */

    FALSE, /* Dessiner une boite? */

    FALSE); /* Dessiner une ombre? */

    /* On affiche */

    refreshCDKScreen (cdkscreen);

    while(legumes->exitType != vNORMAL) /* On ne sort pas par escape */

    {

    activateCDKSelection (legumes, 0);

    }

    /* On affiche le résultat de la sélection */

    mesg[0]="Vous êtes indifférent à :";

    mesg[1]="";

    lcount=2;

    for (i=1;i<=9;i++)

    {

    /* Accès au résultat directement dans la structure */

    if (legumes->selections[i-1]==0)

    {

    /*

    sprintf(temp,"%s",leglist[i-1]);

    mesg[lcount]=copyChar(temp);*/

    mesg[lcount]=leglist[i-1];

    lcount++;

    }

    }

    popupLabel(cdkscreen,mesg,lcount);

    mesg[0]="Vous adorez :";

    mesg[1]="";

    lcount=2;

    for (i=1;i<=9;i++)

    {

    /* Accès au résultat directement dans la structure */

    if (legumes->selections[i-1]==1)

    {

    /*

    sprintf(temp,"%s",leglist[i-1]);

    mesg[lcount]=copyChar(temp);*/

    mesg[lcount]=leglist[i-1];

    lcount++;

    }

    }

    popupLabel(cdkscreen,mesg,lcount);

    mesg[0]="Vous détestez :";

    mesg[1]="";

    lcount=2;

    for (i=1;i<=9;i++)

    {

    /* Accès au résultat directement dans la structure */

    if (legumes->selections[i-1]==2)

    {

    /*

    sprintf(temp,"%s",leglist[i-1]);

    mesg[lcount]=copyChar(temp);*/

    mesg[lcount]=leglist[i-1];

    lcount++;

    }

    }

    popupLabel(cdkscreen,mesg,lcount);

    destroyCDKSelection (legumes);

    destroyCDKScreen (cdkscreen);

    endCDK();

    }

    selection copie copie.TIF

    Figure 4 : Sélection

    2 Formulaires

    2.1 Un formulaire

    Bon, tout ça c’est bien joli, mais tout ce que nous savons faire avec ce que nous avons vu jusqu’à présent, ce sont des interfaces séquentielles, c’est-à-dire un widget après l’autre, ce qui est un peu limité. CDK a tout prévu avec la fonction traverseCDKScreen (man cdk_traverse). Voyons l’exemple suivant dont une copie écran se trouve en figure 5, (page 66).

    #include <cdk/cdk.h>

    /* Déclaration des fonctions de callback */

    /* Aide */

    int helpCB(EObjectType cdktype, void *object, void *clientData, chtype key);

    /* Aide légumes */

    int helplegCB(EObjectType cdktype, void *object, void *clientData, chtype key);

    /* callback bouton Ok */

    int okCB(EObjectType cdktype, void *object, void *clientData, chtype key);

    /* callback bouton cancel */

    int cancelCB(EObjectType cdktype, void *object, void *clientData, chtype key);

    int main() {

    CDKSCREEN *cdkscreen;

    WINDOW *cursesWin;

    CDKLABEL *titre,*tleg,*l1,*l2;

    CDKENTRY *nom_entry,*prenom_entry;

    CDKSELECTION *legumes;

    CDKTEMPLATE *naissance;

    CDKBUTTON *okbut,*cancelbut;

    char *mesg[10];

    char *choix[] = {"[ ]","[Y]","[N]"};

    char *leglist[] = {"Carotte","Navet","Choux-fleur","Brocoli","Pomme de terre",

    "Courgette","Aubergine","Poivron","Rutabaga"};

    char *overlay = "</24>JJ/MM/AAAA";

    char *masque = "##/##/####";

    mesg[0]="</48>Formulaire";

    /* Initialisation */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    /* Initialisation des couleurs CDK */

    initCDKColor();

    /* Définition du titre */

    titre = newCDKLabel(cdkscreen,

    CENTER, /* coordonnée sur x : colonne de debut*/

    TOP, /* coordonnée sur y : ligne de début en partant du haut */

    mesg, /* le tableau de caractere contenant le label */

    1, /* le nombre de lignes à afficher */

    FALSE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    mesg[0]="</48>F1 : Aide";

    l1 = newCDKLabel(cdkscreen,

    LEFT,

    BOTTOM,

    mesg,

    1,

    FALSE,

    FALSE);

    mesg[0]="</48>F10 : Quitte";

    l2 = newCDKLabel(cdkscreen,

    RIGHT,

    BOTTOM,

    mesg,

    1,

    FALSE,

    FALSE);

    /* Entry nom et prenom */

    prenom_entry = newCDKEntry(cdkscreen,

    2, /* coordonnée sur x : colonne de debut*/

    2, /* coordonnée sur y : ligne de début en partant du haut */

    "", /* Le titre de l’entrée */

    "Prenom :", /* texte affiché devant le champ de saisie */

    COLOR_PAIR(24), /* Attribut du texte saisi par l’utilisateur */

    FALSE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    bindCDKObject (vENTRY, prenom_entry, KEY_F (1), helpCB, 0);

    nom_entry = newCDKEntry(cdkscreen,

    2, /* coordonnée sur x : colonne de debut*/

    3, /* coordonnée sur y : ligne de début en partant du haut */

    "", /* Le titre de l’entrée */

    "Nom :", /* texte affiché devant le champ de saisie */

    COLOR_PAIR(24), /* Attribut du texte saisi par l’utilisateur */

    ‘_’|COLOR_PAIR(24), /* Caractère à utiliser pour remplir le champ */

    vMIXED, /* Filtre de caratères (man cdk_display) */

    20, /* Largeur du champ. 0 -> champ le plus large possible à l’écran

    -N -> champ le plus large possible moins

    N caractères */

    0, /* Taille minimale de la saisie */

    256, /* Taille maximale de la saisie */

    FALSE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    bindCDKObject (vENTRY, nom_entry, KEY_F (1), helpCB, 0);

    naissance = newCDKTemplate(cdkscreen,

    2, /* coordonnée sur x : colonne de debut*/

    4, /* coordonnée sur y : ligne de début en partant du haut */

    "", /* Le titre du template */

    "Date de naissance :", /* texte affiché devant le champ de saisie */

    masque, /* Masque de saisie */

    overlay, /* Overlay à afficher */

    FALSE, /* Dessiner une boite? */

    FALSE); /* Dessiner une ombre? */

    bindCDKObject (vTEMPLATE, naissance, KEY_F (1), helpCB, 0);

    mesg[0]="<C></48>Legumes";

    mesg[1]="</48>[ ] = indifférent";

    mesg[2]="</48>[Y]=j’adore! [N]=Je déteste";

    tleg = newCDKLabel(cdkscreen,

    RIGHT, /* coordonnée sur x : colonne de debut*/

    3, /* coordonnée sur y : ligne de début en partant du haut */

    mesg, /* le tableau de caractere contenant le label */

    3, /* le nombre de lignes à afficher */

    FALSE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    legumes = newCDKSelection(cdkscreen,

    RIGHT, /* coordonnée sur x : colonne de debut*/

    7, /* coordonnée sur y : ligne de début en partant du haut */

    LEFT, /* Position de la scrollbar RIGHT,LEFT,NONE */

    7, /* Hauteur de la liste */

    20, /* Largeur de la liste */

    "", /* Titre */

    leglist,/* Tableau de chaine contenant la liste */

    9, /* Nombre d’item à afficher */

    choix, /* Tableau de chaine contenant les différents choix */

    3, /* Nombre de choix */

    A_REVERSE, /* Attribut ncurses de l’item sélectionné */

    FALSE, /* Dessiner une boite? */

    FALSE); /* Dessiner une ombre? */

    /* On associe pour l’objet legumes la touche F1 à la fonction de callback helplegCB */

    bindCDKObject (vSELECTION, legumes, KEY_F (1), helplegCB, 0);

    /* Les deux boutons Ok et Cancel */

    okbut=newCDKButton(cdkscreen,

    LEFT, /* coordonnée sur x : colonne de debut */

    20, /* coordonnée sur y : ligne de début en partant du haut */

    "Ok", /* Texte du bouton */

    (void *) okCB, /* Callback associé au bouton */

    FALSE); /* Dessiner une ombre? */

    /* On affiche le screen*/

    refreshCDKScreen (cdkscreen);

    /* On lance le moteur traverse sur le screen */

    traverseCDKScreen (cdkscreen);

    /* On teste la façon dont on est sorti du screen */

    if (cdkscreen->exitStatus == CDKSCREEN_EXITOK)

    {

    /* sortie normale F10 ou bouton Ok */

    mesg[0]="Sortie normale";

    popupLabel(cdkscreen,mesg,1);

    } else if ( cdkscreen->exitStatus == CDKSCREEN_EXITCANCEL)

    {

    /* sortie par cancel CTRL-X ou bouton Cancel */

    mesg[0]="Sortie cancel";

    popupLabel(cdkscreen,mesg,1);

    } else

    {

    /* Normalement on ne devrait pas être là */

    mesg[0]="Etrange .. on n’est pas sorti!";

    popupLabel(cdkscreen,mesg,1);

    }

    /* on nettoie avant de quitter */

    destroyCDKLabel (titre);

    destroyCDKLabel (tleg);

    destroyCDKLabel (l1);

    destroyCDKLabel (l2);

    destroyCDKSelection (legumes);

    destroyCDKEntry (prenom_entry);

    destroyCDKEntry (nom_entry);

    destroyCDKTemplate (naissance);

    destroyCDKButton (okbut);

    destroyCDKButton (cancelbut);

    destroyCDKScreen (cdkscreen);

    endCDK();

    }

    /* CallBack fonction d’aide */

    /* On n’utilise que le paramètre object qui nous sert à récupérer le cdkscreen */

    int helpCB(EObjectType cdktype, void *object, void *clientData, chtype key)

    {

    CDKSCREEN *screen;

    CDKOBJS *obj = (CDKOBJS *)object;

    screen=obj->screen;

    char *mesg[10];

    mesg[0]="<C>Aide du formulaire";

    mesg[1]="";

    mesg[2]="F1 : Affiche cette aide";

    mesg[3]="F10 : Quitte le formulaire (Ok)";

    mesg[4]="Ctrl x : Quitte le formulaire (Cancel)";

    mesg[5]="TAB : Change de champ";

    popupLabel(screen,mesg,5);

    }

    /* CallBack fonction d’aide spécifique legumes */

    /* On n’utilise que le paramètre object qui nous sert à récupérer le cdkscreen */

    int helplegCB(EObjectType cdktype, void *object, void *clientData, chtype key)

    {

    CDKSCREEN *screen;

    CDKOBJS *obj = (CDKOBJS *)object;

    screen=obj->screen;

    char *mesg[10];

    mesg[0]="<C></48>Legumes";

    mesg[1]="";

    mesg[2]="<C>Utilisez les fleches pour changer d’item";

    mesg[3]="<C>et appuyez sur la barre d’espace pour";

    mesg[4]="<C>changer l’état";

    mesg[5]="";

    popupLabel(screen,mesg,6);

    }

    /* CallBack bouton Ok */

    /* On n’utilise que le paramètre object qui nous sert à récupérer le cdkscreen */

    int okCB(EObjectType cdktype, void *object, void *clientData, chtype key)

    {

    CDKOBJS *obj = (CDKOBJS *)object;

    CDKSCREEN *screen;

    screen=obj->screen;

    exitOKCDKScreen (screen);

    }

    /* CallBack bouton Cancel */

    /* On n’utilise que le paramètre object qui nous sert à récupérer le cdkscreen */

    int cancelCB(EObjectType cdktype, void *object, void *clientData, chtype key)

    {

    CDKOBJS *obj = (CDKOBJS *)object;

    CDKSCREEN *screen;

    screen=obj->screen;

    exitCancelCDKScreen (screen);

    }

    formulaire copie copie.TIF

    Figure 5 : Un formulaire

    Ce programme récapitule tout ce que nous avons vu jusqu’à maintenant. On commence par créer 3 CDKLabel, 2 CDKEntry, 1 CDKTemplate, 1 CDKSelection et 2 CDKButton que nous n’avons pas encore vus. Ces derniers sont des widgets très simples, constitués d’un label et d’une fonction de callback associée. On définit également deux fonctions de callback d’aide, une générale et une pour la sélection. On associe ensuite ces fonctions d’aide avec bindCDKObject à la touche [F1] pour chaque widget.

    La nouveauté dans ce programme est que l’on n’utilise aucune des fonctions d’activation des widgets. À la place, on fait un appel à traverseCDKScreen (cdkscreen) avec, on le voit, le screen CDK comme seul argument. Décrivons maintenant le comportement de cette fonction. Une fois que cette fonction a pris la main, elle va activer le premier widget et ré-associer certaines touches. La touche [Entrée] n’aura plus l’effet habituel consistant à quitter le widget avec un mode vNormal (pour les boutons, la fonction de callback sera appelée de manière standard), un appui sur la touche [Tab] changera le widget actif. La touche [Echap] n’aura plus non plus comme effet de quitter le widget avec un mode vESCAPE_HIT. À la place, elle aura comme effet d’activer le menu déroulant (que nous n’avons pas encore vu et que nous verrons au paragraphe suivant), s’il y en a un de défini. La sortie de la fonction traverseCDKScreen peut se faire de deux façons, soit de façon " normale " par appui sur la touche [F10], le membre cdkscreen->exitStatus est alors défini à CDKSCREEN_EXITOK, ou alors par la combinaison [Ctrl+X], le membre cdkscreen->exitStatus est alors défini à CDKSCREEN_EXITCANCEL. Dans notre cas, nous avons ajouté les deux boutons permettant de sortir de façon plus " classique " du formulaire, en utilisant dans les fonctions de callback des boutons les fonctions exitOKCDKScreen et exitCancelCDKScreen.

    2.2 Des formulaires

    Une fonctionnalité particulièrement intéressante de CDK que nous n’avons pas encore abordée et qui justifie le premier argument (cdkscreen) de toutes les créations de widgets est son aptitude à prédéfinir plusieurs " écrans " et de pouvoir passer facilement de l’un à l’autre. On peut donc facilement avoir plusieurs pages de formulaires et passer de l’un à l’autre. Dans l’exemple qui suit, pour ne pas alourdir la démonstration, nous n’avons pas défini deux formulaires complets, mais juste un widget CDKEntry sur deux " écrans " différents.

    #include <cdk/cdk.h>

    int main() {

    CDKSCREEN *cdkscreen1,*cdkscreen2;

    WINDOW *cursesWin;

    CDKLABEL *titre1,*titre2;

    CDKENTRY *entry1,*entry2;

    char *mesg[10];

    char *boutons[] ={"Oui","Non"};

    boolean oncontinue=TRUE;

    int choix;

    /* Initialisation */

    cursesWin = initscr();

    cdkscreen1 = initCDKScreen (cursesWin);

    cdkscreen2 = initCDKScreen (cursesWin);

    /* Initialisation des couleurs CDK */

    initCDKColor();

    /* Ecran 1 */

    /* Définition du titre */

    mesg[0]="</48>Cdkscreen 1";

    titre1 = newCDKLabel(cdkscreen1,

    CENTER, /* coordonnée sur x : colonne de debut*/

    TOP, /* coordonnée sur y : ligne de début en partant du haut */

    mesg, /* le tableau de caractere contenant le label */

    1, /* le nombre de lignes à afficher */

    FALSE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    /* Un widget Entry */

    entry1 = newCDKEntry(cdkscreen1,

    2, /* coordonnée sur x : colonne de debut*/

    2, /* coordonnée sur y : ligne de début en partant du haut */

    "", /* Le titre de l’entrée */

    "Prenom :", /* texte affiché devant le champ de saisie */

    COLOR_PAIR(24), /* Attribut du texte saisi par l’utilisateur */

    ‘_’|COLOR_PAIR(24), /* Caractère à utiliser pour remplir le champ */

    vMIXED, /* Filtre de caratères (man cdk_display) */

    20, /* Largeur du champ. 0 -> champ le plus large possible à l’écran

    -N -> champ le plus large possible moins

    N caractères */

    0, /* Taille minimale de la saisie */

    256, /* Taille maximale de la saisie */

    FALSE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    /* Ecran 2 */

    /* Définition du titre */

    mesg[0]="</48>Cdkscreen 2";

    titre2 = newCDKLabel(cdkscreen2,

    CENTER, /* coordonnée sur x : colonne de debut*/

    TOP, /* coordonnée sur y : ligne de début en partant du haut */

    mesg, /* le tableau de caractere contenant le label */

    1, /* le nombre de lignes à afficher */

    FALSE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    /* Un widget Entry */

    entry2 = newCDKEntry(cdkscreen2,

    2, /* coordonnée sur x : colonne de debut*/

    2, /* coordonnée sur y : ligne de début en partant du haut */

    "", /* Le titre de l’entrée */

    "Nom :", /* texte affiché devant le champ de saisie */

    COLOR_PAIR(24), /* Attribut du texte saisi par l’utilisateur */

    ‘_’|COLOR_PAIR(24), /* Caractère à utiliser pour remplir le champ */

    vMIXED, /* Filtre de caratères (man cdk_display) */

    20, /* Largeur du champ. 0 -> champ le plus large possible à l’écran

    -N -> champ le plus large possible moins

    N caractères */

    0, /* Taille minimale de la saisie */

    256, /* Taille maximale de la saisie */

    FALSE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    while (oncontinue)

    {

    /* Affichage screen 1 */

    refreshCDKScreen (cdkscreen1);

    activateCDKEntry(entry1,0);

    eraseCDKScreen (cdkscreen1);

    refreshCDKScreen (cdkscreen2);

    activateCDKEntry(entry2,0);

    mesg[0]="Voulez vous continuer?";

    eraseCDKScreen (cdkscreen2);

    choix=popupDialog(cdkscreen2,mesg,1,boutons,2);

    if (choix == 1)

    {

    oncontinue=FALSE;

    }

    }

    /* on nettoie avant de quitter */

    destroyCDKLabel (titre1);

    destroyCDKLabel (titre2);

    destroyCDKEntry (entry1);

    destroyCDKEntry (entry2);

    destroyCDKScreen (cdkscreen1);

    destroyCDKScreen (cdkscreen1);

    endCDK();

    }

    Dans cet exemple, on affiche le premier formulaire refreshCDKScreen (cdkscreen1) et on l’active avec activateCDKEntry (entry1,0) (comme on n’a qu’un widget, on ne s’est pas servi de traverse, mais ça marche évidemment aussi). Une fois quitté le premier formulaire, on l’efface avec eraseCDKScreen (cdkscreen1), puis on fait la même chose avec le second formulaire. On affiche ensuite un dialogue demandant si l’on veut continuer et si oui on repart sur le premier formulaire. L’intérêt de cette méthode, c’est que les objets ne sont pas détruits puis recréés. On a donc rémanence des informations. On voit que cette fonctionnalité combinée à traverse et aux fonctions de binding, peut permettre de créer des interfaces très riches.

    3 Qu’y a-t-il au menu ?

    Pour terminer, CDK possède un widget de menus déroulants nommé CDKMenu (man cdk_menu). Voici un exemple de programme utilisant ce widget. La sortie écran correspondante se trouve en figure 6 (page 69).

    #include <cdk/cdk.h>

    int displayCallback (EObjectType cdktype, void *object, void *clientData, chtype input);

    char *menuInfo[4][4];

    int main() {

    CDKSCREEN *cdkscreen;

    WINDOW *cursesWin;

    CDKMENU *menu;

    CDKLABEL *infoBox;

    CDKLABEL *monlabel;

    int selection;

    char *menulist[MAX_MENU_ITEMS][MAX_SUB_ITEMS];

    int submenusize[4], menuloc[4];

    char *mesg[3],temp[256];

    char *letexte[5];

    menulist[0][0]="</40>Menu 1<!40>";

    menuInfo[0][0]="";

    menulist[1][0]="</40>Menu 2<!40>";

    menuInfo[1][0]="";

    menulist[2][0]="</40>Menu 3<!40>";

    menuInfo[2][0]="";

    menulist[3][0]="</40>Menu 4<!40>";

    menuInfo[3][0]="";

    menulist[0][1]="</56>Menu 1 Item 1<!56>";

    menuInfo[0][1]="Information Menu 1 Item 1";

    menulist[0][2]="</56>Menu 1 Item 2<!56>";

    menuInfo[0][2]="Information Menu 1 Item 2";

    menulist[0][3]="</56>Menu 1 Item 3<!56>";

    menuInfo[0][3]="Information Menu 1 Item 3";

    submenusize[0]=4;

    menuloc[0]=LEFT;

    menulist[1][1]="</56>Menu 2 Item 1<!56>";

    menuInfo[1][1]="Information Menu 2 Item 1";

    menulist[1][2]="</56>Menu 2 Item 2<!56>";

    menuInfo[1][2]="Information Menu 2 Item 2";

    submenusize[1]=3;

    menuloc[1]=LEFT;

    menulist[2][1]="</56>Menu 3 Item 1<!56>";

    menuInfo[2][1]="Information Menu 3 Item 1";

    menulist[2][2]="</56>Menu 3 Item 2<!56>";

    menuInfo[2][2]="Information Menu 3 Item 2";

    menulist[2][3]="</56>Menu 3 Item 3<!56>";

    menuInfo[2][3]="Information Menu 3 Item 3";

    submenusize[2]=4;

    menuloc[2]=LEFT;

    menulist[3][1]="</56>Menu 4 Item 1<!56>";

    menuInfo[3][1]="Information Menu 4 Item 1";

    submenusize[3]=2;

    menuloc[3]=RIGHT;

    /* Initialisation */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    /* Pour désactiver Ctrl-C : raw(); */

    raw();

    /* Initialisation des couleurs CDK */

    initCDKColor();

    /* A l’activation du menu il n’y a pas de callback on initialise

    donc la chaine d’information au premier menu */

    mesg[0]="</48>Information Menu 1 Item 1<!48>";

    infoBox = newCDKLabel (cdkscreen, LEFT, BOTTOM, mesg, 1, FALSE, FALSE);

    menu = newCDKMenu(cdkscreen,

    menulist, /* tableau de chaines à 2 dimensions contenant les menus */

    4, /* Nombre de menus */

    submenusize, /* tableau d’entier contenant le nombre de choix

    de chaque menu */

    menuloc, /* tableau d’entier indiquant par les valeurs

    RIGHT ou LEFT la position du menu */

    TOP, /* Position des menus TOP ou BOTTOM */

    A_BOLD, /* Attribut du menu courant */

    A_REVERSE); /* Attribut du choix courant */

    /* Fonction de callback appelée à chaque modification de l’item courant */

    setCDKMenuPostProcess (menu, displayCallback, infoBox);

    letexte[0]="<C></24>Naviguez dans les menus en utilisant les fleches";

    letexte[1]="<C></24>Sélectionnez avec Entrée";

    letexte[2]="";

    letexte[3]="<C></24>Pour quitter ce programme";

    letexte[4]="<C></24>Utilisez la touche Echap";

    /* Définition du label principal */

    monlabel = newCDKLabel(cdkscreen,

    CENTER, /* coordonnée sur x : colonne de debut*/

    CENTER, /* coordonnée sur y : ligne de début en partant du haut */

    letexte, /* le tableau de caractere contenant le label */

    5, /* le nombre de lignes à afficher */

    TRUE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    /* On affiche */

    refreshCDKScreen (cdkscreen);

    selection=0;

    while(menu->exitType != vESCAPE_HIT)

    {

    selection=activateCDKMenu(menu,0);

    if (menu->exitType == vNORMAL)

    {

    sprintf(temp,"</48>Selection menu #%d, submenu #%d<!48>", 1+selection/100, 1+selection%100);

    mesg[0] = copyChar (temp);

    mesg[1] = "";

    mesg[2] = "</48>Appuyez sur une touche.<!48>";

    popupLabel(cdkscreen,mesg,3);

    } else

    {

    /* sortie du menu sans selection (esc) */

    mesg[0] = "</48>Sortie du menu sans selection<!48>";

    mesg[1] = "";

    mesg[2] = "</48>Appuyez sur une touche.<!48>";

    popupLabel(cdkscreen,mesg,3);

    }

    }

    /* on nettoie avant de quitter */

    destroyCDKScreen (cdkscreen);

    endCDK();

    printf("selection %i\n",selection);

    }

    int displayCallback (EObjectType cdktype, void *object, void *clientData, chtype input)

    {

    CDKMENU *menu = (CDKMENU *)object;

    CDKLABEL *infoBox = (CDKLABEL *)clientData;

    char *mesg[1];

    char temp[256];

    sprintf (temp,"</48>%s<!48>",menuInfo[menu->currentTitle][menu->currentSubtitle+1]);

    mesg[0] = copyChar (temp);

    /* On change le message d’information */

    setCDKLabel (infoBox, mesg, 1, FALSE);

    drawCDKLabel (infoBox, FALSE);

    /* Nettoyage */

    freeChar (mesg[0]);

    return 0;

    }

    Les textes des menus déroulants sont contenus dans un tableau de chaînes de caractères à deux dimensions, dont les dimensions sont imposées : char *menulist[MAX_MENU_ITEMS][MAX_SUB_ITEMS]. Le premier indice correspond au menu principal et le second indice au choix dans ce menu. Deux tableaux d’entiers additionnels sont nécessaires pour définir le CDKMenu : un tableau d’entiers submenusize contient pour chaque menu principal le nombre de choix dans celui-ci ; un autre tableau d’entiers menuloc contient pour chaque menu principal soit RIGHT, soit LEFT suivant qu’ils doivent se positionner à droite ou à gauche.

    Nous avons dans cet exemple ajouté également une fonction de binding spécifique aux menus : setCDKMenuPostProcess. Grâce à cette instruction, à chaque fois que l’utilisateur va changer le menu courant, la fonction de callback displayCallback va être appelée. Dans notre exemple, la fonction de callback va lire la position du menu courant et modifier le texte du CDKLabel infoBox en affichant la chaîne d’information sur le menu définie dans le tableau de chaînes menuInfo. On a donc une actualisation automatique du label lors de la navigation dans les menus.

    Comme les autres widgets, le menu s’active avec la fonction associée d’activation activateCDKMenu. La valeur retournée est égale à 100*i+j où i est l’indice (base 0) du menu principal et j l’indice (base 0) du choix dans ce menu.

    La fonction traversCDKScreen vue dans la section précédente gère parfaitement les menus. La touche [Echap] active alors le menu.

    Notons enfin l’appel de la fonction raw() qui désactive la combinaison [Ctrl+C]. En effet, par défaut, tous les programmes ncurses (et CDK) peuvent être interrompus par [Ctrl+C], ce qui peut être très utile lors du développement, mais peut être contrariant dans une application en production.

    menu copie copie.TIF

    Figure 6 : Menus déroulants

    4 Conclusion

    Voilà, nous arrivons au terme de ce petit tutoriel. Vous devriez maintenant être en mesure de pouvoir réaliser vos interfaces consoles rapidement avec cette excellente bibliothèque CDK.

    Il y a encore de nombreux points de CDK qui n’ont pas été abordés, des widgets supplémentaires comme CDKCalendar, CDKSlider ou encore d’autres fonctionnalités comme les fonctions lowerCDKObject et raiseCDKObject permettant de gérer des objets superposés en faisant passer respectivement à l’arrière-plan et l’avant plan un objet.

    Également très utile, la fonction associée positionCDKxxxx qui permet de déplacer un widget interactivement. La lecture des pages de manuel et des headers fera le reste...

    Références

    [1] Curses Development Kit : http://invisible-island.net/cdk/

    [2] Fichiers d’exemples de ce tutoriel : http://www.femto-st.fr/~daniau/CDK/

    Retrouvez cet article dans : Linux Magazine 108

    Vous souhaitez commenter cet article ?
    Brèves Flux RSS
    Édito : GNU/Linux Magazine 149
    Édito : GNU/Linux Magazine HS N°60
    Édito : Misc 61
    Édito : Linux Pratique 71
    Édito : Linux Essentiel N°25
    Communication RSS Com. RSS Presse
    Lancement de la plateforme de vente en ligne de PDF des Éditions Diamond ! Un...
    Misc N°61 – Communiqué de presse
    GNU/Linux Magazine N°149 – Communiqué de presse
    GNU/Linux Magazine HS N°60 – Communiqué de presse
    Linux Pratique N°71 – Communiqué de presse
    prochainement moteur de recherches des articles
     
    :
    :
    Jours heures minutes secondes
    En kiosque Flux RSS

    Le tout nouveau GNU/Linux Magazine est disponible dès maintenant chez votre marchand de journaux et sur notre site marchand.

    Découvrez le sommaire de ce numéro et un aperçu de ce magazine...

    Lire la suite...

    Le tout nouveau Misc est disponible dès maintenant chez votre marchand de journaux et sur notre site marchand.

    Découvrez le sommaire de ce numéro et un aperçu de ce magazine...

    Lire la suite...

    Le tout nouveau Linux Pratique est disponible dès maintenant chez votre marchand de journaux et sur notre site marchand.

    Découvrez le sommaire de ce numéro et un aperçu de ce magazine...

    Lire la suite...

    Le tout nouveau GNU/Linux Magazine HS est disponible dès maintenant chez votre marchand de journaux et sur notre site marchand.

    Découvrez le sommaire de ce numéro et un aperçu de ce magazine...

    Lire la suite...

    Le tout nouveau Linux Essentiel est disponible dès maintenant chez votre marchand de journaux et sur notre site marchand.

    Découvrez le sommaire de ce numéro et un aperçu de ce magazine...

    Lire la suite...

    Le tout nouveau Misc HS est disponible dès maintenant chez votre marchand de journaux et sur notre site marchand.

    Découvrez le sommaire de ce numéro et un aperçu de ce magazine...

    Lire la suite...