Débuter avec les Enlightenment Foundation Libraries (EFL)


précédentsommairesuivant

VII. Introduction

Comme dit dans la première partie de l'article, Elementary est une bibliothèque permettant l'exploitation d'une gamme de widgets hautement personnalisables. À l'heure actuelle, Elementary n'est toujours pas sortie en version stable du fait de ses quelques bogues et manques de widgets. Malgré cela, cette bibliothèque reste tout à fait appropriée pour la réalisation d'interfaces graphiques ordinaires.

VII-A. Objectifs

Cette partie traitera au mieux l'aspect « C » du développement d'une application avec les EFL. Bien entendu, du code Edje sera introduit afin de montrer comment lier un fichier de description Edje avec du code C, par exemple, ainsi que pour ne pas ignorer la particularité des EFL de séparer la partie graphique de la partie logique d'une application.

Dans le cadre du développement en C, Elementary aura une place centrale mais ne sera logiquement pas la seule bibliothèque utilisée. En effet, Elementary utilisée seule n'est pas suffisante pour écarter les possibilités offertes par d'autres bibliothèques telles qu'Evas, indispensable à la réalisation d'une application, ou Ecore.

VII-B. Compilation

La compilation d'un fichier source utilisant Elementary nommé source.c se fait généralement avec la commande suivante :

 
Sélectionnez
gcc -o source source.c `pkg-config elementary --cflags --libs`

Si vous obtenez une erreur comme quoi elementary.pc serait introuvable (« Package elementary was not found in the pkg-config search path ») malgré le fait que vous ayez déjà installé correctement Elementary, ajoutez le chemin /.../e17/lib/pkgconfig dans la variable d'environnement PKG_CONFIG_PATH :

 
Sélectionnez
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/.../e17/lib/pkgconfig

Tout en remplaçant /.../ par le chemin correct. Cette variable d'environnement a déjà été introduite plus tôt dans l'article, précisée nécessaire dans la partie traitant l'installation des EFL.

Une fois la compilation terminée, on peut trouver l'exécutable à l'emplacement spécifié lors de la compilation.

VIII. Premiers pas avec Elementary

VIII-A. Aperçu des widgets d'Elementary

Dans le cas où l'on rechercherait un widget ou une personnalisation, Elementary vient avec une application, elementary_test, qui recense un grand nombre de widgets afin de donner un aperçu des différents widgets mis à disposition par la bibliothèque.

Image non disponible
L'application elementary_test et l'exemple « Laucher »


L'application est intéressante quand il s'agit de rechercher un widget, mais le code qu'elle met à disposition n'est pas un bon exemple d'écriture de GUI avec les EFL.

VIII-B. Code minimal

Quoi de mieux pour commencer l'étude d'une bibliothèque étroitement liée au GUI que de présenter le code minimal d'ouverture d'une fenêtre afin de pouvoir le détailler progressivement par la suite ?

 
Sélectionnez
#include <Elementary.h>

static void
win_del(void *data, Evas_Object *obj, void *event_info)
{
    elm_exit();
}

EAPI int
elm_main(int argc, char **argv)
{
    Evas_Object *win;

    win = elm_win_add(NULL, "main_window", ELM_WIN_BASIC);
    evas_object_smart_callback_add(win, "delete,request", win_del, NULL);
    evas_object_show(win);

    elm_run();
    elm_shutdown();

    return EXIT_SUCCESS;
}
ELM_MAIN()

