Click here to Skip to main content
15,883,891 members
Articles / Programming Languages / C#
Tip/Trick

Drawing a Rectangle in the C# Console

Rate me:
Please Sign up or sign in to vote.
4.33/5 (6 votes)
18 Apr 2016CPOL2 min read 42.6K   437   9   2
Draw rectangles in a C# console window with this drop-in class

Tip/Trick: Draw Boxes in a C# Console with this Drop-in Class

This is a drop-in class that allows the drawing of rectangles in a console window. I originally built it for my own needs but decided to share it for others that might need it.

Two different drawing modes are supported:

  • WriteLine() Output Style - The function for this is RectangleFromCursor(...). When a new box needs to be drawn on some new appended lines, similar to how WriteLine() performs, then this function can be used. It basically calls WriteLine() repeatedly to draw the new box. One drawback to the WriteLine() version is that multiple rectangles cannot be drawn on the same line. For this, the Overwrite style is needed.
  • Overwrite Style - RectangleFromTop(...) and Rectangle(...) do not use WriteLine(). Instead they set the cursor to a specific location and then write. These functions are best utilized when a rectangle needs to be drawn in a specific location of the console window. If several boxes need to be on the same row, then these functions will serve best. The overwrite style has two types:
    • Draw below offset 0,0 - When using Rectangle(...), use the DrawKind.FromTop option for this. It will draw based on the top of the console buffer area. Basically, if you scroll to the top, 0,0 is the top left corner.
    • Draw below offset of cursor - Use DrawKind.BelowCursor or DrawKind.BelowCursorButKeepCursorLocation for this. This will draw the rectangles using the cursor row as an offset.

Code Features

When building the rectangle drawing class, I tried to make it as flexible as possible.

  • It can draw single or double boarder boxes
  • Draw boxes in different colors
  • It restores the original draw color of the curser when done
  • Supports writing from the top of the window or for appending at the curser
  • Option to keep the curser at end of the rectangle or it can be returned to the original location

Example Usage

Here is some example code...

C#
Console.WriteLine();
Console.WriteLine("01234567890123456789");

// Test 1: draw 2 x 2 square at 1,1
Draw.RectangleFromCursor(1, 0, 2, 2);
Console.WriteLine(" <--Cursor after test 1 was here.");

// Test 2: draw a yellow 2 x 2 square at 4,2
Draw.RectangleFromTop(4, 2, 2, 2, ConsoleColor.DarkYellow);
Console.WriteLine(" <--Cursor after test 2 was here.");

// Test 3: draw a red 2 x 2 square below
Draw.RectangleFromCursor(1, 3, 2, 2, keepOriginalCursorLocation: true, color: ConsoleColor.Red);
Console.WriteLine(" <--Cursor after test 3 was here.");

// Test 4: draw a green 2 x 2 square below
Draw.Rectangle(4, 2, 2, 2, Draw.DrawKind.BelowCursorButKeepCursorLocation, color: ConsoleColor.Green);
Console.WriteLine(" <--Cursor after test 4 was here.");

// Test 5: draw a double-boarder cyan rectangle around everything
Draw.RectangleFromTop(0, 0, 33, 15, ConsoleColor.Cyan, useDoubleLines: true);
Console.WriteLine(" <--Cursor after test 5 was here.");

The output of the above looks like this:

Image 1

The Code (Drop-in Class)

Since the class is not too large, it is being posted here in its entirety. Just drop this in your console project and enjoy.

C#
public static class Draw
{
    /// <summary>
    /// Draws a rectangle in the console using several WriteLine() calls.
    /// </summary>
    /// <param name="width">The width of the rectangle.</param>
    /// <param name="height">The right of the rectangle.</param>
    /// <param name="xLocation">The left side position.</param>
    /// <param name="yLocation">The top position.</param>
    /// <param name="keepOriginalCursorLocation">If true, 
    /// the cursor will return back to the starting location.</param>
    /// <param name="color">The color to use. null=uses current color Default: null</param>
    /// <param name="useDoubleLines">Enables double line boarders. Default: false</param>
    public static void RectangleFromCursor(int width,
        int height,
        int xLocation = 0,
        int yLocation = 0,
        bool keepOriginalCursorLocation = false,
        ConsoleColor? color = null,
        bool useDoubleLines = false)
    {
        {
            // Save original cursor location
            int savedCursorTop = Console.CursorTop;
            int savedCursorLeft = Console.CursorLeft;

            // if the size is smaller then 1 then don't do anything
            if (width < 1 || height < 1)
            {
                return;
            }

            // Save and then set cursor color
            ConsoleColor savedColor = Console.ForegroundColor;
            if (color.HasValue)
            {
                Console.ForegroundColor = color.Value;
            }

            char tl, tt, tr, mm, bl, br;

            if (useDoubleLines)
            {
                tl = '+'; tt = '-'; tr = '+'; mm = '¦'; bl = '+'; br = '+';
            }
            else
            {
                tl = '+'; tt = '-'; tr = '+'; mm = '¦'; bl = '+'; br = '+';
            }

            for (int i = 0; i < yLocation; i++)
            {
                Console.WriteLine();
            }

            Console.WriteLine(
                string.Empty.PadLeft(xLocation, ' ')
                + tl
                + string.Empty.PadLeft(width-1, tt)
                + tr);

            for (int i = 0; i < height; i++)
            {
                Console.WriteLine(
                    string.Empty.PadLeft(xLocation, ' ')
                    + mm
                    + string.Empty.PadLeft(width - 1, ' ')
                    + mm);
            }

            Console.WriteLine(
                string.Empty.PadLeft(xLocation, ' ')
                + bl
                + string.Empty.PadLeft(width - 1, tt)
                + br);


            if (color.HasValue)
            {
                Console.ForegroundColor = savedColor;
            }

            if (keepOriginalCursorLocation)
            {
                Console.SetCursorPosition(savedCursorLeft, savedCursorTop);
            }
        }
    }

