Catégorie : Programmation     Tags :      0 Commentaire

    Retrouvez cet article dans : Linux Magazine 107

    Cet article se veut être une introduction à CDK dans laquelle nous allons présenter, via des exemples, les widgets les plus utiles, afin de pouvoir réaliser très rapidement des interfaces en mode console performantes.

    Même en 2008, il y a de nombreuses situations où l’on peut souhaiter réaliser des interfaces en mode console ; en fait, à chaque fois qu’il n’est pas possible d’utiliser X11. Que ce soit par manque de bande passante (si, si, tout le monde n’a pas du très haut débit, ma liaison ne dépasse pas le Mbit/s) ou tout simplement parce que X11 n’est pas disponible du tout, par exemple dans un système embarqué, dans un système live de secours etc., etc.

    Pour développer des interfaces en mode console, il existe une bibliothèque qui se trouve sur tous les systèmes Linux, et qui s’appelle ncurses. ncurses est aux interfaces console ce que xlib est aux interfaces graphiques. Il y a dans ncurses tout ce qui est nécessaire pour créer des interfaces en mode console, en restant assez bas niveau. Bien que dans la collection des howto standards, on trouve un Ncurses howto, il n’en reste pas moins que ncurses n’est pas une bibliothèque qui s’aborde de façon très intuitive et il faut y passer beaucoup de temps avant de pouvoir programmer une interface convenable.

    Il existe une bibliothèque plus haut niveau et plus facile à aborder, regroupant de nombreux widgets pré-construits. Il s’agit de CDK, un acronyme pour Curses Development Kit [1]. CDK est une bibliothèque écrite en C. Elle n’en est pas moins écrite dans un esprit très orienté objet, chaque widget ayant des méthodes sous forme de fonctions associées. Une définition rigoureuse des structures et le transtypage des pointeurs permet d’avoir également un semblant d’héritage. CDK est très bien documenté, les pages de manuel sont détaillées (bien que comportant quelques erreurs de copier/coller). On prendra soin de les consulter systématiquement pour chaque widget. La lecture des headers (*.h) peut également s’avérer très utile, les structures n’étant pas décrites dans les pages de manuel. La plupart des widgets comportent un petit programme d’exemple, mais ceux-ci ne sont malheureusement pas écrits de manière très didactique et leur lecture n’est pas triviale.

    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.

    Afin de rendre l’article plus " digeste ", celui-ci est divisé en deux parties. Dans la première partie, nous aborderons les bases de la programmation avec CDK et quelques widgets simples ; dans la seconde partie, nous examinerons des widgets plus élaborés, ainsi que la réalisation de pages de formulaires et de menus déroulants.

    1

    Installation

    Tout d’abord, il va nous falloir installer CDK. Avant tout, vérifiez que les paquets ncurses et développement ncurses sont installés sur votre machine.

    CDK est inclus dans certaines distributions (c’est le cas de l’OpenSUSE 10.3 par exemple, mais la version disponible est la version 4.9). Si c’est le cas, vous pouvez installer le paquet correspondant à CDK et son paquet de développement associé. Évitez néanmoins d’utiliser une version antérieure à la version 5.0. Le mieux est de récupérer le tarball à l’adresse en référence [1]. L’installation se fait de manière on ne peut plus classique :

    ./configure

    make

    make install

    Par défaut, l’installation se fera dans /usr/local. La bibliothèque créée, libcdk.a, est une bibliothèque statique, ce qui fait que les programmes compilés ne seront dynamiquement liés qu’à ncurses.

    2

    Hello World!

    On n’y coupera pas ! Notre premier programme CDK sera un classique Hello World!. Pour cela, le premier widget que nous allons utiliser sera un Label (man cdk_label). Comme nous allons le voir, chaque widget possède des fonctions associées (que nous n’appellerons pas méthodes, car il s’agit de langage C, mais l’esprit est le même). Nous n’allons pas détailler toutes ces fonctions ici, elles le sont dans les pages de manuel qu’il faudra consulter avant d’utiliser un widget donné. La bibliothèque est très bien faite et les noms des fonctions sont assez " self exponents” " pour parler français.

    Voici donc notre premier programme CDK :

    #include <cdk/cdk.h>

    int main() {

    CDKSCREEN *cdkscreen;

    WINDOW *cursesWin;

    CDKLABEL *monlabel;

    char *letexte[3];

    letexte[0]="Premier programme CDK";

    letexte[1]="";

    letexte[2]="Hello World!";

    /* Initialisation CDK */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    /* Définition du label */

    monlabel = newCDKLabel(cdkscreen,

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

    CENTER,

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

    CENTER,

    /* le tableau de caractere contenant le label */

    letexte,

    /* le nombre de lignes à afficher */

    3,

    /* Dessiner un boite autour? */

    TRUE,

    /* Dessiner une ombre? */

    FALSE);

    /* On affiche */

    refreshCDKScreen (cdkscreen);

    /* On attend que l’utilisateur appuie sur une touche */

    waitCDKLabel(monlabel,’ ‘);

    /* on nettoie avant de quitter */

    destroyCDKLabel (monlabel);

    destroyCDKScreen (cdkscreen);

    endCDK();

    }

    On compilera ce programme avec la commande :

    gcc hello_world.c -lcdk -lncurses -o hello_world

    ce qui à l’exécution nous donnera l’écran Fig. 1.

    Nous allons détailler les différentes parties de ce programme. Tout d’abord le squelette de tout programme CDK se présentera comme suit :

    helloworld1 copie copie.tif

    Figure 1 : Hello World

    #include <cdk/cdk.h>

    int main() {

    CDKSCREEN *cdkscreen;

    WINDOW *cursesWin;

    ...

    déclarations etc

    ...

    /* Initialisation CDK */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    ...

    trucs divers et varié dont appels cdk

    ...

    /* nettoyage CDK */

    ...

    appel des fonctions destroyCDKxxxx

    ...

    destroyCDKScreen (cdkscreen);

    endCDK();

    }

    La définition du label en elle-même est assez simple. Les commentaires en face de chaque paramètre expliquent leurs fonctions. Ce qu’il faut noter ici, c’est l’utilisation de la fonction waitCDKLabel(monlabel,´ ´); qui attend simplement que l’utilisateur entre le caractère spécifié (ici une espace). Contrairement aux systèmes d’interfaces graphiques modernes comme Qt ou Tk ou autre, il n’y a pas dans CDK et encore moins dans ncurses de gestion de la boucle événementielle. C’est un travail laissé au programmeur, ce qui change un peu la philosophie. Par conséquent, sans cette fonction, le programme passerait immédiatement au nettoyage CDK juste après avoir affiché le label... donc, on ne verrait rien !

    À noter également nombre de #define dans le fichier cdk.h permettant de simplifier l’écriture des programmes, comme CENTER, LEFT, RIGHT, TOP, BOTTOM que l’on peut utiliser dans le système de coordonnées.

    3

    Plus beau, plus fun

    Dans ncurses, les couleurs vont toujours par paires, une couleur de fond et une couleur de caractère. CDK prédéfinit 64 paires de couleurs. On pourra les visualiser avec le programme paires.c disponible ici [2].

    Bien qu’on puisse utiliser (et nous le ferons dans certains cas, comme nous le verrons plus tard) la macro ncurses COLOR_PAIR, CDK offre une façon très simple (man cdk_display) basée sur des tags " à la html " de gérer le formatage des textes et leurs couleurs. Les instructions de formatage et de couleur sont écrites dans les chaînes de caractères elles-mêmes, ainsi :

    (hello_world2.c)

    ....

    ....

    letexte[0]="</48>Premier programme CDK<!48>";

    letexte[1]="";

    letexte[2]="</59>Hello World!<!59>";

    /* Initialisation */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    /* Initialisation des couleurs CDK */

    initCDKColor();

    ....

    ....

    va demander à CDK d’utiliser la paire de couleurs numéro 48 pour la première ligne et la paire de couleurs numéro 59 pour la troisième ligne. Il faut toutefois initialiser le système de couleurs par l’appel de la fonction initCDKColor();. On obtiendra alors l’écran Fig. 2

    helloworld1 copie copie.tif

    Figure 1 : Hello World

    helloworld2 copie copie.TIF

    Figure 2 : Hello World plus fun...

    Le tableau suivant (Tableau 1) liste les tags les plus utiles.

    </xx>Text<!xx>

    Applique au texte la paire de couleurs xx (xx=1 à 64)

    </B>Text<!B>

    Texte en gras

    </U>Text<!U>

    Texte souligné

    </K>Text<!K>

    Texte clignotant

    </R>Text<!R>

    Texte en inverse vidéo

    </N>Text<!N>

    Texte normal

    Tableau 1 : Les tags les plus utiles

    Le plus beau, c’est que les tags peuvent se combiner, ainsi </B/48>Voici<!B> un texte<!48> aura pour résultat l’ensemble de la chaîne avec la paire de couleurs 48 et le mot " Voici "en gras.

    Pour finir, CDK offre également des tags pour la justification et même les listes à puces. Ces tags se placent au début de la chaîne de caractères et sont listés dans le tableau 2.

    <L>Ma phrase

    Justification à gauche

    <R>Ma phrase

    Justification à droite

    <C>Ma phrase

    Justification centrée

    <I=X>Ma phrase

    X=entier : indentation de X caractères

    <B=X>Mon item

    X=caractère : place une puce

    Tableau 2 : Les tags de justification

    Pour finir ce paragraphe, un dernier exemple combinant divers tags. Il faudra penser à modifier dans la fonction newCDKLabel le nombre de lignes à afficher à 10. La sortie écran générée en Fig. 3.

    (hello_world3.c)

    ....

    char *letexte[10];

    letexte[0]="<L></48>Une ligne justifiée à </B>gauche<!B!48>";

    letexte[1]="<R></61>Une ligne justifiée à </K>droite<!K!61>";

    letexte[2]="</36>Une ligne un peu longue dont le seul but est d’agrandir la boite<!36>";

    letexte[3]="<C></13>une ligne </U>centrée<!U!13>";

    letexte[4]="";

    letexte[5]="<B=*></U/24>Item<!U> 1<!24>";

    letexte[6]="<B=*></24>Item 2<!24>";

    letexte[7]="";

    letexte[8]="<I=10></16>Indentation de 10 caractères<!16>";

    letexte[9]="<I=15></16>Indentation de 15 caractères<!16>";

    ....

    /* Définition du label */

    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 */

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

    TRUE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    ....

    }

    helloworld3 copie copie.tif

    Figure 3 : Toujours plus fun ...

    4

    Dialoguons

    Un label, c’est bien, ça peut même être beau, mais c’est un peu léger même pour la plus simple des interfaces. La première des fonctionnalités, c’est de pouvoir poser des questions à l’utilisateur. CDK propose un widget composé d’un label et d’un choix de réponses fixées sous la forme de boutons. La plupart du temps, on répondra par oui ou par non, mais on n’est pas limité à deux choix. Pour l’exemple suivant, nous avons trois choix : oui, non ou grumpf. La sortie écran est donnée en Fig. 4.

    Les commentaires dans l’exemple indiquent la fonction des différents paramètres. Le point nécessitant une petite explication est le paramètre highlight, le huitième de la fonction newCDKDialog qui spécifie l’attribut du bouton actuellement sélectionné par l’utilisateur. Il s’agit en fait de l’attribut ncurses, le tableau 3 en liste les plus utiles. À noter que ces attributs ncurses peuvent être combinés avec des " ou " binaires. Par exemple, A_UNDERLINE|A_BLINK donnera un caractère souligné clignotant.

    A_NORMAL

    Je vois vraiment pas ce que ça peut être :)

    A_UNDERLINE

    caractère souligné

    A_REVERSE

    caractère en inverse vidéo

    A_BOLD

    caractère gras

    A_BLINK

    caractère clignotant

    COLOR_PAIR(n)

    Utiliser la paire de couleurs n

    Tableau 3 : Attributs ncurses les plus utiles

    dialog1 copie copie.TIF

    Figure 4 : Dialogue CDKDialog

    La nouveauté ici est l’utilisation de la fonction associée activate, en l’occurrence ici activateCDKDialog. Cette fonction va gérer la boucle événementielle pour nous, c’est elle qui va décider ce qu’il convient de faire quand l’utilisateur appuie sur telle ou telle touche, c’est-à-dire changer de bouton actif, valider l’entrée, etc. Toutes les structures de widgets ont un membre de type int appelé exitType que l’on va pouvoir tester à la sortie de la fonction. Cet élément prend les valeurs indiquées en Tableau 4. À noter, une autre valeur possible vEARLY_EXIT que nous ne discuterons pas dans ce tutoriel. Remarquons donc que le comportement standard de CDK est qu’on peut toujours sortir des fonctions activate avec la touche d’échappement, libre au programmeur de shunter cette possibilité, si cela ne lui convient pas.

    vNORMAL

    Sortie normale du widget

    vESCAPE_HIT

    Sortie par la touche Echap

    vNEVER_ACTIVATED

    État initial

    Tableau 4 : Valeurs du membre exitType

    En ce qui concerne la récupération des informations du widget, elle se fera suivant les cas directement par la fonction activate comme c’est le cas ici, par des fonctions associées spécifiques ou encore en accédant à la structure.

    Dans cet exemple, nous introduisons également deux fonctions très utiles, décrites dans man cdk_util à savoir popupLabel et popupDialog. popupLabel affiche un label au centre de l’écran et attend une touche quelconque au clavier après quoi ce label disparaît. popupDialog affiche un dialogue au centre de l’écran et attend le choix de l’utilisateur (la valeur -1 est retournée si on sort par la touche Echap), puis ce dialogue disparaît. Ces deux fonctions regroupent donc une création d’objet, son affichage, son activation et sa destruction. Les options de configuration de ces label et dialogue sont par contre moins nombreuses.

    Nous allons maintenant faire une petite expérience en notant tout d’abord que, dans notre exemple, le CDKDialog " question " reste présent à l’écran après qu’on ait quitté l’activation comme on peut le voir en Fig. 5 contrairement aux versions pop-up qui s’effacent automatiquement.

    L’effacement d’un widget se fait avec la fonction associée erase, dans notre cas l’ajout suivant :

    ...

    selection = activateCDKDialog (question, 0);

    eraseCDKDialog(question);

    /* Comment on a quitté et ce qu’on a répondu */

    ...

    effacera de l’écran le dialogue une fois terminée son utilisation. Mais attention, le widget n’est pas détruit, il est juste effacé de l’écran. On pourra le tracer à nouveau individuellement grâce à la fonction associée draw, et il sera également affiché de nouveau à chaque rafraîchissement de l’écran, ce qui a lieu notamment après la fermeture d’une fenêtre pop-up comme on le constatera en exécutant ce programme. Si on souhaite qu’il disparaisse, il faudra utiliser la fonction associée destroy qui efface l’objet et libère tout l’espace mémoire qui lui était alloué. Ainsi, si l’on déplace l’instruction destroyCDKDialog(question) utilisée pour le nettoyage final en fin de programme à la place du eraseCDKDialog(question), on pourra constater que effectivement le dialogue ne réapparaît plus.

    5

    Soyons plus ouverts

    Avec les dialogues, nous avons vu comment poser une question fermée à l’utilisateur. Nous allons maintenant voir comment lui poser des questions ouvertes avec la famille de widgets Entry. Cette famille comporte trois widgets, CDKEntry pour les entrées simples, CDKTemplate pour des entrées comportant un masque de saisie et enfin CDKMentry pour des entrées multilignes.

    5.1

    Entrée simple et callback

    dialog2 copie copie.tif

    Figure 5 : Dialogue CDKDialog après entrée utilisateur

    Voyons tout d’abord un exemple d’entrée simple :

    #include <cdk/cdk.h>

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

    int main() {

    WINDOW *cursesWin;

    CDKENTRY *saisie;

    CDKSCREEN *cdkscreen;

    CDKLABEL *compteur;

    char *titre = "<C></32>Entrez quelquechose (F1 pour l’aide)";

    char *label = "</24/B>Saisie :";

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

    /* Initialisation */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    /* Initialisation des couleurs CDK */

    initCDKColor();

    mesg[0]="</48>Aide non utilisée ";

    compteur = newCDKLabel(cdkscreen,

    LEFT,

    BOTTOM,

    mesg,

    1,

    FALSE,

    FALSE);

    saisie = newCDKEntry(cdkscreen,

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

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

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

    label, /* texte affiché devant le champ de saisie */

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

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

    /* Cette méthode de définition des attributs/couleurs utilisant le | est courante en ncurses */

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

    40, /* 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 */

    TRUE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    bindCDKObject (vENTRY, saisie, KEY_F (1), saisieCB, compteur); /* (man cdk_bind) */

    /* si la touche F1 est appuyée, on appelle la fonction saisieCB avec les paramètre suivant :

    saisieCB(vENTRY,saisie,compteur,KEY_F (1)) */

    /* On affiche */

    refreshCDKScreen (cdkscreen);

    while(saisie->exitType != vNORMAL) /* on ne sort pas sur un ESC */

    {

    info = activateCDKEntry (saisie, 0);

    }

    mesg[0] = "<C>Vous avez saisi :";

    sprintf (temp,"<C></24>%s",info);

    mesg[1] = copyChar (temp); /* copyChar fait partie de CDK -> strdup */

    mesg[2] = "";

    mesg[3] = "<C>Appuyez sur une touche";

    popupLabel (cdkscreen, mesg, 4);

    /* on nettoie avant de quitter */

    destroyCDKLabel (compteur);

    destroyCDKEntry (saisie);

    destroyCDKScreen (cdkscreen);

    endCDK();

    exit(TRUE);

    }

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

    {

    CDKSCREEN *screen;

    CDKLABEL *label=(CDKLABEL *)clientData;

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

    static int count;

    /* on récupère le cdkscreen pour pouvoir afficher le popupLabel */

    screen = ((CDKOBJS *)object)->screen;

    count++;

    sprintf(temp,"</48>Aide utilisée %i fois<!48>",count);

    mesg[0]=copyChar(temp);

    setCDKLabelMessage(label,mesg,1);

    freeChar(mesg[0]);

    mesg[0]="<C></B/2>Information sur la saisie";

    mesg[1]="";

    mesg[2]="<C>Ben ... ya qu’à taper puis appuyer sur";

    mesg[3]="<C>la touche entrée!";

    popupLabel(screen,mesg,4);

    return(TRUE);

    }

    Comme il n’y a pas beaucoup de différence avec l’utilisation du widget CDKDialog précédemment décrit, à savoir création du widget avec la fonction associée newCDKEntry, puis activation du widget avec activateCDKEntry, j’en ai profité pour introduire dans cet exemple un concept particulièrement utile de CDK permettant de rendre les widgets beaucoup plus dynamiques, à savoir les fonctions callback. Avant d’aborder ce point, un commentaire sur le huitième paramètre de la fonction newCDKentry, le filtre de caractère nommé displayType dans la page de manuel (man cdk_entry) et qui est de type EdisplayType. Les valeurs possibles pour ce type énuméré CDK sont détaillées dans la page de manuel man cdk_display. vMIXED signifie qu’on accepte tous les caractères, vCHAR aurait par exemple forcé à n’utiliser que des caractères alphabétiques et vINT uniquement des caractères numériques.

    Revenons maintenant à nos fonctions callback. Tout d’abord, quel va être le comportement de ce programme ? Le widget saisie va s’afficher et attendre la saisie utilisateur. Si celui-ci appuie sur la touche [F1], un popuLabel d’aide va s’afficher, et le label compteur en bas à gauche va changer son affichage pour indiquer combien de fois l’aide a été utilisée (Fig. 6). Cela est réalisé grâce à la fonction bindCDKObject (man cdk_binding) :

    bindCDKObject (vENTRY, /* le type du widget */

    saisie, /* le widget */

    KEY_F (1), /* La touche (définition ncurses voir /usr/include/ncurses.h ) */

    saisieCB, /* La fonction à appeler */

    compteur); /* un pointeur facultatif sur un objet CDK ou autre */

    Le prototype des fonctions de callback CDK écrites par l’utilisateur doit correspondre à celui-ci :

    static int XXXCB (EObjectType cdktype,

    void *object,

    void *clientData,

    chtype key)

    {

    return (TRUE);

    }

    Le type EObjectType est un type énuméré CDK dont les valeurs possibles sont décrites dans la page de manuel cdk_binding. Il représente le type de widget. Pour résumer, lorsque le widget saisie sera activé et que l’utilisateur appuiera sur la touche [F1], notre fonction de callback saisieCB sera appelée avec les paramètres suivants :

    saisieCB(vENTRY,saisie,compteur,KEY_F (1))

    Pour finir sur cet exemple, dans la routine saisieCB, nous avons besoin pour afficher le popupLabel du pointeur sur le screen CDK de l’objet appelant saisie. Il y a au moins trois méthodes pour cela.

    entrycb copie copie.TIF

    Figure 6 : Appui sur la touche [F1] lors de la saisie

    5.1.1

    Méthode 1

    CDK fournit une macro nommée ScreenOf qui renvoie le CDKSCREEN associé au widget, mais il est nécessaire de fournir à cette macro un pointeur typé alors que celui que la fonction reçoit est de type void. Il est donc nécessaire de le transtyper :

    screen = ScreenOf((CDKENTRY *)object);

    5.1.2

    Méthode 2

    Toutes les structures des widgets CDK sont construites de telle sorte que leur premier membre obj est un pointeur sur une structure CDKOBJS. Le membre screen de cette structure est le paramètre qui nous intéresse. Comme obj est le premier membre de la structure, on peut directement transtyper en CDKOBJS notre pointeur :

    screen = ((CDKOBJS *)object)->screen;

    5.1.3

    Méthode 3

    On peut aussi accéder au membre obj, puis au membre screen directement, mais l’écriture qui en résulte commence à ressembler à ce que je déteste en C, mais chacun ses goûts...

    screen = (&((CDKENTRY *)object)->obj)->screen;

    5.2

    Entrée multiligne

    Le widget CDKMentry (man cdk_mentry) permet de faire une entrée utilisateur sur plusieurs lignes. Je ne reporte ici que la partie création, l’utilisation étant similaire à ce que l’on a déjà vu.

    saisie = newCDKMentry(cdkscreen,

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

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

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

    label, /* texte affiché devant le champ de saisie */

    A_REVERSE|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) */

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

    -N -> champ le plus large possible moins N caractères */

    5, /* Hauteur du champ (même règles que pour la largeur) */

    3, /* Nombre de lignes du champ -> comportement un peu curieux

    puisque le caractère de remplissage rempli de toute façon toutes

    les lignes. Du coup ça ne sert qu’à limiter la taille maximale de saisie */

    9, /* Taille minimale de la saisie -1 => -1 correspond à 0 */

    TRUE, /* Dessiner un boite autour? */

    FALSE); /* Dessiner une ombre? */

    La sortie écran correspondante se trouve en Fig. 7.

    mentry copie copie.tif

    Figure 7 : Entrée multiligne

    5.3

    Template

    Le widget CDKTemplate (man cdk_template) permet de créer des masques de saisie comme dans cet exemple où l’on demande à l’utilisateur sa date de naissance :

    #include <cdk/cdk.h>

    int main() {

    CDKSCREEN *cdkscreen;

    WINDOW *cursesWin;

    CDKTEMPLATE *naissance;

    char *titre = "<C></32>Entrez votre date de naissance";

    char *label = "</24/B>Date :";

    char *overlay = "JJ/MM/AAAA";

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

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

    /* Initialisation */

    cursesWin = initscr();

    cdkscreen = initCDKScreen (cursesWin);

    /* Initialisation des couleurs CDK */

    initCDKColor();

    naissance = newCDKTemplate(cdkscreen,

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

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

    titre, /* Le titre du template */

    label, /* texte affiché devant le champ de saisie */

    masque, /* Masque de saisie */

    overlay, /* Overlay à afficher */

    TRUE, /* Dessiner une boite? */

    FALSE); /* Dessiner une ombre? */

    /* On affiche */

    refreshCDKScreen (cdkscreen);

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

    {

    info = activateCDKTemplate (naissance, 0);

    }

    mixed = mixCDKTemplate (naissance);

    mesg[0] = "<C>Vous avez saisi sans masque :";

    /*sprintf (temp, "<C>(%.*s)", (int)(sizeof(temp) - 10), info);*/

    sprintf (temp,"<C>(%s)",info);

    mesg[1] = copyChar (temp);

    mesg[2] = "<C>Et avec masque :";

    sprintf (temp,"<C>(%s)",mixed);

    mesg[3] = copyChar(temp);

    mesg[4] = "";

    mesg[5] = "<C>Appuyez sur une touche";

    popupLabel (cdkscreen, mesg, 6);

    destroyCDKTemplate (naissance);

    /* on nettoie avant de quitter */

    destroyCDKScreen (cdkscreen);

    endCDK();

    }

    Ce widget ressemble beaucoup au widget CDKEntry. La différence notable se trouve dans les chaînes overlay et masque. La chaîne overlay contient une chaîne de caractères correspondant à l’affichage avant toute entrée de l’utilisateur. Elle joue le rôle du caractère de remplissage dans le CDKEntry ; la chaîne masque, quant à elle, détermine quels sont les caractères modifiables par l’utilisateur et de quelle façon, en suivant le tableau 5.

    #

    Entier

    A

    Alphabétique

    C

    Alphabétique, caractères convertis en majuscules

    c

    Alphabétique, caractères convertis en minuscules

    M

    Alphanumérique

    X

    Alphanumérique, caractères convertis en majuscules

    x

    Alphanumérique, caractères convertis en minuscules

    Autres caractères

    considéré comme non éditable

    Tableau 5 : Caractères du masque

    L’entrée saisie par l’utilisateur ne comprend que les champs éditables, la fonction associée mixCDKTemplate permet de récupérer une chaîne de caractères comprenant les champs saisis par l’utilisateur et les caractères non éditables du masque. Dans notre exemple, si l’utilisateur entre le 25 juillet 1940, soit un affichage à l’écran : 25/07/1940, la chaîne renvoyée par la fonction activateCDKTemplate contiendra 25071940 et la chaîne renvoyée par mixCDKTemplate contiendra 25/07/1940.

    6

    Conclusion de cette première partie

    Au terme de cette première partie, nous avons donc vu comment on peut simplement poser des questions à l’utilisateur de notre programme en choix fermé (les widgets de type dialog), en choix ouvert (les widgets de type entry). Nous avons également vu comment CDK permet très simplement de gérer les couleurs et les caractéristiques des caractères à l’aide de balises. Enfin, nous avons vu que CDK ne se limite pas à un simple affichage, mais permet de dynamiser l’interface grâce au mécanisme des fonctions de callback.

    Je vous donne donc rendez-vous pour la seconde partie de ce tutoriel, où après avoir examiné une autre famille très importante de widgets (les listes), nous verrons les outils que nous fournit CDK pour gérer des formulaires complets. Nous terminerons enfin ce tutoriel par la réalisation de menus déroulant [2].

    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 107

    Posté par (La rédaction) | Signature : William Daniau | Article paru dans Creative Commons License

    Laissez une réponse

    Vous devez avoir ouvert une session pour écrire un commentaire.