elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Estamos en la red social de Mastodon


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  .NET (C#, VB.NET, ASP) (Moderador: kub0x)
| | | |-+  Menús en modo consola
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Menús en modo consola  (Leído 4,244 veces)
Meta


Desconectado Desconectado

Mensajes: 3.438



Ver Perfil WWW
Menús en modo consola
« en: 3 Febrero 2019, 08:54 am »

Hola:

Estoy usando la consola de C#, me dio ahora por el retro.



Hice este menú de opciones, pero no hace nada. Por ahora solo selecciona las opciones.

Lo que no se es como entrar en otra opción dentro de ella en DOS al pulsar Enter.

Estoy en el submenú que sale un menaje que diga. Estoy dentro de la opción DOS. Con capacidad de pulsar Escape y vuelva al menú principal.

Lo que he hecho hasta ahora es solo esto.

Código
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace Menu_consola_02_cs
  8. {
  9.    class Program
  10.    {
  11.        static void Main(string[] args)
  12.        {
  13.            // Título de la ventana.
  14.            Console.Title = "Menú de opciones";
  15.  
  16.            // Tamaño ventana consola.
  17.            Console.WindowWidth = 20; // X anchura.
  18.            Console.WindowHeight = 8; // Y altura.
  19.  
  20.            // Cursor invisible.
  21.            Console.CursorVisible = false;
  22.  
  23.            //Contador de teclas y navegador
  24.            int contador = 0;
  25.            //tomar la tecla para validar luego
  26.            ConsoleKey tecla;
  27.            //escondo el cursor
  28.            Console.CursorVisible = false;
  29.            do
  30.            {
  31.                //******************************************************************
  32.                //Pinto el menú
  33.                Console.Clear();
  34.                Console.Write("╔══════════════════╗\n");
  35.                if (contador == 0)
  36.                {
  37.                    Console.BackgroundColor = ConsoleColor.White;
  38.                    Console.ForegroundColor = ConsoleColor.Black;
  39.                    Console.Write("║   UNO            ║\n");
  40.                    Console.BackgroundColor = ConsoleColor.Black;
  41.                    Console.ForegroundColor = ConsoleColor.White;
  42.                }
  43.                else
  44.                {
  45.                    Console.BackgroundColor = ConsoleColor.Black;
  46.                    Console.ForegroundColor = ConsoleColor.White;
  47.                    Console.Write("║   UNO            ║\n");
  48.                }
  49.                if (contador == 1)
  50.                {
  51.                    Console.BackgroundColor = ConsoleColor.White;
  52.                    Console.ForegroundColor = ConsoleColor.Black;
  53.                    Console.Write("║   DOS            ║\n");
  54.                    Console.BackgroundColor = ConsoleColor.Black;
  55.                    Console.ForegroundColor = ConsoleColor.White;
  56.                }
  57.                else
  58.                {
  59.                    Console.BackgroundColor = ConsoleColor.Black;
  60.                    Console.ForegroundColor = ConsoleColor.White;
  61.                    Console.Write("║   DOS            ║\n");
  62.                }
  63.                if (contador == 2)
  64.                {
  65.                    Console.BackgroundColor = ConsoleColor.White;
  66.                    Console.ForegroundColor = ConsoleColor.Black;
  67.                    Console.Write("║   TRES           ║\n");
  68.                    Console.BackgroundColor = ConsoleColor.Black;
  69.                    Console.ForegroundColor = ConsoleColor.White;
  70.                }
  71.                else
  72.                {
  73.                    Console.BackgroundColor = ConsoleColor.Black;
  74.                    Console.ForegroundColor = ConsoleColor.White;
  75.                    Console.Write("║   TRES           ║\n");
  76.                }
  77.                if (contador == 3)
  78.                {
  79.                    Console.BackgroundColor = ConsoleColor.White;
  80.                    Console.ForegroundColor = ConsoleColor.Black;
  81.                    Console.Write("║   CUATRO         ║\n");
  82.                    Console.BackgroundColor = ConsoleColor.Black;
  83.                    Console.ForegroundColor = ConsoleColor.White;
  84.                }
  85.                else
  86.                {
  87.                    Console.BackgroundColor = ConsoleColor.Black;
  88.                    Console.ForegroundColor = ConsoleColor.White;
  89.                    Console.Write("║   CUATRO         ║\n");
  90.                }
  91.                if (contador == 4)
  92.                {
  93.                    Console.BackgroundColor = ConsoleColor.White;
  94.                    Console.ForegroundColor = ConsoleColor.Black;
  95.                    Console.Write("║   ESC = SALIR    ║\n");
  96.                    Console.BackgroundColor = ConsoleColor.Black;
  97.                    Console.ForegroundColor = ConsoleColor.White;
  98.                }
  99.                else
  100.                {
  101.                    Console.BackgroundColor = ConsoleColor.Black;
  102.                    Console.ForegroundColor = ConsoleColor.White;
  103.                    Console.Write("║   ESC = SALIR    ║\n");
  104.                }
  105.                Console.Write("╚══════════════════╝\n");
  106.                //Fin de pintar el menú
  107.                //******************************************************************
  108.  
  109.                //leer tecla ingresada por el usuario
  110.                tecla = Console.ReadKey(true).Key;
  111.  
  112.                //validar el tipo de tecla
  113.                if (tecla == ConsoleKey.DownArrow)
  114.                {
  115.                    contador += 1;
  116.                }
  117.                if (tecla == ConsoleKey.UpArrow)
  118.                {
  119.                    contador -= 1;
  120.                }
  121.                //valido que el conteo de teclas no supere el rango establecido por los Ifs de más arriba
  122.                if (contador > 4)
  123.                {
  124.                    contador = 4;
  125.                }
  126.                if (contador < 0)
  127.                {
  128.                    contador = 0;
  129.                }
  130.                //uso la tecla escape como salida
  131.            } while (tecla != ConsoleKey.Escape);
  132.        }
  133.    }
  134. }
  135.  

No logro cuajarlo como si se ha hecho por aquí en este otro ejemplo de abajo.

Código
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace Menu_y_opciones_consola_02_cs
  8. {
  9.    class Program
  10.    {
  11.        static void Main(string[] args)
  12.        {
  13.            // Título de la ventana.
  14.            Console.Title = "Menú y opciones C# 2017";
  15.  
  16.            // Tamaño ventana consola.
  17.            Console.WindowWidth = 30; // X. Ancho.
  18.            Console.WindowHeight = 17; // Y. Alto.
  19.  
  20.            // Cursor invisible.
  21.            Console.CursorVisible = false;
  22.  
  23.            // Cuadro doble borde ventana.
  24.            Menu_y_opciones_consola_02_cs.Cuadro.cuadrado();
  25.  
  26.            // Posición del mansaje en la ventana.
  27.            Console.SetCursorPosition(2, 2);
  28.            Console.WriteLine("Elija una opción:");
  29.            Console.WriteLine("");
  30.            Console.SetCursorPosition(2, 4);
  31.            Console.WriteLine("1 - Opción A.");
  32.            Console.SetCursorPosition(2, 5);
  33.            Console.WriteLine("2 - Opción B.");
  34.            Console.SetCursorPosition(2, 6);
  35.            Console.WriteLine("3 - Opción C.");
  36.            Console.SetCursorPosition(2, 7);
  37.            Console.WriteLine("Escape - Salir.");
  38.            Console.SetCursorPosition(2, 8);
  39.            Console.Write("===============");
  40.  
  41.            ConsoleKey key;
  42.  
  43.            do
  44.            {
  45.                // Cursor invisible
  46.                Console.CursorVisible = false;
  47.  
  48.                // Lee cualquier tecla.
  49.                key = Console.ReadKey(true).Key;
  50.  
  51.                // Variable de mensaje vacío.
  52.                string mensaje = string.Empty;
  53.  
  54.                // Leer tecla selecconada por el usuario.
  55.                switch (key)
  56.                {
  57.                    case ConsoleKey.D1: // Tecla principal 1.
  58.                    case ConsoleKey.NumPad1: // Tecla extendida 1.
  59.                        Console.SetCursorPosition(2, 10);
  60.                        mensaje = "OPCIÓN A."; // Mostrar mensaje en pantalla.
  61.                        break;
  62.  
  63.                    case ConsoleKey.D2:
  64.                    case ConsoleKey.NumPad2:
  65.                        mensaje = "OPCIÓN B.";
  66.                        break;
  67.                    case ConsoleKey.D3:
  68.                    case ConsoleKey.NumPad3:
  69.                        mensaje = "OPCIÓN C.";
  70.                        break;
  71.                }
  72.  
  73.                // Posición de los mensajes.
  74.                Console.SetCursorPosition(2, 10);
  75.                Console.Write("             "); // 13 espacios.
  76.                Console.SetCursorPosition(2, 10);
  77.                Console.Write(mensaje);
  78.  
  79.            }
  80.  
  81.            // Salir de la plicación al pulsar la tecla Escape o número 4.
  82.            while (key != ConsoleKey.Escape);
  83.  
  84.  
  85.        }
  86.    }
  87. }
  88.  

Saludos.


En línea

EdePC
Moderador Global
***
Desconectado Desconectado

Mensajes: 2.042



Ver Perfil
Re: Menús en modo consola
« Respuesta #1 en: 4 Febrero 2019, 00:10 am »

Saludos,

- Mmm, interesante, basta que injertes el siguiente IF:

Código
  1.      //leer tecla ingresada por el usuario
  2.        tecla = Console.ReadKey(true).Key;
  3.  
  4.        if ( tecla == ConsoleKey.Enter) {
  5.          do {
  6.            Console.Clear();
  7.            Console.WriteLine( "Usted a elegido la opcion: " + contador );
  8.            Console.Write( "Presione Escape regresar al menu" );
  9.          } while ( Console.ReadKey(true).Key != ConsoleKey.Escape );
  10.        }
  11.  
  12.      //validar el tipo de tecla
  13.        if (tecla == ConsoleKey.DownArrow) {

- Por cierto, a mí no me reconoce los extraños caracteres que utilizas para dibujar el recuadro, he tenido que recurrir a Unicode: https://en.wikipedia.org/wiki/Box-drawing_character


En línea

Meta


Desconectado Desconectado

Mensajes: 3.438



Ver Perfil WWW
Re: Menús en modo consola
« Respuesta #2 en: 4 Febrero 2019, 21:17 pm »

Muchas gracias. En Windows 10, "Mapa de carácteres" saqué todo. ;)
« Última modificación: 4 Febrero 2019, 23:06 pm por Meta » En línea

Meta


Desconectado Desconectado

Mensajes: 3.438



Ver Perfil WWW
Re: Menús en modo consola
« Respuesta #3 en: 5 Febrero 2019, 22:47 pm »

Buenas:

Me ha servido el truco para el código de arriba. Ahora haciendo un menú de solo usar 16x2 de resolusión. Hago este código base.

En este caso lo que hace es seleccionar opciones en el menú, pero no hace nada más. Las opciones en el menú se llama.

Menú ▲▼

1. UNO
2. DOS
3. TRES
4. CUATRO
5. ESC - SALIR

Por ejemplo, seleccionamos el 3. TRES. Pulse Enter y justo una línea de abajo dice:

3. TRES ▲▼

Después de pulsar Enter, se sustituye el texto 3. TRES ▲▼ por otro abajo.

Alum. ●●●●●●○○

En el cual podemos hacer cosas, estando ya en la subopción indicado arriba. Si pulsamos Enter, de Alum. ●●●●●●○○ vuelve al menú principal en este caso donde estaba, llamdo 3. TRES ▲▼. Si etás todavía en Alum. ●●●●●●○○, puedes pulsar la teclas arriba y abajo para mover las opciones indicadas de esta manera mostrada abajo.

Son 8 puntos. Lo que hace es alumbrar el brillo de una luz, el brillo más débil es de esta manera. Alum. ○○○○○○○○. El brillo máximo es de otra manera, Alum. ●●●●●●●●. Con las flechas del teclado arriba y abajo, seleccionamos un punto, de 1 hasta 8. La mitad sería así: Alum. ●●●●○○○○. Pulsa enter, guarda la configuración en una variable para que la recuerde y sale al menú principal.

Espero que se entienda lo que quiero hacer.

Dejo el código base, solo selecciona opciones pero al pulsar Enter tiene que hacer al menos el 3. TRES.

Código consola C#:
Código
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace Menu_consola_09_cs
  8. {
  9.    class Program
  10.    {
  11.        static void Main(string[] args)
  12.        {
  13.            // Título de la ventana.
  14.            Console.Title = "Menú de opciones";
  15.  
  16.            // Tamaño ventana consola.
  17.            // X anchura.
  18.            Console.WindowWidth = 16;
  19.  
  20.            // Y altura.
  21.            Console.WindowHeight = 2;
  22.  
  23.            // Oculto el cursor.
  24.            Console.CursorVisible = false;
  25.  
  26.            // Contador de teclas y navegador.
  27.            int contador = 0;
  28.  
  29.            // Capturar tecla para luego validar.
  30.            ConsoleKey tecla;
  31.  
  32.            do
  33.            {
  34.  
  35.                //******************************************************************
  36.                // Dibujo el menú.
  37.  
  38.                // Rellenar fondo verde.
  39.                Console.BackgroundColor = ConsoleColor.Green;
  40.  
  41.                // Letras negras.
  42.                Console.ForegroundColor = ConsoleColor.Black;
  43.  
  44.                // Limpiar pantalla.
  45.                Console.Clear();
  46.  
  47.                if (contador == 0)
  48.                {
  49.                    Console.SetCursorPosition(0, 0);
  50.                    Console.Write("MENú &#9650;&#9660;");
  51.                }
  52.  
  53.                if (contador == 1)
  54.                {
  55.                    Console.SetCursorPosition(0, 0);
  56.                    Console.WriteLine("1.   UNO");
  57.                }
  58.  
  59.                if (contador == 2)
  60.                {
  61.                    Console.SetCursorPosition(0, 0);
  62.                    Console.WriteLine("2.   DOS");
  63.                }
  64.  
  65.                if (contador == 3)
  66.                {
  67.                    Console.SetCursorPosition(0, 0);
  68.                    Console.WriteLine("3.   TRES");
  69.                }
  70.  
  71.                if (contador == 4)
  72.                {
  73.                    Console.SetCursorPosition(0, 0);
  74.                    Console.WriteLine("4.  CUATRO");
  75.                }
  76.  
  77.                if (contador == 5)
  78.                {
  79.                    Console.SetCursorPosition(0, 0);
  80.                    Console.WriteLine("5. ESC = SALIR");
  81.                }
  82.  
  83.                // Fin de pintar el menú.
  84.                //******************************************************************
  85.  
  86.                // Leer tecla ingresada por el usuario.
  87.                tecla = Console.ReadKey(true).Key;
  88.  
  89.                //validar el tipo de tecla
  90.                if (tecla == ConsoleKey.DownArrow)
  91.                {
  92.                    contador += 1;
  93.                }
  94.  
  95.                if (tecla == ConsoleKey.UpArrow)
  96.                {
  97.                    contador -= 1;
  98.                }
  99.  
  100.                // Si está en la última opción, salta a la primera.
  101.                if (contador > 5)
  102.                {
  103.                    contador = 0;
  104.                }
  105.  
  106.                // Si está en la primera posición, salta a la última.
  107.                if (contador < 0)
  108.                {
  109.                    contador = 5;
  110.                }
  111.  
  112.                // Uso la tecla escape como salida.
  113.            } while (tecla != ConsoleKey.Escape);
  114.        }
  115.    }
  116. }


Captura:


Una cosa a tener en cuenta. En vez de aparecer

MENú ▲▼

En pantalla, lo primero que debe aparecer en el programa en HOLA. Si pulsas Enter, entonces ya aparece el Menú. Si pulsa salir apareces en HOLA. Luego hacer lo demás con el 3. TRES indicado arriba.

¿Alguna ayuda?

Saludos.
En línea

Serapis
Colaborador
***
Desconectado Desconectado

Mensajes: 3.348


Ver Perfil
Re: Menús en modo consola
« Respuesta #4 en: 6 Febrero 2019, 17:58 pm »

De entrada, una mejor opción es ofrecer al usuario opciones que ya conoce, como subrayar determinada letra, para invitarle a pulsar dicha tecla, es decir relacionar la tecla con dicho menú.

Así se pasaría de este menú soseras:
1. UNO
2. DOS
3. TRES
4. CUATRO
5. ESC - SALIR

...a uno más elaborado así:
    UNO
    DOS
    TRES
    CUATRO
    SUBMENU »
    SALIR (Esc)

Nota que ahora, cuando se pulsa una tecla se revisa si es alguna de las subrayadas, en vez de números. Las teclas Up y Down (left y Right) siguen haciendo lo mismo, moverse entre opciones deseleccionando el actual que pasa a ser el previo y seleccionado el nuevo que pasa a ser el actual, y al tiempo seleccionas el carácter para dicho menú... es decir tu tendrás un string tal que UDTCMS, y al tiempo de subir y bajar el cursor, paseas entre dichas letras, tal que cuando se pulse la tecla enter, haces equivaler esa letra como la opción.
Así tendrías:
Código:
char opcion, previa
entero actual

Cuando el usuario pulsa una tecla:
Código:
previa = opcion
si console.readkey = enter
    opcion = "UDTCMS".CharAt(actual)
sino
    opcion = console.readkey
fin si
llamada a menuAcciones

Verificar si la tecla pulsada 'opcion' es alguna para la que tenemos una acción definida, en cuyo caso ejecutamos su código.
Código:
   funcion menuAcciones
        seleccionar caso para opcion
             caso "U"
                 // acción en este caso
             caso "D"
                 // acción en este caso
             caso "T"
                 // acción en este caso
             caso "C"
                 // acción en este caso
             caso "M"
                 // acción borrar el menú actual y mostrar las opciones del submenú elegido.
             caso "S", consolekey.escape
                 // acción en este caso, salir...
             resto de casos // no se admiten
                 opcion = previa
        fin seleccion
    fin funcion

Nota que he añadido un submenú

Segundo. Recuerda que puedes cambiar la fuente que se usa en la consola. Hay fuentes que contienes los glifos muy apropiados para determinadas cosas... por ejemplo hay fuentes que tienen las teclas (fuente: Game Key 2), muchas flechitas (fuente: Game control) símbolos (fuente: Alchemy), circulos como los que quieres para señalar el nivel de brillo (fuente: Almanac Mt) que tiene para las fases de la luna, los símbolos para luna llena y luna nueva, te pueden valer para lo que quieres... pero vamos hay muchísimas fuentes... tómate 1 día para verlas y elegir la que mejor se acomode. ten en cuenta que puede que al elegir un menú tengas que seleccionar una fuente y luego al slair de él, volver a la fuente previa. Y recuerda también que si el programa no son solo pruebas para ti, sino que es algo que será compilado y repartido, si las fuentes no son las habituales que contiene-mantiene el S.O. será conforme que se acompañen con el programa.

Ah... eso de "Alum." suena más a aluminio que a alumbrar, te sugiero que uses "Nivel de brillo" mejor, y si es demasiado largo, solo "Brillo +" y "Brillo -", y que responda a subir y bajar el brillo no solo las flechas de cursor, UP=right= + y Down=left= - es decir 3 teclas como equivalentes de la misma acción.
Por la misma razón, si la opción 3 ya tiene asignada una acción, no la llames TRES, llámala BRILLO y como aloja un submenú, síguele con una flechita de indicador de submenú: BRILLO »

    UNO
    DOS
    BRILLO »
    CUATRO
    SUBMENU »
    SALIR (Esc)

Así ahora el submenú que se abre al pulsar B (o tener seleccionada la opcion actual=2 (contando 0, es la 3ª), sería así:
    SUBIR BRILLO +
    BAJAR BRILLO -
    --------------------------
    NIVEL ●●●●○○○○
    --------------------------
    VOLVER



Y por fin, te señalo como hacer un menú consistente, del que puedas hacer cosas más o menos complejas, pero asequibles, facilitando enormemente la tarea.
Lo ideal es que crees una clase Menu, y añadas métodos... por ejemplo en el 'New', le pasas el string (que pondré unas líneas más abajo), como un array de strings... que luego la clase debe procesar.

Dibujar un menú es tener elaborado un pequeño menú, como operas con consola, puede ser elaborado enteramente en string... sigue leyendo...
Citar

-1 Raiz                7  -2
00 0UNO                0  -1
01 0DOS                0  -1
02 0BRILLO             6  -1
03    0SUBIR BRILLO +  0   2
04    0BAJAR BRILLO -  0   2
05    ---------------- 0   2
06    NIVEL (N)        0   2
07    ---------------- 0   2
08    0VOLVER          0   2
09 0CUATRO             0  -1
10 1CINCO              0  -1
11 ----------------    0  -1
12 0SALIR              0  -1
             
Si te das cuenta, poner un tabulador (en el foro espacios, porque no deja poner tabuladores), es más por ver visualmente la jerarquía del menú y corregir si algo no está bien... ya que la jerarquía real se expresa con los números en las columnas de la derecha.
También si te fijas, hay varias columna...

Esto sugiere pués crear una estructura Item, debajo las explicaciones de dicha estructura y relacionarla con esas línea de texto que contienene el menú:
Código:
Estructura Item
    entero indice      //índice absoluto del menú.
    entero hotspot    // índice del caracter que está subrayado (el que activa su acción)
    string nombre        // el texto que se muestra.

    entero hijos       // cantidad de hijos que tiene dicho submenú.
                        // El índice de los mismo, empieza en el índice absoluto siguiente al padre.
                        // ojo, para localizar sus hijos y no sus nietos, se deben contar solo los que
    entero padre      // índice absoluto del menú padre. puede ser 0 para todos excepto para esos de volver.
                        //  pero con menús complejos mejor que apunten al padre, así sabremos buscar si un menú es hijo o no de otro.
fin estructura


Inicialmente se parte de un array de esta estructura, que se crea a partir del string anteriormente indicado.
Visiblemente no está muy logrado (no me apetece perder demasiado tiempo en ello), pero te describo cada columna.

- La columna 0 en realidad es innecesaria reflejarla en el string. Es el índice correlativo (es decir la enésima línea), que viene a coincidir con el índice en el array, la he puesto solo para facilitar señalar a qué indice apuntar como padre. En la estructura si debe hacerse constar, pués en caso de tener hijos, empieza en el índice siguiente a éste, por lo que es preciso conocerlo.
- La columna 1 es un dígito (0-9) indica que carácter del texto estará subrayado (hotspot en la estructura). Si no tiene dígito, en la estructura debe consignarse -1. A la hora de dibujar dicho ítem, se considera si el número es mayor o igual a 0, en cuyo caso la letra en dicha posición se subraya (también vale dibujarla de otro color o ponerla en negrita).
- La columna 2 contiene el texto del menú (si te gusta todo en mayúsculas allá tú). Campo 'nombre' de la estructura.
- La columna 3 es un número, señala cuantos hijos tiene. Si un menú tiene hijos, tendrá un valor mayor que 0, y servirá para en un bucle localizarlos y saber cuando terminar... cuando se seleccione un ítem tu invocas a tu clase:
Código:
Si menu.Item(x).tieneHijos
    dibujarSumenuDe(menu, item(x))
sino
    llamada a ejecutarAccion(x)  // la función que mas arriba llamamos menuAcciones
fin si
servirá también para a la hora de dibujar el ítem del menú, dibujar el " »" a la derecha del nombre del menú. Es decir, se añade el " »" detrás del nombre.
- La columna 4 es un número, señala quien es el padre de dicho menú. Observa como todo el submenú de brillo (indice 2), tiene como padre precisamente el valor 2 (indices 3 a 8). Un valor -1 indica que están el padre es raíz, es decir que no admite referencia al padre.
- Una posible columna 5 podría indicar otras opciones como fuente (supongamos que usas 5 fuentes distintas, un dígito indicaría que fuente usar) . nuevamente solo los ítems que son submenús tendrían un digito a considerar, para el resto  un valor -1...

Este sería el code para el ítem 'Volver de un submenú...
Código:
if menu.item(x).padre > -1
    dibujarSubmenuDe(menu, menu.getItemPadre(menu.item(x).padre))
fin si
Pués que el único menú Volver en raíz, sería el equivalente a Salir, no habrá opción de apuntar a un padre inexistente, pués solo sucede en los menús volver... es decir dicho valor se podría ignorar para todos (tener valor 0) excepto para los ítems volver. se podría modificar así:
Código:
if menu.item(x).padre => 0
    dibujarSubmenuDe(menu, menu.getItemPadre(menu.item(x).padre))
sino
    Salir
fin si

Por último, recuerda separar adecuadamente el tratamiento de datos del procesado de dibujado.
Para el procesado de los datos, sugiero una clase menú, que maneje ítems. Y un array de estructuras Item.
Para el dibujado también sugiero encapsular todo el proceso en una clase que en un método dibujar, recibe como parámetro la clase menú (para tener acceso a los miembros de la clase) y un ítem del menú, (el programa tiene un ítem -1 que es raíz y que despliega el menú principal, que suele ser un menú horizontal, del que descuelgan luego 'las ramas'), y es éste ítem para el que a través del menú dibujará sus ítems hijos, observando cuantos hijos tiene, sabiendo que empiezan un índice después y que sus hijos son aquellos que tiene en el campo padr,e el índice de dicho ítem.
La clase principal, es la que muestra el resultado y la que intercede entre el menú, el usuario y la clase dibujado.
La clase de dibujar, puede alojar también opciones sobre la fuente usada, colores  a usar en cada caso, etc... si se simplifica al extremo, quizás no requiera usar una clase para ello, es decir contener un simple método "dibujarMenu", no justifica una clase.

...confío que te ilustre lo sufieciente para mejorar tu esquema aunque lo complique un poco y tardes más, a futuro tendrás un base adecuada para proyectos más o menos complejos... que te ayudarían a ahorrar mucho tiempo.


P.d:
Cuando solicitas al menú que te devuelve un submenú, también se crea una cadena o array 'hotkeys', que se compone exactamente de cada carácter hotkey de cada ítem del menú. Si un ítem no tiene hotkey, para ello se deja como carácter un char 'nulo', es decir un carácter que no sea pulsable por teclado, o dicho de otra manera, que no sean las teclas usadas 'enter, up, down, right, left, escape', ni letras o dígitos, por ejemplo '*' así de una sola evaluación puedes ver si hay que perder tiempo o no en procesar la tecla pulsada...
por ejemplo la cadena hotkeys para el submenú brillo, podría ser: hotkeys = "SB***V" (de Subir, Bajar y Volver, las otros ítems del menú no generan acciones, una muestra el nivel del brillo y las otras dos son separadores de menús).

Código:
opcion = console.readkey
k = InString(hotkeys, opcion)  // devuelve el índice en el substring, que nos da el índice del menú pulsado (si existe)
Si (k >= 0)
   si tecla es distinto de *
      llamada a CambiarFoco(k)
      llamada a ejecutarAccion(actual)
   fin si
sino
    // todavía puede ser enter, up, down, +, - left, right, pero estas es mejor procesarlas en otra función aparte
    seleccionar opcion
         caso enter
              llamada a ejecutarAccion(actual)
         caso up, right, +
              si (actual < maxItems)
                   CambiarFoco(actual + 1)
              fin si
         caso down, left, -
              si (actual > 0)
                   CambiarFoco(actual - 1)
              fin si
    fin seleccion
fin si

Código:
funcion CambiarFoco(entero ahora)
    previo = actual
    deseleccionar previo
    actual = ahora
    seleccionar actual
fin funcion
Si el menú tiene demasiados submenús, entre medias, al no estar seguidos los ítems, 'hermanos' exigirá una búsqueda, para obtener su índice absoluto, que es el que luego se habrá de seleccionar (bloque select case) para poder ejecutar la acción asociada... puede ahorrarse la búsqueda si se añade 2 columnas más, sobre el menú, donde se enlaza un item a su hermano siguiente y previo... Es decir complicando un poco más el menú, hacemos que sea más rápido el acceso.

Añadiendo ambos ´campos a la estructura:
Código:
Estructura Item
    entero indice    
    entero hotspot  
    string nombre
    entero padre  
    entero hijos  
    entero siguiente   // el índice absoluto de su hermano siguiente (columna 5)
    entero previo      // el índice absouto de su hermano previo (columna 6)    
fin estructura

Aquí como quedaría añadiendo esas  2  columnas nuevas a la derecha. El guión viene a indicar que no importa, no son seleccionables, no dan ancceso desde ellos al anterior y/o sigiente.
Citar

-1 Raiz                7  -2  -  -
00 0UNO                0  -1  1  -
01 0DOS                0  -1  2  0
02 0BRILLO             6  -1  9  1
03    0SUBIR BRILLO +  0   2  4  -
04    0BAJAR BRILLO -  0   2  8  3
05    ---------------- 0   2  -  -
06    NIVEL (N)        0   2  -  -
07    ---------------- 0   2  -  -
08    0VOLVER          0   2  -  4
09 0CUATRO             0  -1 10  2
10 1CINCO              0  -1 12  9
11 ----------------    0  -1  -  -
12 0SALIR              0  -1  - 10
También en el código debe mantenerrse la estructura del primer ítem, en pantalla, para obtener el índice absoluto en el array y poder obtener datos del resto de hermanos...
« Última modificación: 7 Febrero 2019, 00:20 am por NEBIRE » En línea

Meta


Desconectado Desconectado

Mensajes: 3.438



Ver Perfil WWW
Re: Menús en modo consola
« Respuesta #5 en: 7 Febrero 2019, 06:16 am »

Gracias, estoy en ello. ;)

Lo dejo más claro, luego hago esquema de cada submenú.



Antes usé solo if. Ahora hice lo mismo pero con Switch. No se cual es el más indicado para hacer el submenú.

Código
  1.                switch (contador)
  2.                {
  3.                    case 0:
  4.                        Console.SetCursorPosition(0, 0);
  5.                        Console.Write("FECHA");
  6.  
  7.  
  8.                        break;
  9.                    case 1:
  10.                        Console.SetCursorPosition(0, 0);
  11.                        Console.Write("MENú &#9650;&#9660;");
  12.                        break;
  13.                    case 2:
  14.                        Console.SetCursorPosition(0, 0);
  15.                        Console.WriteLine("1.   UNO");
  16.                        break;
  17.                    case 3:
  18.                        Console.SetCursorPosition(0, 0);
  19.                        Console.WriteLine("2.   DOS");
  20.                        break;
  21.                    case 4:
  22.                        Console.SetCursorPosition(0, 0);
  23.                        Console.WriteLine("3.   TRES");
  24.                        break;
  25.                    case 5:
  26.                        Console.SetCursorPosition(0, 0);
  27.                        Console.WriteLine("4.  CUATRO");
  28.                        break;
  29.                    case 6:
  30.                        Console.SetCursorPosition(0, 0);
  31.                        Console.WriteLine("5. ESC = SALIR");
  32.                        break;
  33.                    default:
  34.                        Console.WriteLine("Fuera de rango.");
  35.                        break;
  36.                }

Salu2.
« Última modificación: 7 Febrero 2019, 06:53 am por Meta » En línea

Serapis
Colaborador
***
Desconectado Desconectado

Mensajes: 3.348


Ver Perfil
Re: Menús en modo consola
« Respuesta #6 en: 7 Febrero 2019, 15:16 pm »

If es el más adecuado cuando slo tienes 2,3 o si me apuras hasta 4 opciones...
Cuando sean múltiples opciones, el switch ofrece mucha más claridad. O cuando sean 3 o 4 pero cada caso comparte parcialmente acciones, ya que con un correcto orden el uso de break, facilita la no duplicación de código.
En línea

Meta


Desconectado Desconectado

Mensajes: 3.438



Ver Perfil WWW
Re: Menús en modo consola
« Respuesta #7 en: 7 Febrero 2019, 21:39 pm »

Buenas:

Hoy me volví loco de la cabeza. Entrego código incompleto, lo entrego como curiosidad. Lo intentaré acabarlo al 100 %.

Código
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace Menu_consola_09_cs
  8. {
  9.    class Program
  10.    {
  11.        // Variables globales.
  12.        public static int luz = 6;
  13.        public const int BRILLO_MAX = 8;
  14.        public static bool radio = false;
  15.  
  16.        static void Main(string[] args)
  17.        {
  18.            // Título de la ventana.
  19.            Console.Title = "Menú de opciones";
  20.  
  21.            // Tamaño ventana consola.
  22.            // X anchura.
  23.            Console.WindowWidth = 16;
  24.  
  25.            // Y altura.
  26.            Console.WindowHeight = 2;
  27.  
  28.            // Oculto el cursor.
  29.            Console.CursorVisible = false;
  30.            ConsoleKey teclaInicial;
  31.            Console.BackgroundColor = ConsoleColor.Green;
  32.  
  33.            // Letras negras.
  34.            Console.ForegroundColor = ConsoleColor.Black;
  35.  
  36.            // Limpiar pantalla.
  37.            do
  38.            {
  39.                Console.Clear();
  40.                Console.WriteLine(DateTime.Now.ToString("dd/MM/yyyy"));
  41.                teclaInicial = Console.ReadKey(true).Key;
  42.                if(teclaInicial == ConsoleKey.Enter)
  43.                {
  44.                    menuPrincipal();
  45.                }
  46.            } while (teclaInicial != ConsoleKey.Escape); // SANTIAGOOOOO.
  47.  
  48.        }
  49.        public static void menuPrincipal()
  50.        {
  51.  
  52.            // Contador de teclas y navegador.
  53.            int opcion = 0;
  54.            bool salir = false;
  55.            // Capturar tecla para luego validar.
  56.            ConsoleKey tecla;
  57.  
  58.            do
  59.            {
  60.  
  61.                //******************************************************************
  62.                // Dibujo el menú.
  63.  
  64.                // Rellenar fondo verde.
  65.                Console.BackgroundColor = ConsoleColor.Green;
  66.  
  67.                // Letras negras.
  68.                Console.ForegroundColor = ConsoleColor.Black;
  69.  
  70.                // Limpiar pantalla.
  71.                Console.Clear();
  72.  
  73.                switch (opcion)
  74.                {
  75.                    case 0:
  76.                        Console.SetCursorPosition(0, 0);
  77.                        Console.Write("Language");
  78.                        break;
  79.                    case 1:
  80.                        Console.SetCursorPosition(0, 0);
  81.                        Console.WriteLine("Ajustar hora ->");
  82.                        break;
  83.                    case 2:
  84.                        Console.SetCursorPosition(0, 0);
  85.                        Console.WriteLine("Ajustar fecha ->");
  86.                        break;
  87.                    case 3:
  88.                        Console.SetCursorPosition(0, 0);
  89.                        Console.WriteLine("Brillo");
  90.                        break;
  91.                    case 4:
  92.                        Console.SetCursorPosition(0, 0);
  93.                        Console.WriteLine("Ver radio");
  94.                        break;
  95.                    case 5:
  96.                        Console.SetCursorPosition(0, 0);
  97.                        Console.WriteLine("Vol. avisos");
  98.                        break;
  99.                    case 6:
  100.                        Console.SetCursorPosition(0, 0);
  101.                        Console.WriteLine("Vol. teclas");
  102.                        break;
  103.                    case 7:
  104.                        Console.SetCursorPosition(0, 0);
  105.                        Console.WriteLine("Salir menú");
  106.                        break;
  107.                    default:
  108.                        Console.WriteLine("Fuera de rango.");
  109.                        break;
  110.                }
  111.  
  112.                // Fin de pintar el menú.
  113.                //******************************************************************
  114.  
  115.                // Leer tecla ingresada por el usuario.
  116.                tecla = Console.ReadKey(true).Key;
  117.  
  118.                // Validar el tipo de tecla.
  119.                if (tecla == ConsoleKey.Enter)
  120.                {
  121.                    switch (opcion)
  122.                    {
  123.                        case 3:
  124.                            brillo();
  125.                            break;
  126.                        case 4:
  127.                            radiazo();
  128.                            break;
  129.                        case 7:
  130.                            salir = true;
  131.                            break;
  132.                        default:
  133.                            break;
  134.                    }
  135.                }
  136.  
  137.                if (tecla == ConsoleKey.DownArrow)
  138.                {
  139.                    opcion += 1;
  140.                }
  141.  
  142.                if (tecla == ConsoleKey.UpArrow)
  143.                {
  144.                    opcion -= 1;
  145.                }
  146.  
  147.                // Si está en la última opción, salta a la primera.
  148.                if (opcion > 7)
  149.                {
  150.                    opcion = 0;
  151.                }
  152.  
  153.                // Si está en la primera posición, salta a la última.
  154.                if (opcion < 0)
  155.                {
  156.                    opcion = 7;
  157.                }
  158.  
  159.                // Uso la tecla escape como salida.
  160.            } while (salir==false);
  161.        }
  162.  
  163.        #region Brillo (3).
  164.        public static void brillo()
  165.        {
  166.            ConsoleKey teclaBrillo;
  167.            Console.Clear();
  168.            do
  169.            {
  170.  
  171.                Console.SetCursorPosition(0, 0);
  172.                Console.Write("Luz: ");
  173.  
  174.                for (int i = 0; i < luz; i++)
  175.                {
  176.                    Console.Write("X");
  177.                }
  178.  
  179.                for (int j = 0; j < (BRILLO_MAX - luz); j++)
  180.                {
  181.                    Console.Write("-");
  182.                }
  183.  
  184.                teclaBrillo = Console.ReadKey(true).Key;
  185.  
  186.                // ¿Se pulsó el cursor arriba?
  187.                if (teclaBrillo == ConsoleKey.UpArrow)
  188.                {
  189.                    //¿no llega al limite?
  190.                    if (luz < BRILLO_MAX)
  191.                    {
  192.                        // Incrementa 1.
  193.                        luz++;
  194.                    }
  195.                }
  196.  
  197.                if (teclaBrillo == ConsoleKey.DownArrow)
  198.                {
  199.                    if (luz > 0)
  200.                    {
  201.                        // Decremmenta 1.
  202.                        luz--;
  203.                    }
  204.                }
  205.  
  206.            } while (teclaBrillo != ConsoleKey.Enter);
  207.        }
  208.        #endregion
  209.  
  210.        #region Radio (4).
  211.        public static void radiazo()
  212.        {
  213.            ConsoleKey teclaRadio;
  214.            Console.Clear();
  215.            do
  216.            {
  217.                Console.SetCursorPosition(0, 0);
  218.                Console.Write("Radio: ");
  219.  
  220.  
  221.  
  222.                if (radio == true)
  223.                {
  224.                    Console.SetCursorPosition(7, 0);
  225.                    Console.Write("On ");
  226.                }
  227.  
  228.                else
  229.                {
  230.                    Console.SetCursorPosition(7, 0);
  231.                    Console.Write("Off");
  232.                }
  233.  
  234.                teclaRadio = Console.ReadKey(true).Key;
  235.  
  236.                if (teclaRadio == ConsoleKey.UpArrow)
  237.                {
  238.                    Console.SetCursorPosition(7, 0);
  239.                    Console.Write("On ");
  240.                    radio = true;
  241.                }
  242.  
  243.                if (teclaRadio == ConsoleKey.DownArrow)
  244.                {
  245.                    Console.SetCursorPosition(7, 0);
  246.                    Console.Write("Off");
  247.                    radio = false;
  248.                }
  249.  
  250.            } while (teclaRadio != ConsoleKey.Enter);
  251.        }
  252.        #endregion
  253.  
  254.    }
  255. }
  256.  
  257.  

Hay una parte en Ver Radio que no me sale. Si pulso la fecla del teclado arriba, me sale "Radio: On". Si sigo pulsado la fecla arriba otra vez, se queda en On, lo mismo hacia abajo, que se queda en Off.

¿Hay alguna manera de que si pulso la tecla flecha arriba todo el rato o abajo se cambie en On y Off?

El código es esta función.
Código
  1. public static void radiazo()
  2.        {
  3.            ConsoleKey teclaRadio;
  4.            Console.Clear();
  5.            do
  6.            {
  7.                Console.SetCursorPosition(0, 0);
  8.                Console.Write("Radio: ");
  9.  
  10.  
  11.  
  12.                if (radio == true)
  13.                {
  14.                    Console.SetCursorPosition(7, 0);
  15.                    Console.Write("On ");
  16.                }
  17.  
  18.                else
  19.                {
  20.                    Console.SetCursorPosition(7, 0);
  21.                    Console.Write("Off");
  22.                }
  23.  
  24.                teclaRadio = Console.ReadKey(true).Key;
  25.  
  26.                if (teclaRadio == ConsoleKey.UpArrow)
  27.                {
  28.                    Console.SetCursorPosition(7, 0);
  29.                    Console.Write("On ");
  30.                    radio = true;
  31.                }
  32.  
  33.                if (teclaRadio == ConsoleKey.DownArrow)
  34.                {
  35.                    Console.SetCursorPosition(7, 0);
  36.                    Console.Write("Off");
  37.                    radio = false;
  38.                }
  39.  
  40.            } while (teclaRadio != ConsoleKey.Enter);
  41.        }

Saludos
;)
« Última modificación: 7 Febrero 2019, 23:31 pm por Meta » En línea

