Para que dejeis de preguntar de una vez por los menus

(1/3) > >>

do-while:
MODIFICADO

Añadido:
----------
- portabilidad
- texto centrado


Ya se que todo el codigo que viene a continuacion es una morcilla de las de Burgos, pero si mirais el ejemplo que hay al final, vereis como se simplifica todo a la hora de utilizar los menus.

Menu.h
Código
 
/*
 
IMPORTANTE: Cuando el menu ya no sea util, ultilizar siempre la funcion finalizarMenu
 
*/
 
#ifndef MENU_H
#define MENU_H
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
/*
* Para compilar en UNIX desactivar la definicion de WINDOWS y activar la de UNIX
* Para otros SO desactivar ambas.
*/
 
#ifndef WINDOWS
   #define WINDOWS
#endif
/*
#ifndef UNIX
    #define UNIX
#endif
*/
 
#define MENU_OK                   0L
#define MENU_ERROR                1L
#define MENU_MEMORIA_INSUFICIENTE 2L
 
#define MENU_MODO_NORMAL      0L
#define MENU_MODO_ULTIMA_CERO 1L
 
struct Menu
{
   char*         titulo;
   char*         texto;
   char**        opciones;
   int           numOpciones; /* numero de opciones */
   int           maxlen;
   unsigned long lFlags;
};
typedef struct Menu Menu;
 
void inicializarMenu(Menu* menu,char* titulo, char* texto, char* opciones[]);
int mostrarMenu(Menu* menu,int modo);
void finalizarMenu(Menu* menu);
 
#endif /* MENU_H */
 

menu.c
Código
#include "menu.h"
 
void inicializarMenu(Menu* menu, char* titulo, char* texto, char* opciones[])
{
  menu->lFlags = MENU_OK;
 
  if(titulo == NULL)
     menu->titulo = NULL;
  else
  {
      if((menu->titulo = (char*) malloc(strlen(titulo) * sizeof(char) + 1)))
          strcpy(menu->titulo,titulo);
     else
     {
        menu->lFlags |= MENU_ERROR | MENU_MEMORIA_INSUFICIENTE;
        menu->texto = NULL;
     }
  }
 
  if(texto == NULL)
     menu->texto = NULL;
  else
  {
     if((menu->texto = (char*) malloc(strlen(texto) * sizeof(char) + 1)))
        strcpy(menu->texto,texto);
     else
     {
        menu->lFlags |= MENU_ERROR | MENU_MEMORIA_INSUFICIENTE;
        menu->texto = NULL;
 
        if(menu->titulo)
        {
           free(menu->titulo);
           menu->titulo = NULL;
        }
     }
  }
 
  if(opciones == NULL)
     menu->opciones = NULL;
  else
  {
     menu->numOpciones = -1;
 
     while(opciones[ ++(menu->numOpciones) ][0]);
 
     if((menu->opciones = (char**) malloc(menu->numOpciones * sizeof(char*))))
     {
        int i=0;
 
        menu->maxlen = 0;
 
        for(i=0 ; i < menu->numOpciones ; i++)
        {
           if
           (
              (menu->opciones[i] =
              (char*) malloc(strlen(opciones[i]) * sizeof(char) + 1))
           )
           {
              strcpy(menu->opciones[i],opciones[i]);
 
              if(strlen(menu->opciones[i]) > menu->maxlen)
                 menu->maxlen = strlen(menu->opciones[i]);
           }
           else
           {
              int j;
 
              for(j=0 ; j<i ; j++)
                 free(menu->opciones[j]);
 
              free(menu->opciones);
 
              menu->opciones = NULL;
              menu->numOpciones = 0;
 
              if(menu->texto)
              {
                 free(menu->texto);
                 menu->texto = NULL;
              }
 
              if(menu->titulo)
              {
                 free(menu->titulo);
                 menu->titulo = NULL;
              }
 
              menu->lFlags |= MENU_ERROR | MENU_MEMORIA_INSUFICIENTE;
           }
        }
     }
     else
     {
        menu->lFlags |= MENU_ERROR | MENU_MEMORIA_INSUFICIENTE;
        menu->opciones = NULL;
 
        if(menu->texto)
        {
           free(menu->texto);
           menu->texto = NULL;
        }
 
        if(menu->titulo)
        {
           free(menu->titulo);
           menu->titulo = NULL;
        }
     }
  }
}
 
