Thursday, 12 February 2015

Making a menu for the console in C# [Part 1]

The menu method

For the first year programming in my university we were required to make a few console applications in C#. Due to the nature of end users all input needs to be validated else someone is going to have fun blowing up your program.

One of the ways I validated my user input was by having a scrolling menu system, A few people commented on it and asked me how I did it so I thought it would make an interesting first Blog/Tutorial post for this website.

Structure

How the method will work

The menu method works by taking a string array which contains every option on the menu and will return an int32 which will be the index of the option the user entered. Doing it this way will allow for some interesting designs later on such as option menus or basic file browsing.

This is how we declare the method:
static int Menu(string[] inArray) {

How the method is coded

The menu has two easy parts; the "Drawing Phase" and the "User Input Phase", these are looped until the user has selected the option they want, it's very simple.

Drawing phase

This for loop will go through each element of the array that has been passed into the method and prints it out. If the elements index is equal to the selectedItem (what the user is currently selecting, don't worry we will be using this later) then it prints out the element in a "highlighted" colour.
for (int i = 0; i < inArray.Length; i++) {
    if (i == selectedItem) {//This section is what highlights the selected item
        Console.BackgroundColor = ConsoleColor.Gray;
        Console.ForegroundColor = ConsoleColor.Black;
        Console.WriteLine("-" + inArray[i]);
        Console.ResetColor();
    } else {//this section is what prints unselected items
        Console.WriteLine("-" + inArray[i]);
    }
}
 
bottomOffset = Console.CursorTop;
If I pass a array that holds the days of the week in an array this code will print the array like this.

Note: due to the fact that selectedItem was declared as 0 the option "Monday" has been automatically highlighted.

We also set a value called bottomOffest to where the cursor is from the top of the screen, remember that because it is very important later on.

User input phase

Now we need to allow the user to move the selection cursor around so that they are able to move it over the option they want to select. I want to move the selection cursor around using the arrow keys, which is very easy to do in C#, all we need to do is use Console.ReadKey(true) to read what keys the user is pressing. Note: we pass "true" into the ReadKey method so that the method doesn't echo the keys we press onto the screen, this is not necessary but will make the menu look better.

This is the code for the user input so far.
kb = Console.ReadKey(true); //read the keyboard
 
switch (kb.Key) { //react to input
    case ConsoleKey.UpArrow:
        if (selectedItem > 0) {
            selectedItem--;
        } else {
            selectedItem = (inArray.Length - 1);
        }
        break;
 
    case ConsoleKey.DownArrow:
        if (selectedItem < (inArray.Length - 1)) {
            selectedItem++;
        } else {
            selectedItem = 0;
        }
        break;
}
The value kb is of type ConsoleKeyInfo which allows us to easily test what key has been pressed. As you can see we move the value selectedItem either up or down depending on what key has been pressed and if selectedItem goes out of the bounds of the array we flip it back to the start or the end of the array, this allows us to loop back to the top of the array if we go past the end of it or loop the the bottom of the array if we go past the start of it.

Now we need to feed this new selectedItem value back into the drawing phase, simply put the code in a loop according to this pseudo-code.

While (User has not selected something)
     Draw Menu
     Get User Input
     React to User Input

 The final thing to add to the user input phase is a way to break out of this loop and return the selectedItem variable, to do this simply add a case for the enter key which will break out of the loop.
Here is the case I made.
case ConsoleKey.Enter:
    loopComplete = true;
    break;

Making things look pretty

The code so far should work, it will return the values correctly and will display the item the user is currently selecting, but every time the user goes up or down the array will be printed after the last pass. This means we get a big confusing stream of options which would confuse the end user, to fix this we have two solutions.
  1. The quick and dirty way
  2. My way
The quick and dirty way involves clearing the whole screen (Console.Clear()) when the user moves up and down making the array redraw itself in the same place, but this is a salt the earth policy as the Clear method will clear any information the programmer put on the screen to help the user.

The better way of doing things is moving the cursor back to the top of the array and drawing over the previous array which sounds complex but it's not, I'm just bad at explaining it.

All you have to do is record the start and end point of the array (on the console) and move the cursor back to the top of the array when you want to draw again, you can see it on this Gist I made [Link].

Another thing to do to make the menu prettier is to turn the cursor off with
Console.CursorVisible = false;
so that the cursor wont be flashing around when you are printing the array, just remember to make it visible again before the method ends.

How it looks

[View on youtube]

I will talk about how to use this method in another Blog post as it's getting too early in the morning.

Source Code

Console Menu - Brogie [Link]

1 comment:

Copyright © 2014 Stumbling Through Programming