Serapis
Colaborador
***
Desconectado Desconectado

Mensajes: 3.348


Ver Perfil
Re: Menús en modo consola
« Respuesta #8 en: 8 Febrero 2019, 18:33 pm »

Aunque no he revisado el código... basta una ojeada rápida para ver que tiene mejor pinta...

Sobre tus dudas:
Citar
Si pulso la fecla del teclado arriba, me sale "Radio: On". Si sigo pulsado la fecla arriba otra vez, se queda en On, lo mismo hacia abajo, que se queda en Off.
¿Hay alguna manera de que si pulso la tecla flecha arriba todo el rato o abajo se cambie en On y Off?
A ver si te he entendido correctamente...
Tu tienes off, pulsas cursor arriba y se pone on, preguntas que si sería posible que si segir pulsando cursor arriba cambie de on a ofF (y viceversa en caso opuesto)??
Si te entendí bien, la respuesta es sí...

Observa esta pequeña reflexión:

Código:
entero estadoRadio= 0        // off
entero max = 5                  // este valor por ejemplo.

Si tecla = Up
    si estadoradio <= 0         //cambia su estado por 'contracorriente'
        estadoradio = 1
    sino
        estadoradio +=1         // acumula estado
        si EstadoRadio = Max  // llegando a cierto umbral, pasamos al estado opuesto.
            estadoRadio = 0
        fin si
    fin si