Par le biais de l'inclusion du fichier Elementary.h, nous obtenons la possibilité d'utiliser toutes les fonctions que la bibliothèque met à disposition. Elementary inclut par défaut Eina, Eet, Evas, Ecore et Edje (et d'autres, selon la configuration), ce qui signifie qu'inclure Elementary.h permet d'utiliser toutes ces bibliothèques sans avoir besoin d'inclure des fichiers d'en-tête supplémentaires.

 
Sélectionnez
EAPI int
elm_main(int argc, char **argv)
{
    ...
}
ELM_MAIN()

La macro ELM_MAIN() définissant la fonction main() et appelant la fonction elm_main(), cette dernière est considérée comme la fonction principale du programme.

 
Sélectionnez
Evas_Object *win; 

Cela définit un pointeur win de type Evas_Object, structure qui correspond à la base de tous les éléments graphiques.

 
Sélectionnez
win = elm_win_add(NULL, "main_window", ELM_WIN_BASIC); 
evas_object_smart_callback_add(win, "delete,request", win_del, NULL); 
evas_object_show(win); 

L'utilisation de la fonction elm_win_add mène à la création d'une fenêtre de nom unique main_window et de type ELM_WIN_BASIC (une fenêtre classique). L'utilisation - qui sera bien plus amplement détaillée par la suite - de la fonction evas_object_smart_callback_add() fait en sorte que la fonction win_del() soit appelée lorsque l'utilisateur demande à fermer la fenêtre avec le bouton associé. Cette fonction appelle elm_exit() qui permet de quitter la boucle principale, lancée par elm_run(). Enfin, evas_object_show() affiche la fenêtre.

Malgré tout, cette fenêtre n'a pas de titre, contient uniquement un fond noir, et n'est donc au final pas tellement attirante. Remédions-y en changeant le contenu de elm_main() :

 
Sélectionnez
EAPI int 
elm_main(int argc, char **argv) 
{ 
    Evas_Object *win, *background; 

    win = elm_win_add(NULL, "main_window", ELM_WIN_BASIC); 
    elm_win_title_set(win, "Elementary"); 
    evas_object_smart_callback_add(win, "delete,request", win_del, NULL); 

    background = elm_bg_add(win); 
    evas_object_size_hint_min_set(background, 200, 100); 
    evas_object_size_hint_weight_set(background, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); 
    elm_win_resize_object_add(win, background); 
    evas_object_show(background); 

    evas_object_show(win); 

    elm_run(); 
    elm_shutdown(); 

    return EXIT_SUCCESS; 
} 
ELM_MAIN()

Par le biais de la fonction elm_win_title_set(), on peut définir le titre d'une fenêtre :

 
Sélectionnez
elm_win_title_set(win, "Elementary"); 

De même, la bibliothèque permet de créer un arrière-plan à un objet Elementary par le biais de la fonction elm_bg_add() :

 
Sélectionnez
// Crée un arrière-plan pour win :
background = elm_bg_add(win); 
// Définit des dimensions minimales à background :
evas_object_size_hint_min_set(background, 200, 100);
// Permet un redimensionnement horizontal et vertical :
evas_object_size_hint_weight_set(background, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
// Ajoute l'objet dans win et fait en sorte qu'il s'adapte à sa taille :
elm_win_resize_object_add(win, background); 
evas_object_show(background); 

La création d'un objet Elementary retourne toujours un Evas_Object*. Il est donc possible de manipuler un tel objet par le biais des méthodes fournies à la fois par la bibliothèque Evas et par la bibliothèque Elementary. Les deux bibliothèques peuvent parfois fournir les mêmes fonctionnalités. Dans ce cas, par convention, il est recommandé d'utiliser les méthodes d'Elementary.

VIII-C. Edje et le code C

VIII-C-1. Utiliser un fichier EDJ dans du code C

Il est extrêmement rare que des applications complètes soient exclusivement développées en Edje. Comme dit dans la partie précédente, l'intérêt d'Edje est surtout de fournir l'aspect graphique de l'application afin de laisser le C gérer la partie logique. C'est pour cette raison que la méthode de lien d'un fichier Edje avec le code C est abordée ci-dessous, venant avec le concept de layouts :

 
Sélectionnez
Evas_Object *win, *layout;
...
layout = elm_layout_add(win); 
elm_layout_file_set(layout, "interface.edj", "background_group"); 
elm_win_resize_object_add(win, layout); 
evas_object_show(layout);

La fonction d'Elementary elm_layout_add() permet de créer un layout à un objet Elementary. Sa syntaxe est identique à celle de elm_bg_add(), vue précédemment. Le reste du code a déjà été vu, à l'exception d'une ligne :

 
Sélectionnez
elm_layout_file_set(layout, "interface.edj", "background_group"); 

La fonction elm_layout_file_set() permet de définir le fichier EDJ qui sera utilisé en tant que layout. Ici, « background_group » correspond au groupe à charger.

On peut alors manipuler le layout ainsi créé par le biais des fonctions dédiées d'Elementary ainsi qu'avec les fonctions d'Evas.

VIII-C-2. Un exemple

Afin d'illustrer l'utilisation d'un fichier EDJ dans du C, prenons un exemple de fichier Edje qui pourra éventuellement servir de base par la suite. C'est d'ailleurs un bel exemple de l'utilisation des macros avec Edje et des éléments de type TABLE. Voici le code complet de chargement avec Elementary :

 
Sélectionnez
#include <Elementary.h> 

static void 
win_del(void *data, Evas_Object *obj, void *event_info) 
{ 
    elm_exit(); 
} 

EAPI int 
elm_main(int argc, char **argv) 
{ 
    Evas_Object *win, *layout; 

    win = elm_win_add(NULL, "main_window", ELM_WIN_BASIC); 
    elm_win_title_set(win, "Elementary"); 
    evas_object_smart_callback_add(win, "delete,request", win_del, NULL); 

    layout = elm_layout_add(win); 
    elm_layout_file_set(layout, "interface.edj", "background_group"); 
    elm_win_resize_object_add(win, layout); 
    evas_object_show(layout); 

    evas_object_resize(win, 500, 300); 
    evas_object_show(win); 

    elm_run(); 
    elm_shutdown(); 

    return EXIT_SUCCESS; 
} 
ELM_MAIN()

Selon les images utilisées, cela ressemblera plus ou moins à ceci :

Image non disponible
Icônes de l'application en provenance du site everaldo.com

VIII-C-3. Interactions entre C et EDC

L'intérêt premier des fichiers de description Edje est de pouvoir séparer la partie graphique de la partie logique d'une application. Il est ainsi nécessaire de pouvoir gérer les signaux envoyés par Edje avec la partie logique de l'application.

Un programme Edje peut, comme dit dans la partie introduisant Edje, envoyer un signal par le biais de SIGNAL_EMIT :

 
Sélectionnez
program { 
    name: "mouse_click"; 
    signal: "mouse,clicked,1"; 
    source: "element"; 
    action: SIGNAL_EMIT "element,clicked" ""; 
}

Le signal pourra alors être récupéré par un callback dans le C. Cela sera traité plus en détail dans la partie suivante, concernant les évènements.

Note : comme montré dans la partie précédente de l'article, les fichiers de description Edje peuvent comprendre des widgets d'Elementary avec le type EXTERNAL. C'est pour cette raison qu'il est hautement préférable de définir les widgets Elementary par le biais d'Edje, puis de les gérer dans le code C en récupérant un Evas_Object de l'élément Edje (méthode utilisée dans la partie suivante) puis en l'exploitant afin d'insérer des lignes, du texte ou autre, selon le widget.

VIII-D. La gestion des évènements

Un framework ne permettant pas une gestion des évènements est statique et donc peu intéressant. Ainsi, les EFL permettent une gestion des évènements par le biais des callbacks, c'est-à-dire des fonctions qui sont appelées lorsqu'un événement particulier s'est produit. De multiples fonctions sont utilisables selon le contexte pour créer un callback. Parmi elles :

  • evas_object_smart_callback_add, utilisée avec des smart objets (ou objets intelligents) ;
  • evas_object_event_callback_add, utilisée avec des objets Evas ;
  • edje_object_signal_callback_add, quant à elle utilisée pour gérer les signaux en provenance d'une interface Edje.

Le premier moyen a déjà brièvement été présenté dans les exemples. Son prototype est le suivant :

 
Sélectionnez
EAPI void evas_object_smart_callback_add(Evas_Object * obj, 
    const char *    event, 
    Evas_Smart_Cb   func, 
    const void *    data 
)

Avec obj, le smart objet sur lequel le callback va s'appliquer, event, l'évènement sur lequel réagir, func, la fonction callback et data, les paramètres à passer à la fonction callback. Cette dernière sera forcément de cette forme :

 
Sélectionnez
void callback(void *data, Evas_Object *obj, void *event_info) ;

Avec data, la valeur de l'argument data passée lors de l'ajout du callback, obj, l'objet sur lequel l'évènement s'est produit et event_info, le pointeur vers une structure de données pouvant ou non être passé.

Par exemple, pour un bouton Elementary nommé button, on pourrait avoir ceci :

 
Sélectionnez
void button_clicked(void *data, Evas_Object *obj, void *event_info) 
{ 
    printf("Click event.\n");
}
...
evas_object_smart_callback_add(button, "clicked", button_clicked, NULL);

La deuxième méthode est généralement utilisée sur les objets Evas simples :

 
Sélectionnez
EAPI void evas_object_event_callback_add(Evas_Object * obj, 
    Evas_Callback_Type      type, 
    Evas_Object_Event_Cb    func, 
    const void *            data 
)

Avec obj, l'objet sur lequel le callback va s'appliquer, type, le type d'évènement appelant le callback (par exemple EVAS_CALLBACK_KEY_DOWN et EVAS_CALLBACK_MOUSE_UP), func, la fonction callback et data, les paramètres à passer à la fonction callback. Cette dernière sera de la forme suivante :

 
Sélectionnez
void callback(void *data, Evas *e, Evas_Object *obj, void *event_info);

Avec e, le canvas Evas qui a appelé l'évènement. Les autres arguments sont les mêmes que ceux de la première méthode détaillée. Toutefois, la partie traite d'Elementary et non d'Evas, donc aucune information supplémentaire ne sera donnée concernant cette méthode.

La troisième méthode permet de créer une interaction entre le code C et Edje. Son prototype est le suivant :

 
Sélectionnez
EAPI void edje_object_signal_callback_add(Evas_Object * obj, 
    const char * emission, 
    const char * source, 
    void(*)(void*,Evas_Object*,const char*,const char*) func, 
    void *       data 
)

Avec obj, l'objet qui va émettre le signal, emission, le nom du signal, source, le nom de la part Edje source, func, la fonction callback et data, les paramètres à passer à la fonction callback, de la forme donnée dans le prototype :

 
Sélectionnez
void callback(void *data, Evas_Object *obj, const char *emission, const char *source)

Par exemple, pour récupérer le signal émis dans le programme présenté plus tôt :

 
Sélectionnez
void 
edje_event(void *data, Evas_Object *obj, const char *emission, const char *source) 
{ 
    printf("Click event.\n"); 
}

layout = elm_layout_add(win); 
elm_layout_file_set(layout, "interface.edj", "group_name"); 
elm_win_resize_object_add(win, layout); 
evas_object_show(layout); 

edje = elm_layout_edje_get(layout); 
edje_object_signal_callback_add(edje, "element,clicked", "*", edje_event, NULL);

Il est nécessaire de passer par elm_layout_edje_get() pour récupérer l'objet Edje depuis l'objet Elementary afin d'ajouter par la suite un callback.

Note : on peut également écrire une fonction permettant de récupérer la totalité des évènements se produisant dans l'Edje afin de déboguer :

 
Sélectionnez
void 
edje_event(void *data, Evas_Object *obj, const char *emission, const char *source) 
{ 
    printf("Signal %s from %s\n", emission, source); 
}
...
edje_object_signal_callback_add(edje, "*", "*", edje_event, NULL);

Utilisé avec le code d'exemple donné plus tôt dans la partie II.3.2, voici les logs d'un simple clic sur une icône :

 
Sélectionnez
Signal mouse,down,1 from table 
Signal mouse,down,1 from table[3]:event_handler 
Signal mouse,up,1 from table 
Signal mouse,clicked,1 from table 
Signal mouse,up,1 from table[3]:event_handler 
Signal mouse,clicked,1 from table[3]:event_handler 

Et dans le cas où l'on aurait ajouté ce programme dans la macro TABLE_IMAGE :

 
Sélectionnez
program {                                       \ 
    name: "mouse_click";                        \ 
    signal: "mouse,clicked,1";                  \ 
    source: "event_handler";                    \ 
    action: SIGNAL_EMIT _name",clicked" "";     \ 
}                                               \

Une ligne supplémentaire s'ajouterait aux logs :

 
Sélectionnez
Signal graphics,clicked from table[3]:

L'avantage d'un tel système de logs et que l'on voit l'intégralité de ce qu'il se passe sur l'interface utilisateur, ce qui simplifie grandement le débogage.

IX. Quelques widgets

Maintenant que l'on sait comment créer une interface avec Elementary combinée avec Edje ainsi qu'agir en réaction à un événement, il est temps de partir plus en profondeur dans Elementary, et ainsi aller à la rencontre de quelques widgets intéressants.

IX-A. Les listes

Les listes sont des éléments extrêmement utilisés dans les diverses applications que l'on utilise quotidiennement, que ce soit pour afficher une liste de fichiers, une playlist ou bien d'autres choses encore. Elementary fournit le widget List pour créer de tels objets dont voici un exemple basique d'utilisation :

 
Sélectionnez
Evas_Object *win, *list; 
char buf[32]; 
int i; 

... 

list = elm_list_add(win); 
elm_win_resize_object_add(win, list); 
elm_list_mode_set(list, ELM_LIST_LIMIT); 
evas_object_size_hint_weight_set(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); 

for (i = 0; i < 10; ++i) 
{ 
    snprintf(buf, sizeof(buf), "Élément n°%d", i); 
    elm_list_item_append(list, buf, NULL, NULL, NULL, NULL); 
} 

elm_list_go(list); 
evas_object_show(list);

À ce stade de l'article, seules trois fonctions sont à détailler :

  • elm_list_mode_set() : permet de changer le mode de la liste ;
  • elm_list_item_append() : permet d'ajouter un élément dans la liste ;
  • elm_list_go() : à appeler avant d'afficher la liste.

Toutes étant quoi qu'il en soit détaillées dans la documentation.

Image non disponible

Cette liste est aussi triste qu'inutile. Il serait intéressant de lui ajouter des icônes sur le côté et de lui assigner une fonction callback afin de gérer les sélections d'éléments.

Le plus simple, les callbacks :

 
Sélectionnez
void 
list_event(void *data, Evas_Object *obj, void *event_info) 
{ 
    Elm_List_Item *item; 
    // On récupère l'item sélectionné de la liste :
    item = elm_list_selected_item_get(obj); 
    // On affiche le message ainsi que le texte de son label :
    printf("Double click happened. %s.\n", elm_list_item_label_get(item)); 
}

...

evas_object_smart_callback_add(list, "clicked,double", list_event, NULL);

Lors d'un double-clic sur l'élément n° 5 par exemple, cela affichera ceci dans la console :

 
Sélectionnez
Double click happened. Élément n° 5.

La liste exhaustive des signaux utilisables est disponible dans le fichier elm_list.c.

Ajouter des icônes à une liste est une tâche légèrement plus longue dans le sens où il est nécessaire de créer une boîte pour les afficher.

 
Sélectionnez
Evas_Object *win, *list, *box, *icon; 

... 

    for (i = 0; i < 10; ++i) 
    { 
        // On crée une boîte : 
        box = elm_box_add(win); 
        // On crée une icône : 
        icon = elm_icon_add(win); 
        // On définit le fichier image de l'icône : 
        elm_icon_file_set(icon, "images/icon.png", NULL); 
        // On retire la mise à l'échelle : 
        elm_icon_scale_set(icon, 0, 0); 
        // On ajoute l'icône dans la boîte : 
        elm_box_pack_end(box, icon); 
        // On affiche l'image : 
        evas_object_show(icon); 
        // Le texte de l'item :
        snprintf(buf, sizeof(buf), "Élément n°%d", i); 
        // On utilise la boîte pour afficher l'icône à gauche : 
        elm_list_item_append(list, buf, box, NULL, NULL, NULL); 
    }

Avec les commentaires, aucune explication additionnelle n'est requise.

IX-B. Les genlist

Dans la première partie de l'article, lors de la présentation d'Elementary, le concept des genlists était abordé. Pour résumer l'intérêt, si l'on remplace dans le code précédent la ligne :

 
Sélectionnez
for (i = 0; i < 10; ++i) 

Par la ligne :

 
Sélectionnez
for (i = 0; i < 1000; ++i) 

Que va-t-il se passer ? Pour donner des chiffres, l'application va « juste » passer de 2 Mo à 17 Mo, en termes de consommation de mémoire. Si on rajoute un zéro, faisant passer le nombre d'éléments à 10 000, sous une machine des plus classiques, l'application va se mettre à laguer et va démarrer en plus de vingt secondes. Ainsi, on peut en déduire que le choix d'une liste classique est furieusement inapproprié à une utilisation à grande échelle. C'est là qu'interviennent les genlists, bien plus appropriées à ce type d'usage.

 
Sélectionnez
char * 
gl_label_get(void *data, Evas_Object *obj, const char *part) 
{ 
   char buf[256]; 
   snprintf(buf, sizeof(buf), "Élément n°%d", (int)data); 
   return strdup(buf); 
} 

Evas_Object * 
gl_icon_get(void *data, Evas_Object *obj, const char *part) 
{ 
   return NULL; 
} 

Eina_Bool 
gl_state_get(void *data, Evas_Object *obj, const char *part) 
{ 
   return EINA_FALSE; 
} 

void 
gl_del(void *data, Evas_Object *obj) 
{ 
} 

... 

    Evas_Object *win, *background, *genlist; 
    Elm_Genlist_Item_Class item; 
    int i; 

    genlist = elm_genlist_add(win); 
    elm_win_resize_object_add(win, genlist); 
    evas_object_size_hint_weight_set(genlist, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); 
    evas_object_show(genlist); 

    item.item_style = "default"; 
    item.func.label_get = gl_label_get; 
    item.func.icon_get = gl_icon_get; 
    item.func.state_get = gl_state_get; 
    item.func.del = gl_del; 

    for (i = 0; i < 10000; ++i) 
    { 
        elm_genlist_item_append(genlist, &item, (void *)i, 
            NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); 
    } 

    evas_object_show(genlist);

Le rendu est identique à la capture d'écran présentée plus haut, au détail près qu'il y a bien plus d'éléments.

De manière à avoir un sujet de comparaison avec l'utilisation d'une liste normale, pour dix éléments, l'application va prendre 2.4 Mo et 2.7 Mo pour mille. Avec dix mille éléments, l'application prendra à peine 4 Mo en mémoire (contre environ 150 pour l'utilisation des listes classiques) et ne souffrira d'aucun problème de ralentissement. On peut donc conclure que les genlists sont parfaitement adaptées aux utilisations à grande échelle. Toutefois, comme vous pouvez le voir, le codage d'une genlist est plus complexe que celui d'une simple liste. C'est pour cela qu'il est préférable d'utiliser les listes classiques dans le cas où les éléments à y stocker sont peu nombreux et peu complexes.

Par la notion de complexité, il est entendu que les genlists ne présentent pas uniquement des avantages en matière de consommation en mémoire. Elles sont également pratiques pour réaliser des listes sous forme d'arbre, par exemple. À noter qu'un élément d'une genlist peut être sous plusieurs styles, posséder plusieurs labels, plusieurs états, etc. d'où une réelle divergence des genlists par rapport à leurs cousines.

À première vue, le code donné peut assez logiquement sembler suspect. Pour le comprendre, il est nécessaire d'assimiler précisément la manière dont une genlist fonctionne.

Une genlist crée et détruit les objets des éléments la composant au fur et à mesure que l'utilisateur va la faire défiler, les groupe dans des blocs afin de déterminer aisément lesquels allouer et détruire. Combinée avec un concept de files, une genlist arrive à afficher un nombre incroyable d'éléments avec une consommation ridicule de mémoire. Une question se pose alors : comment fait-elle pour créer et détruire les objets au vol sans stocker les données en mémoire ? C'est là que la structure Elm_Genlist_Item_Class entre en jeu. Son rôle : permettre à une genlist de faire son travail de création/suppression par le biais des différentes fonctions qu'elle fournit.

 
Sélectionnez
item.item_style = "default"; 
item.func.label_get = gl_label_get; 
item.func.icon_get = gl_icon_get; 
item.func.state_get = gl_state_get; 
item.func.del = gl_del;

Il est bien entendu obligatoire de fournir les fonctions, dans le sens où une genlist ne peut pas inventer ce qu'elle doit afficher.

Le concept est assez intéressant. Si vous souhaitez avoir un aperçu de ce qui se fait dans la pratique, soit parce que vous avez du mal à assimiler le concept ou tout simplement par curiosité, créez un int (nommé num, par exemple) et incrémentez-le à chaque fois que la méthode gl_label_get() est appelée. Utilisez alors cet entier pour spécifier le texte de l'élément :

 
Sélectionnez
snprintf(buf, sizeof(buf), "Élément n°%d", num);
num++;
return strdup(buf);

Compilez, lancez le programme. Vous pouvez constater que le numéro évolue en permanence, à chaque fois que vous faites défiler la liste.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2011 Louis du Verdier. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.