How can I update the current line in a C# Windows Console App?

前端 未结 17 1025
南旧
南旧 2020-11-22 14:43

When building a Windows Console App in C#, is it possible to write to the console without having to extend a current line or go to a new line? For example, if I want to sho

相关标签:
17条回答
  • 2020-11-22 15:04

    i was looking for same solution in vb.net and i found this one and it's great.

    however as @JohnOdom suggested a better way to handle the blanks space if previous one is larger than current one..

    i make a function in vb.net and thought someone could get helped ..

    here is my code:

    Private Sub sPrintStatus(strTextToPrint As String, Optional boolIsNewLine As Boolean = False)
        REM intLastLength is declared as public variable on global scope like below
        REM intLastLength As Integer
        If boolIsNewLine = True Then
            intLastLength = 0
        End If
        If intLastLength > strTextToPrint.Length Then
            Console.Write(Convert.ToChar(13) & strTextToPrint.PadRight(strTextToPrint.Length + (intLastLength - strTextToPrint.Length), Convert.ToChar(" ")))
        Else
            Console.Write(Convert.ToChar(13) & strTextToPrint)
        End If
        intLastLength = strTextToPrint.Length
    End Sub
    
    0 讨论(0)
  • 2020-11-22 15:05

    You can use Console.SetCursorPosition to set the position of the cursor and then write at the current position.

    Here is an example showing a simple "spinner":

    static void Main(string[] args)
    {
        var spin = new ConsoleSpinner();
        Console.Write("Working....");
        while (true) 
        {
            spin.Turn();
        }
    }
    
    public class ConsoleSpinner
    {
        int counter;
    
        public void Turn()
        {
            counter++;        
            switch (counter % 4)
            {
                case 0: Console.Write("/"); counter = 0; break;
                case 1: Console.Write("-"); break;
                case 2: Console.Write("\\"); break;
                case 3: Console.Write("|"); break;
            }
            Thread.Sleep(100);
            Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
        }
    }
    

    Note that you will have to make sure to overwrite any existing output with new output or blanks.

    Update: As it has been criticized that the example moves the cursor only back by one character, I will add this for clarification: Using SetCursorPosition you may set the cursor to any position in the console window.

    Console.SetCursorPosition(0, Console.CursorTop);
    

    will set the cursor to the beginning of the current line (or you can use Console.CursorLeft = 0 directly).

    0 讨论(0)
  • 2020-11-22 15:05

    Inspired by @E.Lahu Solution, implementation of a bar progress with percentage.

    public class ConsoleSpinner
    {
        private int _counter;
    
        public void Turn(Color color, int max, string prefix = "Completed", string symbol = "■",int position = 0)
        {
            Console.SetCursorPosition(0, position);
            Console.Write($"{prefix} {ComputeSpinner(_counter, max, symbol)}", color);
            _counter = _counter == max ? 0 : _counter + 1;
        }
    
        public string ComputeSpinner(int nmb, int max, string symbol)
        {
            var spinner = new StringBuilder();
            if (nmb == 0)
                return "\r ";
    
            spinner.Append($"[{nmb}%] [");
            for (var i = 0; i < max; i++)
            {
                spinner.Append(i < nmb ? symbol : ".");
            }
    
            spinner.Append("]");
            return spinner.ToString();
        }
    }
    
    
    public static void Main(string[] args)
        {
            var progressBar= new ConsoleSpinner();
            for (int i = 0; i < 1000; i++)
            {
                progressBar.Turn(Color.Aqua,100);
                Thread.Sleep(1000);
            }
        }
    
    0 讨论(0)
  • 2020-11-22 15:06

    So far we have three competing alternatives for how to do this:

    Console.Write("\r{0}   ", value);                      // Option 1: carriage return
    Console.Write("\b\b\b\b\b{0}", value);                 // Option 2: backspace
    {                                                      // Option 3 in two parts:
        Console.SetCursorPosition(0, Console.CursorTop);   // - Move cursor
        Console.Write(value);                              // - Rewrite
    }
    

    I've always used Console.CursorLeft = 0, a variation on the third option, so I decided to do some tests. Here's the code I used:

    public static void CursorTest()
    {
        int testsize = 1000000;
    
        Console.WriteLine("Testing cursor position");
        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < testsize; i++)
        {
            Console.Write("\rCounting: {0}     ", i);
        }
        sw.Stop();
        Console.WriteLine("\nTime using \\r: {0}", sw.ElapsedMilliseconds);
    
        sw.Reset();
        sw.Start();
        int top = Console.CursorTop;
        for (int i = 0; i < testsize; i++)
        {
            Console.SetCursorPosition(0, top);        
            Console.Write("Counting: {0}     ", i);
        }
        sw.Stop();
        Console.WriteLine("\nTime using CursorLeft: {0}", sw.ElapsedMilliseconds);
    
        sw.Reset();
        sw.Start();
        Console.Write("Counting:          ");
        for (int i = 0; i < testsize; i++)
        {        
            Console.Write("\b\b\b\b\b\b\b\b{0,8}", i);
        }
    
        sw.Stop();
        Console.WriteLine("\nTime using \\b: {0}", sw.ElapsedMilliseconds);
    }
    

    On my machine, I get the following results:

    • Backspaces: 25.0 seconds
    • Carriage Returns: 28.7 seconds
    • SetCursorPosition: 49.7 seconds

    Additionally, SetCursorPosition caused noticeable flicker that I didn't observe with either of the alternatives. So, the moral is to use backspaces or carriage returns when possible, and thanks for teaching me a faster way to do this, SO!


    Update: In the comments, Joel suggests that SetCursorPosition is constant with respect to the distance moved while the other methods are linear. Further testing confirms that this is the case, however constant time and slow is still slow. In my tests, writing a long string of backspaces to the console is faster than SetCursorPosition until somewhere around 60 characters. So backspace is faster for replacing portions of the line shorter than 60 characters (or so), and it doesn't flicker, so I'm going to stand by my initial endorsement of \b over \r and SetCursorPosition.

    0 讨论(0)
  • 2020-11-22 15:08

    From the Console docs in MSDN:

    You can solve this problem by setting the TextWriter.NewLine property of the Out or Error property to another line termination string. For example, the C# statement, Console.Error.NewLine = "\r\n\r\n";, sets the line termination string for the standard error output stream to two carriage return and line feed sequences. Then you can explicitly call the WriteLine method of the error output stream object, as in the C# statement, Console.Error.WriteLine();

    So - I did this:

    Console.Out.Newline = String.Empty;
    

    Then I am able to control the output myself;

    Console.WriteLine("Starting item 1:");
        Item1();
    Console.WriteLine("OK.\nStarting Item2:");
    

    Another way of getting there.

    0 讨论(0)
  • 2020-11-22 15:09
        public void Update(string data)
        {
            Console.Write(string.Format("\r{0}", "".PadLeft(Console.CursorLeft, ' ')));
            Console.Write(string.Format("\r{0}", data));
        }
    
    0 讨论(0)
提交回复
热议问题