PeroSi tecla = down
    si estadoradio =>1  
        estadoRadio = 0
    sino
        estadoRadio -=1  
        si estadoradio = -(Max-1)  //mismas cantidad que para ambos casos.
            estadoRadio= 1
        fin
    fin si
sino
    salir  //otra tecla que no venga a cuento con este ítem del menú.
fin si

// finalmente dibujamos el estado según el valor.
Si estadoRadio >0
    escribir "On "
sino
    escribir "Off"
fin si    

Si lo examinas bien, si está off, y pulsas arriba se pone en on, una nueva pulsación arriba, aumenta una cuenta, y si se pulsa las veces sufientes la cuenta llega a umbral, que lo pone al estado contrario. Debajo de esa operatoria, finalmente se dibuja el estado 'on/off' resultante .
Tu decides el valor de umbral, pero que sea mayor que 2, si no, es preferibel usar un buleano, que alterne el valor inndistintamente de la tecla pulsada (y en ese caso es mejor que responda a la tecla espacio o enter), donde una pulsación lo pone 'on' y una nueva pulsación en 'off').

Si pulsas la tecla, con una duración larga sin soltarla y esperas que responda a dicho estado, se complica la cosa por consola... esa gestión desde interfaz es sencilla, pués la provee la propio ventana/formulario con eventos 'keyDown' (tecla pulsada) y 'keyUp' (tecla soltada), por consola no creo que merezca la pena perder el tiempo, resultará farragoso y las consolas están pensadas para determinadas acciones.
Si la interacción con el usuario debe ser más poderosa, estonces siempre es mejor abandonar la consola y proveer una interfaz de usuario con todo su potencial. Esto es, cada cosa hay que usarla para lo que se ha diseñado, mejor, que para hacer aquello para lo que justamente no ha sido diseñado. A nadie se le ocurre usar un patinete para transportar containers de mercancías, ni usar un un tren de alta velocidad como el juguete de un niño.


