Partage
  • Partager sur Facebook
  • Partager sur Twitter

Une fonction de menus pour vous.

    13 octobre 2006 à 7:11:09

    Salut les gens! J'ai une fonction pour console à vous proposer:
    Simple, elle génère un menu quand on l'appelle.

    Exemple:
    On a un choix à faire, par exemple le choix principal (choix_p), voilà comment vous devez prosséder avec cette fonction:

    long choix_p;

    //On fait décider au joueur quel sera le choix_p :
     choix_p = menu('p', 4, "Menu du jeu", "1.Nouveau jeu.|2.Continuer la partie en  cours.|3.Informations sur le jeu.|4.Fermer le programme.|");

     printf(" Votre choix est : %ld\n\n", choixPrincipal);

    Voilà le résultat: (Sans les espaces.)

    [ Menu du jeu ]


    -> 1.Nouveau jeu. <-

    2.Continuer la partie en cours.

    3.Inforlations sur la partie.

    4.Fermer le programme.



    Le prototype:
    long menu(char type, const long nombreDeChoix, const char* titre, const char* menu);

    Les paramètres:
    • le Type, c'est le chois du type de menu, rendu etc... (pour l'instant je n'en ai qu'un: 'p' pour principal, si vous en trouvez d'autres sans failles faites passer !
    • le nombres de choix, constitue le nombre de choix possibles dans le menu.
    • Le titre, c'est ce qu'il y aura en haut entre crochets.
    • Le contenu du menu, qui doit contenir les phrases à afficher en liste comme des choix. Il faut séparer les phrases choix par des '|' et finir par ce symbole aussi (voir exemple) sinon le programme plante...

    Comment l'opérateur doit -il l'utiliser?

    Simple: Les touches 8 et 2 du pav.num. permettent de naviguer dans le menu. Une fois placé, la touche 5 permet d'activer cette commande.


    Et voici la fonction elle même:

    long menu(char type, const long nombreDeChoix, const char* titre, const char* menu)
    {
            long curseurMenu = 0, curseurLigne = 0, commande = 1, numeroLigne = 0, i = 0;
            char toucheAppuyee = 0;
            char lettre = 0;

            do
            {
                    system("CLS");
                    printf("\n\t\t[ %s ]\n\n", titre);
                    do
                    {
                            char ligne[60] = "";

                            //On indentifie la ligne.
                            while(lettre != '|')
                            {
                                    lettre = menu[curseurMenu];
                                    if(lettre != '|')
                                    ligne[curseurLigne] = menu[curseurMenu];
                                    curseurMenu++, curseurLigne++;
                            };
                            lettre = 0;
                            curseurLigne = 0;

                            //On affiche la ligne.
                            if(type=='p')
                            {
                                    numeroLigne++;
                                    printf("\n ");
                                    for( i = 0 ; i < numeroLigne ; i++)
                                            printf(" ");
                                    if (commande == numeroLigne)
                                            printf("-> %s <-\n", ligne);
                                    else
                                            printf("   %s\n", ligne);
                            }

                    }while(nombreDeChoix != numeroLigne);
                    printf("\n\n");

                    //On remet à zero les variables conditionnelles
                    curseurMenu = 0;
                    numeroLigne = 0;
                    curseurLigne = 0;

                    //On attend la saisie de l'opérateur.
                    toucheAppuyee = getch();

                    //On gère la commande.
                    if(toucheAppuyee == '8') commande--;
                    if(toucheAppuyee == '2') commande++;
                    if(commande > nombreDeChoix) commande = 1;
                    if(commande < 1) commande = nombreDeChoix;

            }while (toucheAppuyee != '5');
            return commande;
    }


    Qu'en pensez vous? pratique? inutile? Code source complètement nul?
    En tous cas elle est à vous !
    • Partager sur Facebook
    • Partager sur Twitter
      13 octobre 2006 à 13:06:35

      Citation : wi4

      Salut les gens! J'ai une fonction pour console à vous proposer:
      Simple, elle génère un menu quand on l'appelle.


      Ah, enfin ! Ca fait longtemps que j'attend une initiative dans ce sens, car ma spécialité, c'est le 'composant logiciel'.

      Déjà, il y a quelques problèmes de réalisation dans ton code :

      • system() est appelée sans prototype
      • printf() est appelée sans prototype
      • getch() est appelée sans prototype. Attention, non portable.
      • Il n'y a pas de main(), j'en conclue que c'est un module séparé. Il manque donc le header et son inclusion.

      Ceci reglé, j'ai testé avec l'exemple donné et après correction d'une erreur d'identificateur, le fonctionnement est conforme à ce qui est annoncé.

      Néanmoins, j'émettrais quelques réserves.

      • Coté utilisateur, l'usage des touches 8, 5 et 2 pose problème sur un portable.
      • De plus, ce n'est pas très intuitif, surtout que des numéros sont proposés à l'écran. Il faut donc faire le choix suivant. Soit on tape le numéro, soit on sélectionne avec les flêches. C'est une question de portabilité.
      • Sur le plan de la réalisation, il faut déterminer le degré de portabilité. On sait faire des menus 100% standard en réduisant nos ambitions de présentation, en affichant les choix possibles (lettre, nombre, commentaires) sur stdout et faisant une lecture standard sur stdin. Evidement, il faut se passer aussi des commandes passées par system().
      • Si on choisi d'utiliser les fleches et une présentation plein écran, on s'y tient exclusivement. Pas de mélanges entre entrées/sorties standard et directes.
      • Enfin, coté utilisateur de la fonction, il faut simplifier l'interface. Le coup des chaines sépares par un |, ce n'est pas très opérationnel. Une solution à base de tableau de chaines est sans doutes préférable


      Pour la présentation plein ecran (MS-DOS/Windows avec CONIO), je verrais ça :

      /* menu.c */
      #include "menu.h"

      #define CONIO 1

      #if CONIO

      #include <conio2.h>
      #include <string.h>


      static void aff (char const **liste, int x, int y0, int max, size_t select,
                       int normal)
      {
         if (normal)
         {
            textbackground (BLACK);
            textcolor (WHITE);
         }
         else
         {
            textbackground (WHITE);
            textcolor (BLACK);
         }

         gotoxy (x, y0 + 2 + select);
         cprintf ("%-*s", max, liste[select]);
      }

      int menu (char const *titre, char const **liste, size_t nb_elem)
      {
         int commande = -1;
         struct text_info ti;

         /* afficher le titre et les menus auto-centres et la selection par defaut. */
         clrscr ();

         gettextinfo (&ti);
         {
            int y0 = (ti.screenheight - (1 + 1 + nb_elem)) / 2;
            {
               int x = (ti.screenwidth - (strlen (titre) + strlen ("[  ]"))) / 2;
               gotoxy (x, y0);
            }
            cprintf ("[ %s ]", titre);

            {
               size_t i;
               size_t max = 0;

               for (i = 0; i < nb_elem; i++)
               {
                  size_t const n = strlen (liste[i]);
                  if (n > max)
                  {
                     max = n;
                  }
               }

               {
                  size_t select = 0;
                  int x = (ti.screenwidth - max) / 2;
                  for (i = 0; i < nb_elem; i++)
                  {
                     if (i == select)
                     {
                        aff (liste, x, y0, max, i, 0);
                     }
                     else
                     {
                        aff (liste, x, y0, max, i, 1);
                     }
                  }

                  /* saisir en affichant la selection */

                  {
                     enum
                     {
                        ESC = 27,
                        UP = 72,
                        DN = 80,
                        dummy
                     };
                     int fin = 0;


                     while (!fin)
                     {
                        int c = getch ();
                        fin = c == ESC;

                        switch (c)
                        {
                        case 0:
                        case 224:
                           if (kbhit ())
                           {
                              c = getch ();

                              switch (c)
                              {
                              case UP:
                                 aff (liste, x, y0, max, select, 1);
                                 if (select == 0)
                                 {
                                    select = nb_elem;
                                 }
                                 select--;
                                 aff (liste, x, y0, max, select, 0);
                                 break;

                              case DN:
                                 aff (liste, x, y0, max, select, 1);
                                 select++;
                                 if (select == nb_elem)
                                 {
                                    select = 0;
                                 }
                                 aff (liste, x, y0, max, select, 0);
                                 break;
                              }
                           }
                           break;
                        case '\r':
                           commande = select;
                           fin = 1;

                           textattr (ti.normattr);
                           break;
                        default:
                           ;
                        }
                     }
                  }
               }
            }
         }

         return commande;
      }
      #else
      #include <stdlib.h>
      #include <stdio.h>
      #endif

      avec

      /* menu.h */
      #ifndef H_ED_MENU_20061013125036
      #define H_ED_MENU_20061013125036

      #ifdef __cplusplus
      extern "C"
      {
      #endif
      #include <stddef.h>

         int menu (char const *titre, char const **liste, size_t nb_elem);

      #ifdef __cplusplus
      }
      #endif

      #endif /* guard */

      /* Guards added by GUARD (c) ED 2000-2005 Jan 17 2005 Ver. 1.7 */

      et le test :
      /* main.c */
      #include "menu.h"

      #include <stdio.h>

      int main (void)
      {
         /* liste des choix possibles */
         static char const *liste[] =
            {
               "Nouveau jeu.",
               "Continuer la partie en cours.",
               "Informations sur le jeu.",
               "Fermer le programme.",
            };

         int choix = menu ("Menu du jeu", liste, sizeof liste / sizeof * liste);

         printf (" Votre choix est : %d\n\n", choix);

         return 0;
      }

      • Partager sur Facebook
      • Partager sur Twitter
      Music only !
        13 octobre 2006 à 19:36:11

        Ouf, tant de problèmes posés, je ne suis pas un pro -ed-, loin de là, tu m'as l'air très renseigné et je posais cette idée en toute inadvertance d'amateur. Mais je suis heureux que cette initiative te plaise.

        Je n'arrive pas à comprendre ton code, je ne connais pas ces librairies.

        En fait j'ai choisi 8, 2 et 5 pour valider mais je n'ai pas été judicieux c'est vrai, j'aimreais bien savoir comment traiter les touches directionnelles du clavier.

        Ensuite je n'ai pas très bien compris de quelle notion tu parles avec "portabilité" par exemple pour getch().

        Aussi je ne comprend pas le problème que pose '|' pour séparer les différentes phrases. J'aimerais bien que tu m'explique comment fonctionne ta liste, enfait il faudrait créer une structure sous forme de liste de char avant de l'envoyer à la fonction?

        Enfin, j'utilise ce code dans un main j'ai oublié aussi les includes comme tu l'as noté.

        #include <stdio.h>
        #include <stdlib.h>


        Merci de ton intérêt -ed-!
        • Partager sur Facebook
        • Partager sur Twitter
          13 octobre 2006 à 20:19:43

          Citation : wi4

          Je n'arrive pas à comprendre ton code, je ne connais pas ces librairies.


          Je n'utilise qu'une bibliothèque non standard, c'est CONIO. Toi aussi, puisque tu utilisais getch(). Simplement, j'utilise d'autres fonctions de celle-ci.

          Citation : Pas de titre


          En fait j'ai choisi 8, 2 et 5 pour valider mais je n'ai pas été judicieux c'est vrai, j'aimreais bien savoir comment traiter les touches directionnelles du clavier.


          C'est indiqué dans mon code. C'est le mécanisme qui utilise getch(), kbhit(), et les valeurs DN eu UP définies un peu avant. Les touches étendues émettent 2 caractères. 0 xxx ou 224 xxx, xxx étant le code de la touche étendue.

          Citation : Pas de titre


          Ensuite je n'ai pas très bien compris de quelle notion tu parles avec "portabilité" par exemple pour getch().


          getch() appartient à une bibliothèque non standard (CONIO). Celle-ci est disponible pour la plupart des implémentation du C sur PC avec MS-DOS ou Windows, mais pas (ou plus difficilement) sous Linux. C'est pour ça qu'elle n'est pas portable, c'est à dire disponible sur toutes les (ou la plupart des ) plateformes.

          Citation : Pas de titre


          Aussi je ne comprend pas le problème que pose '|' pour séparer les différentes phrases. J'aimerais bien que tu m'explique comment fonctionne ta liste, enfait il faudrait créer une structure sous forme de liste de char avant de l'envoyer à la fonction?


          Ta liste avec séparateurs n'est pas très pratique à écrire ni à faire évoluer. De plus, elle nécessite une interprétation à l'exécution, un découpage, bref, c'est compliqué et lent à gérer. J'ai proposé une solution alternative qui fonctionne avec un tableau de chaine (dans le main()). On passe l'adresse du premier élément du tableau et le nombre d'éléments.

          Tu as lu mon code ? En principe, il est 'auto documenté'. Mais si ce n'est pas clair essaye de poser des questions plus précices.
          • Partager sur Facebook
          • Partager sur Twitter
          Music only !

          Une fonction de menus pour vous.

          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
          • Editeur
          • Markdown