    /// <summary>
    /// Draws a rectangle in a console window using the top line of the buffer as the offset.
    /// </summary>
    /// <param name="xLocation">The left side position.</param>
    /// <param name="yLocation">The top position.</param>
    /// <param name="width">The width of the rectangle.</param>
    /// <param name="height">The right of the rectangle.</param>
    /// <param name="color">The color to use. null=uses current color Default: null</param>
    public static void RectangleFromTop(
        int width,
        int height,
        int xLocation = 0,
        int yLocation = 0,
        ConsoleColor? color = null,
        bool useDoubleLines = false)
    {
        Rectangle(width, height, xLocation, yLocation, DrawKind.FromTop, color, useDoubleLines);
    }

    /// <summary>
    /// Specifies if the draw location should be based on the current cursor location or the
    /// top of the window.
    /// </summary>
    public enum DrawKind
    {
        BelowCursor,
        BelowCursorButKeepCursorLocation,
        FromTop,
    }

    /// <summary>
    /// Draws a rectangle in the console window.
    /// </summary>
    /// <param name="width">The width of the rectangle.</param>
    /// <param name="height">The right of the rectangle.</param>
    /// <param name="xLocation">The left side position.</param>
    /// <param name="yLocation">The top position.</param>
    /// <param name="drawKind">Where to draw the rectangle and 
    /// where to leave the cursor when finished.</param>
    /// <param name="color">The color to use. null=uses current color Default: null</param>
    /// <param name="useDoubleLines">Enables double line boarders. Default: false</param>
    public static void Rectangle(
        int width, 
        int height, 
        int xLocation = 0, 
        int yLocation = 0, 
        DrawKind drawKind = DrawKind.FromTop, 
        ConsoleColor? color = null, 
        bool useDoubleLines = false)
    {        
        // if the size is smaller then 1 than don't do anything
        if (width < 1 || height < 1)
        {
           return;
        }

        // Save original cursor location
        int savedCursorTop = Console.CursorTop;
        int savedCursorLeft = Console.CursorLeft;

        if (drawKind == DrawKind.BelowCursor || drawKind == DrawKind.BelowCursorButKeepCursorLocation)
        {
            yLocation += Console.CursorTop;
        }

        // Save and then set cursor color
        ConsoleColor savedColor = Console.ForegroundColor;
        if (color.HasValue)
        {
            Console.ForegroundColor = color.Value;
        }

        char tl, tt, tr, mm, bl, br;

        if (useDoubleLines)
        {
            tl = '+'; tt = '-'; tr = '+'; mm = '¦'; bl = '+'; br = '+';
        }
        else
        {
            tl = '+'; tt = '-'; tr = '+'; mm = '¦'; bl = '+'; br = '+';
        }

        SafeDraw(xLocation, yLocation, tl);
        for (int x = xLocation + 1; x < xLocation + width; x++)
        {
            SafeDraw(x, yLocation, tt);
        }
        SafeDraw(xLocation + width, yLocation, tr);

        for (int y = yLocation + height; y > yLocation; y--)
        {
            SafeDraw(xLocation, y, mm);
            SafeDraw(xLocation + width, y, mm);
        }

        SafeDraw(xLocation, yLocation + height + 1, bl);
        for (int x = xLocation + 1; x < xLocation + width; x++)
        {
            SafeDraw(x, yLocation + height + 1, tt);
        }
        SafeDraw(xLocation + width, yLocation + height + 1, br);

        // Restore cursor
        if (drawKind != DrawKind.BelowCursor)
        {
            Console.SetCursorPosition(savedCursorLeft, savedCursorTop);
        }

        if (color.HasValue)
        {
            Console.ForegroundColor = savedColor;
        }
    }

    private static void SafeDraw(int xLocation, int yLocation, char ch)
    {
        if (xLocation < Console.BufferWidth && yLocation < Console.BufferHeight)
        {
            Console.SetCursorPosition(xLocation, yLocation);
            Console.Write(ch);
        }
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Help desk / Support
United States United States
Ryan White is an IT Coordinator, currently living in Pleasanton, California.

He earned his B.S. in Computer Science at California State University East Bay in 2012. Ryan has been writing lines of code since the age of 7 and continues to enjoy programming in his free time.

You can contact Ryan at s u n s e t q u e s t -A-T- h o t m a i l DOT com if you have any questions he can help out with.

Comments and Discussions

 
QuestionHandy for highlighting/emphasising something in a console log Pin
David James Tuke19-Apr-16 19:37
professionalDavid James Tuke19-Apr-16 19:37 
AnswerRe: Handy for highlighting/emphasising something in a console log Pin
Ryan Scott White20-Apr-16 4:47
professionalRyan Scott White20-Apr-16 4:47 
Agreed! Smile | :) For quick simple projects or scripts, console apps are the way to go.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.