En línea

Meta


Desconectado Desconectado

Mensajes: 3.438



Ver Perfil WWW
Re: Menús en modo consola
« Respuesta #9 en: 8 Febrero 2019, 20:47 pm »

Hola:

Sí, haz entedido bien, tamién es mejor la opción booleana. Lo saqué así al final.

Código
  1.        public static void radiazo()
  2.        {
  3.            ConsoleKey teclaRadio;
  4.            Console.Clear();
  5.            do
  6.            {
  7.                Console.SetCursorPosition(0, 0);
  8.                Console.Write("Ver radio: ");          
  9.  
  10.                Console.SetCursorPosition(11, 0);
  11.                Console.Write(radio ? "On " : "Off");
  12.  
  13.  
  14.                teclaRadio = Console.ReadKey(true).Key;
  15.  
  16.                if ((teclaRadio == ConsoleKey.UpArrow) || (teclaRadio == ConsoleKey.DownArrow))
  17.                {
  18.                    radio = !radio;
  19.                }
  20.  
  21.            } while (teclaRadio != ConsoleKey.Enter);
  22.        }

Si vez que ahora dice el On y Off si pulso todo el rato arriba o abajo ya puedo cambiar, tal como lo haz entendido.

Si te fijas bien, el On y Off está fijo. Quiero que parpadee en cada 0.5 segundos, o lo que es lo mismo, 500 ms (mili segundos).

Iba a usar Sleep, pero prefiero usar timer para que no se quede esclavo el programa aunque sea corto de tiempo.

¿Por qué quiero hacer esto así?

Porque estoy practicando en modo consola usando el 16x2, aunque ahora mismo el 16x1. Cuando lo domine partes por partes lo que deseo, como el booleano, el XXXXXX-- del brillo, y me falta el volumen del 0 que es mute hasta aumentar el sonido hasta el 7. Poco a poco lo estoy haciendo.

Cuando acabe con C#, adaptaré este código a un LCD real de 16x2 como puedes ver aquí.

Quiero aprender hacer menús para LCD pero primero que acabo antes, en PC. ;)


Saludos.
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines