Menús en modo consola

Iniciado por Meta, 3 Febrero 2019, 08:54 AM

0 Miembros y 1 Visitante están viendo este tema.

Meta

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 (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Menu_consola_02_cs
{
    class Program
    {
        static void Main(string[] args)
        {
            // Título de la ventana.
            Console.Title = "Menú de opciones";

            // Tamaño ventana consola.
            Console.WindowWidth = 20; // X anchura.
            Console.WindowHeight = 8; // Y altura.

            // Cursor invisible.
            Console.CursorVisible = false;

            //Contador de teclas y navegador
            int contador = 0;
            //tomar la tecla para validar luego
            ConsoleKey tecla;
            //escondo el cursor
            Console.CursorVisible = false;
            do
            {
                //******************************************************************
                //Pinto el menú
                Console.Clear();
                Console.Write("╔══════════════════╗\n");
                if (contador == 0)
                {
                    Console.BackgroundColor = ConsoleColor.White;
                    Console.ForegroundColor = ConsoleColor.Black;
                    Console.Write("║   UNO            ║\n");
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                }
                else
                {
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write("║   UNO            ║\n");
                }
                if (contador == 1)
                {
                    Console.BackgroundColor = ConsoleColor.White;
                    Console.ForegroundColor = ConsoleColor.Black;
                    Console.Write("║   DOS            ║\n");
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                }
                else
                {
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write("║   DOS            ║\n");
                }
                if (contador == 2)
                {
                    Console.BackgroundColor = ConsoleColor.White;
                    Console.ForegroundColor = ConsoleColor.Black;
                    Console.Write("║   TRES           ║\n");
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                }
                else
                {
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write("║   TRES           ║\n");
                }
                if (contador == 3)
                {
                    Console.BackgroundColor = ConsoleColor.White;
                    Console.ForegroundColor = ConsoleColor.Black;
                    Console.Write("║   CUATRO         ║\n");
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                }
                else
                {
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write("║   CUATRO         ║\n");
                }
                if (contador == 4)
                {
                    Console.BackgroundColor = ConsoleColor.White;
                    Console.ForegroundColor = ConsoleColor.Black;
                    Console.Write("║   ESC = SALIR    ║\n");
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                }
                else
                {
                    Console.BackgroundColor = ConsoleColor.Black;
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.Write("║   ESC = SALIR    ║\n");
                }
                Console.Write("╚══════════════════╝\n");
                //Fin de pintar el menú
                //******************************************************************

                //leer tecla ingresada por el usuario
                tecla = Console.ReadKey(true).Key;

                //validar el tipo de tecla
                if (tecla == ConsoleKey.DownArrow)
                {
                    contador += 1;
                }
                if (tecla == ConsoleKey.UpArrow)
                {
                    contador -= 1;
                }
                //valido que el conteo de teclas no supere el rango establecido por los Ifs de más arriba
                if (contador > 4)
                {
                    contador = 4;
                }
                if (contador < 0)
                {
                    contador = 0;
                }
                //uso la tecla escape como salida
            } while (tecla != ConsoleKey.Escape);
        }
    }
}


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

Código (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Menu_y_opciones_consola_02_cs
{
    class Program
    {
        static void Main(string[] args)
        {
            // Título de la ventana.
            Console.Title = "Menú y opciones C# 2017";

            // Tamaño ventana consola.
            Console.WindowWidth = 30; // X. Ancho.
            Console.WindowHeight = 17; // Y. Alto.

            // Cursor invisible.
            Console.CursorVisible = false;

            // Cuadro doble borde ventana.
            Menu_y_opciones_consola_02_cs.Cuadro.cuadrado();

            // Posición del mansaje en la ventana.
            Console.SetCursorPosition(2, 2);
            Console.WriteLine("Elija una opción:");
            Console.WriteLine("");
            Console.SetCursorPosition(2, 4);
            Console.WriteLine("1 - Opción A.");
            Console.SetCursorPosition(2, 5);
            Console.WriteLine("2 - Opción B.");
            Console.SetCursorPosition(2, 6);
            Console.WriteLine("3 - Opción C.");
            Console.SetCursorPosition(2, 7);
            Console.WriteLine("Escape - Salir.");
            Console.SetCursorPosition(2, 8);
            Console.Write("===============");

            ConsoleKey key;

            do
            {
                // Cursor invisible
                Console.CursorVisible = false;

                // Lee cualquier tecla.
                key = Console.ReadKey(true).Key;

                // Variable de mensaje vacío.
                string mensaje = string.Empty;

                // Leer tecla selecconada por el usuario.
                switch (key)
                {
                    case ConsoleKey.D1: // Tecla principal 1.
                    case ConsoleKey.NumPad1: // Tecla extendida 1.
                        Console.SetCursorPosition(2, 10);
                        mensaje = "OPCIÓN A."; // Mostrar mensaje en pantalla.
                        break;

                    case ConsoleKey.D2:
                    case ConsoleKey.NumPad2:
                        mensaje = "OPCIÓN B.";
                        break;
                    case ConsoleKey.D3:
                    case ConsoleKey.NumPad3:
                        mensaje = "OPCIÓN C.";
                        break;
                }

                // Posición de los mensajes.
                Console.SetCursorPosition(2, 10);
                Console.Write("             "); // 13 espacios.
                Console.SetCursorPosition(2, 10);
                Console.Write(mensaje);

            }

            // Salir de la plicación al pulsar la tecla Escape o número 4.
            while (key != ConsoleKey.Escape);


        }
    }
}


Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

EdePC

Saludos,

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

Código (csharp) [Seleccionar]
      //leer tecla ingresada por el usuario
        tecla = Console.ReadKey(true).Key;

        if ( tecla == ConsoleKey.Enter) {
          do {
            Console.Clear();
            Console.WriteLine( "Usted a elegido la opcion: " + contador );
            Console.Write( "Presione Escape regresar al menu" );
          } while ( Console.ReadKey(true).Key != ConsoleKey.Escape );
        }

      //validar el tipo de tecla
        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

Meta

#2
Muchas gracias. En Windows 10, "Mapa de carácteres" saqué todo. ;)
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Meta

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 (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Menu_consola_09_cs
{
    class Program
    {
        static void Main(string[] args)
        {
            // Título de la ventana.
            Console.Title = "Menú de opciones";

            // Tamaño ventana consola.
            // X anchura.
            Console.WindowWidth = 16;

            // Y altura.
            Console.WindowHeight = 2;

            // Oculto el cursor.
            Console.CursorVisible = false;

            // Contador de teclas y navegador.
            int contador = 0;

            // Capturar tecla para luego validar.
            ConsoleKey tecla;

            do
            {

                //******************************************************************
                // Dibujo el menú.
               
                // Rellenar fondo verde.
                Console.BackgroundColor = ConsoleColor.Green;

                // Letras negras.
                Console.ForegroundColor = ConsoleColor.Black;
               
                // Limpiar pantalla.
                Console.Clear();

                if (contador == 0)
                {
                    Console.SetCursorPosition(0, 0);
                    Console.Write("MENú ▲▼");
                }

                if (contador == 1)
                {
                    Console.SetCursorPosition(0, 0);
                    Console.WriteLine("1.   UNO");
                }

                if (contador == 2)
                {
                    Console.SetCursorPosition(0, 0);
                    Console.WriteLine("2.   DOS");
                }

                if (contador == 3)
                {
                    Console.SetCursorPosition(0, 0);
                    Console.WriteLine("3.   TRES");
                }

                if (contador == 4)
                {
                    Console.SetCursorPosition(0, 0);
                    Console.WriteLine("4.  CUATRO");
                }

                if (contador == 5)
                {
                    Console.SetCursorPosition(0, 0);
                    Console.WriteLine("5. ESC = SALIR");
                }

                // Fin de pintar el menú.
                //******************************************************************

                // Leer tecla ingresada por el usuario.
                tecla = Console.ReadKey(true).Key;

                //validar el tipo de tecla
                if (tecla == ConsoleKey.DownArrow)
                {
                    contador += 1;
                }

                if (tecla == ConsoleKey.UpArrow)
                {
                    contador -= 1;
                }

                // Si está en la última opción, salta a la primera.
                if (contador > 5)
                {
                    contador = 0;
                }

                // Si está en la primera posición, salta a la última.
                if (contador < 0)
                {
                    contador = 5;
                }

                // Uso la tecla escape como salida.
            } while (tecla != ConsoleKey.Escape);
        }
    }
}



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.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Serapis

#4
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:

char opcion, previa
entero actual


Cuando el usuario pulsa una tecla:

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.

   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ú:

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:

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ú...

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í:

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).


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



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:

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...

Meta

#5
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 (csharp) [Seleccionar]
                switch (contador)
                {
                    case 0:
                        Console.SetCursorPosition(0, 0);
                        Console.Write("FECHA");


                        break;
                    case 1:
                        Console.SetCursorPosition(0, 0);
                        Console.Write("MENú ▲▼");
                        break;
                    case 2:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("1.   UNO");
                        break;
                    case 3:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("2.   DOS");
                        break;
                    case 4:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("3.   TRES");
                        break;
                    case 5:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("4.  CUATRO");
                        break;
                    case 6:
                        Console.SetCursorPosition(0, 0);
                        Console.WriteLine("5. ESC = SALIR");
                        break;
                    default:
                        Console.WriteLine("Fuera de rango.");
                        break;
                }


Salu2.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Serapis

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.

Meta

#7
Buenas:

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

Código (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Menu_consola_09_cs
{
   class Program
   {
       // Variables globales.
       public static int luz = 6;
       public const int BRILLO_MAX = 8;
       public static bool radio = false;

       static void Main(string[] args)
       {
           // Título de la ventana.
           Console.Title = "Menú de opciones";

           // Tamaño ventana consola.
           // X anchura.
           Console.WindowWidth = 16;

           // Y altura.
           Console.WindowHeight = 2;

           // Oculto el cursor.
           Console.CursorVisible = false;
           ConsoleKey teclaInicial;
           Console.BackgroundColor = ConsoleColor.Green;

           // Letras negras.
           Console.ForegroundColor = ConsoleColor.Black;

           // Limpiar pantalla.
           do
           {
               Console.Clear();
               Console.WriteLine(DateTime.Now.ToString("dd/MM/yyyy"));
               teclaInicial = Console.ReadKey(true).Key;
               if(teclaInicial == ConsoleKey.Enter)
               {
                   menuPrincipal();
               }
           } while (teclaInicial != ConsoleKey.Escape); // SANTIAGOOOOO.
           
       }
       public static void menuPrincipal()
       {

           // Contador de teclas y navegador.
           int opcion = 0;
           bool salir = false;
           // Capturar tecla para luego validar.
           ConsoleKey tecla;
           
           do
           {

               //******************************************************************
               // Dibujo el menú.

               // Rellenar fondo verde.
               Console.BackgroundColor = ConsoleColor.Green;

               // Letras negras.
               Console.ForegroundColor = ConsoleColor.Black;

               // Limpiar pantalla.
               Console.Clear();

               switch (opcion)
               {
                   case 0:
                       Console.SetCursorPosition(0, 0);
                       Console.Write("Language");
                       break;
                   case 1:
                       Console.SetCursorPosition(0, 0);
                       Console.WriteLine("Ajustar hora ->");
                       break;
                   case 2:
                       Console.SetCursorPosition(0, 0);
                       Console.WriteLine("Ajustar fecha ->");
                       break;
                   case 3:
                       Console.SetCursorPosition(0, 0);
                       Console.WriteLine("Brillo");
                       break;
                   case 4:
                       Console.SetCursorPosition(0, 0);
                       Console.WriteLine("Ver radio");
                       break;
                   case 5:
                       Console.SetCursorPosition(0, 0);
                       Console.WriteLine("Vol. avisos");
                       break;
                   case 6:
                       Console.SetCursorPosition(0, 0);
                       Console.WriteLine("Vol. teclas");
                       break;
                   case 7:
                       Console.SetCursorPosition(0, 0);
                       Console.WriteLine("Salir menú");
                       break;
                   default:
                       Console.WriteLine("Fuera de rango.");
                       break;
               }

               // Fin de pintar el menú.
               //******************************************************************

               // Leer tecla ingresada por el usuario.
               tecla = Console.ReadKey(true).Key;

               // Validar el tipo de tecla.
               if (tecla == ConsoleKey.Enter)
               {
                   switch (opcion)
                   {
                       case 3:
                           brillo();
                           break;
                       case 4:
                           radiazo();
                           break;
                       case 7:
                           salir = true;
                           break;
                       default:
                           break;
                   }
               }

               if (tecla == ConsoleKey.DownArrow)
               {
                   opcion += 1;
               }

               if (tecla == ConsoleKey.UpArrow)
               {
                   opcion -= 1;
               }

               // Si está en la última opción, salta a la primera.
               if (opcion > 7)
               {
                   opcion = 0;
               }

               // Si está en la primera posición, salta a la última.
               if (opcion < 0)
               {
                   opcion = 7;
               }

               // Uso la tecla escape como salida.
           } while (salir==false);
       }

       #region Brillo (3).
       public static void brillo()
       {
           ConsoleKey teclaBrillo;
           Console.Clear();
           do
           {
               
               Console.SetCursorPosition(0, 0);
               Console.Write("Luz: ");

               for (int i = 0; i < luz; i++)
               {
                   Console.Write("X");
               }

               for (int j = 0; j < (BRILLO_MAX - luz); j++)
               {
                   Console.Write("-");
               }

               teclaBrillo = Console.ReadKey(true).Key;

               // ¿Se pulsó el cursor arriba?
               if (teclaBrillo == ConsoleKey.UpArrow)
               {
                   //¿no llega al limite?
                   if (luz < BRILLO_MAX)
                   {
                       // Incrementa 1.
                       luz++;
                   }
               }

               if (teclaBrillo == ConsoleKey.DownArrow)
               {
                   if (luz > 0)
                   {
                       // Decremmenta 1.
                       luz--;
                   }
               }

           } while (teclaBrillo != ConsoleKey.Enter);
       }
       #endregion

       #region Radio (4).
       public static void radiazo()
       {
           ConsoleKey teclaRadio;
           Console.Clear();
           do
           {
               Console.SetCursorPosition(0, 0);
               Console.Write("Radio: ");

               

               if (radio == true)
               {
                   Console.SetCursorPosition(7, 0);
                   Console.Write("On ");
               }

               else
               {
                   Console.SetCursorPosition(7, 0);
                   Console.Write("Off");
               }

               teclaRadio = Console.ReadKey(true).Key;

               if (teclaRadio == ConsoleKey.UpArrow)
               {
                   Console.SetCursorPosition(7, 0);
                   Console.Write("On ");
                   radio = true;
               }

               if (teclaRadio == ConsoleKey.DownArrow)
               {
                   Console.SetCursorPosition(7, 0);
                   Console.Write("Off");
                   radio = false;
               }

           } while (teclaRadio != ConsoleKey.Enter);
       }
       #endregion

   }
}



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 (csharp) [Seleccionar]
public static void radiazo()
        {
            ConsoleKey teclaRadio;
            Console.Clear();
            do
            {
                Console.SetCursorPosition(0, 0);
                Console.Write("Radio: ");



                if (radio == true)
                {
                    Console.SetCursorPosition(7, 0);
                    Console.Write("On ");
                }

                else
                {
                    Console.SetCursorPosition(7, 0);
                    Console.Write("Off");
                }

                teclaRadio = Console.ReadKey(true).Key;

                if (teclaRadio == ConsoleKey.UpArrow)
                {
                    Console.SetCursorPosition(7, 0);
                    Console.Write("On ");
                    radio = true;
                }

                if (teclaRadio == ConsoleKey.DownArrow)
                {
                    Console.SetCursorPosition(7, 0);
                    Console.Write("Off");
                    radio = false;
                }

            } while (teclaRadio != ConsoleKey.Enter);
        }


Saludos
;)
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Serapis

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

Sobre tus dudas:
CitarSi 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:


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.



Meta

Hola:

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

Código (csharp) [Seleccionar]
        public static void radiazo()
        {
            ConsoleKey teclaRadio;
            Console.Clear();
            do
            {
                Console.SetCursorPosition(0, 0);
                Console.Write("Ver radio: ");           

                Console.SetCursorPosition(11, 0);
                Console.Write(radio ? "On " : "Off");
               

                teclaRadio = Console.ReadKey(true).Key;

                if ((teclaRadio == ConsoleKey.UpArrow) || (teclaRadio == ConsoleKey.DownArrow))
                {
                    radio = !radio;
                }

            } while (teclaRadio != ConsoleKey.Enter);
        }


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.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/