int mostrarMenu(Menu* menu,int modo)
{
  int i=0, opcion=0;
 
  if(menu->numOpciones)
  {
      do{
 
         #ifdef WINDOWS
            system("CLS");
         #elif defined UNIX
            system("clear");
         #endif
 
         if(menu->titulo)
         {
            for(i=0 ; i<80 ; i++)
                printf("=");
 
            printf("%*s\n", 40 + strlen(menu->titulo) / 2, , menu->titulo);
 
            for(i=0 ; i<80 ; i++)
                printf("=");
         }
 
         if(menu->texto)
             printf("%-*s%s\n\n",40 - menu->maxlen / 2 - 8, " ", menu->texto);
 
         for(i=0 ; i < menu->numOpciones ; i++)
         {
            if(modo == MENU_MODO_ULTIMA_CERO && i == menu->numOpciones - 1)
            {
               if(menu->numOpciones > 10)
                  printf("%*s 0. %-*s\n", 40 - menu->maxlen / 2 - 4, " ", 40 + menu->maxlen / 2,
                                           menu->opciones[i]);
               else
                  printf("%*s0. %-*s\n", 40 - menu->maxlen / 2 - 4, " ", 40 + menu->maxlen / 2,
                                          menu->opciones[i]);
            }
            else
            {
               if(modo != MENU_MODO_ULTIMA_CERO)
               {
                  if(menu->numOpciones >= 10)
                  {
                     printf("%*s%2d. %-*s\n", 40 - menu->maxlen / 2 - 4, " ", i+1,
                                               40 + menu->maxlen / 2, menu->opciones[i]);
                  }
                  else
                  {
                     printf("%*s%d. %-*s\n", 40 - menu->maxlen / 2 - 4, " ", i+1,
                                              40 + menu->maxlen / 2, menu->opciones[i]);
                  }
               }
               else
               {
                  if(menu->numOpciones > 10)
                  {
                     printf("%*s%2d. %-*s\n", 40 - menu->maxlen / 2 - 4, " ", i+1,
                                               40 + menu->maxlen / 2, menu->opciones[i]);
                  }
                  else
                  {
                     printf("%*s%d. %-*s\n", 40 - menu->maxlen / 2 - 4, " ", i+1,
                                              40 + menu->maxlen / 2, menu->opciones[i]);
                  }
               }
            }
         }
         printf("%-*s>", 40 - menu->maxlen / 2 - 8, " ");
 
        if(!scanf("%d", &opcion))
        {
           while(getchar() != '\n');
           scanf("%d", &opcion);
        }        
 
      }while
      (
         (
            (modo != MENU_MODO_ULTIMA_CERO) ? (opcion < 1) : (opcion < 0)
         )
         ||
         (
            (modo != MENU_MODO_ULTIMA_CERO) ?
               (opcion >  menu->numOpciones)
               :
               (opcion >= menu->numOpciones)
         )
      );
 
      return opcion;
  }
 
  return -1;
}
 
void finalizarMenu(Menu* menu)
{
  if(menu->texto)
  {
     free(menu->texto);
     menu->texto = NULL;
  }
 
  if(menu->opciones)
  {
      int i=0;
 
      for(i=0 ; i < menu->numOpciones ; i++)
      {
          if(menu->opciones[i])
          {
              free(menu->opciones[i]);
              menu->opciones[i] = NULL;
          }
      }
      free(menu->opciones);
      menu->opciones = NULL;
  }
 
  menu->numOpciones = 0;
}
 

ejemplo: (tener en cuenta que menu.h y menu.c tienen que estar en el mismo directorio donde este el fichero con la funcion principal)
Código
#include <stdio.h>
#include <stdlib.h>
 
#include "menu.h"
#include "menu.c" /* solo si no se va crear un proyecto*/
 
int main(int argc, char *argv[])
{
   Menu menu;
   char *opciones[] = {"Continuar","Salir",""}; /* la ultima opcion siempre es una cadena vacia*/
   int opcion;
 
   inicializarMenu(&menu,"MENU DE PRUEBA","Escoger una opcion:",opciones);
 
   do{
       opcion=mostrarMenu(&menu,MENU_MODO_ULTIMA_CERO);
 
       switch(opcion)
       {
           case 1:
               printf("Has escogido continuar.\n");
               break;
           case 0:
               printf("Has escogido salir.\n");
               break;
       }
   }while(opcion!=0);
 
   /* ¡¡¡¡¡IMPORTANTE!!!!! */
   finalizarMenu(&menu);
 
   return 0;
}
 

En lo que es el menu, me gustaria completar alguna opcion mas, pero el codigo ya es funcional.

Si el codigo no funciona, avisad, ya que es una adaptacion del codigo que realmente tengo guardado. Lo he puesto asi para evitar incluir mas headers y mas codigo.

El codigo de ejemplo lo he imprivosado sobre la marcha. Si hubiese algun error revisad el codigo, que no creo que haya darle muchas vueltas.

Littlehorse:
Esta bastante bien el codigo, como consejo te diria que en vez de pensar en sumarle opciones le mejores la portabilidad. No tiene sentido que sea exclusivo de Windows solamente por system y fflush  ;D.

Un saludo!

^Winder^:
Ahora solo falta ponerle una chincheta al tema  ;D

do-while:
Jajajaja!

Lo de la portabilidad ya lo estaba pensando, al codigo ya tiene algunos mesecillos y ultimamente he estado pensando en la portabilidad.

Lo de system("PAUSE"), tiene facil solucion, para lo del fflush(stdin) ya tengo una alternativa y una solucion, pero lo de limpiar la pantalla... me parece que no hay ningun equivalente estandar para limpiarla, ¿no?

Le hecho un vistazo y a ver que sale.

¡Hasta luego!

Eternal Idol:
Cita de: Winder en  4 Diciembre 2009, 23:22 pm

Ahora solo falta ponerle una chincheta al tema  ;D


Para eso estan los privados  ;)

do-while: con compilacion condicional podes hacerlo.

Navegación

[0] Índice de Mensajes

[#] Página Siguiente