Console application - WriteLine above the current work line

I saw several other posts very similar to this one, but the answers they give do not answer the question correctly. Sorry if something is hidden that I could not find ...

I want to use Console.WriteLine () to print something higher than my current Console.ReadLine (), for example, my application prints "Hello world" and starts a thread that (after 5 seconds) will print "I just waited 5 seconds" above the line where I need to enter something, for example:

Hello world Please input something: _ 

Then 5 seconds will pass, and it will look like this:

 Hello world I just waited 5 seconds Please input something: _ 

So far, I tried to use Console.SetCursorPosition (0, Console.CursorTop - 1), but it just prints on the line "Please enter something: _", and if I use Console.CursorTop-2, [2] Out range "(I don’t know why this is so), and if I use Console.CursorTop - 2, it prints in the section" Please enter something: _ "... so my question is: how to print something ABOVE the line "Please enter something: _"

+5
source share
2 answers

Just moving the cursor is not enough, the problem is that you are inserting text. It’s possible, the Console.MoveBufferArea () method gives you access to the base buffer of the console screen and allows you to move text and attributes to another line.

There are several sophisticated cases. You have already found, you must make the console scroll if the cursor is at the end of the buffer. And the timer is a very difficult problem to solve, you can really do it right only if you can prevent Console.ReadLine () from moving the cursor at the same time that the Elapsed Time event inserts text. This requires a lock , you cannot insert a lock in Console.ReadLine ().

Sample code you can play with to find you:

 static string TimedReadline(string prompt, int seconds) { int y = Console.CursorTop; // Force a scroll if we're at the end of the buffer if (y == Console.BufferHeight - 1) { Console.WriteLine(); Console.SetCursorPosition(0, --y); } // Setup the timer using (var tmr = new System.Timers.Timer(1000 * seconds)) { tmr.AutoReset = false; tmr.Elapsed += (s, e) => { if (Console.CursorTop != y) return; int x = Cursor.Left; Console.MoveBufferArea(0, y, Console.WindowWidth, 1, 0, y + 1); Console.SetCursorPosition(0, y); Console.Write("I just waited {0} seconds", seconds); Console.SetCursorPosition(x, y + 1); }; tmr.Enabled = true; // Write the prompt and obtain the user input Console.Write(prompt); return Console.ReadLine(); } } 

Sample Usage:

 static void Main(string[] args) { for (int ix = 0; ix < Console.BufferHeight; ++ix) Console.WriteLine("Hello world"); var input = TimedReadline("Please input something: ", 2); } 

Pay attention to the test on the Console.Top property, it guarantees that nothing will become radically wrong when the user has typed too much text and forcibly scrolled or if Console.ReadLine () completed the same time that the timer was ticked. The proof that this is thread safe in all possible cases is hard to do, there will certainly be problems when Console.ReadLine () moves the cursor horizontally at the same time that the Elapsed handler is executed. I recommend that you write your own Console.ReadLine () method so that you can insert the lock and make sure it is always safe.

+5
source

You can use carriage return ( \r or U + 000D) to return the cursor to the beginning of the current line, and then overwrite what is there. Sort of

 // A bunch of spaces to clear the previous output Console.Write("\r "); Console.WriteLine("\rI just waited 5 seconds"); Console.Write("Please input something: "); 

However, if the user has already started typing, this will no longer work (since you cannot overwrite everything they typed, and they will lose what they typed on the screen, although it is still there in memory.

To fix this problem correctly, you really need to change the console character buffer. You should move everything above the current line one line, and then insert your message. You can use Console.MoveBufferArea to move the area up. Then you need to save the current cursor position, move the cursor to the beginning of the line above, write a message and reset the cursor position to the saved one.

And then you should hope that the user will not write while you write your message, because this will ruin the situation. I'm not sure that you can solve this problem by using ReadLine , although you cannot temporarily block something while ReadLine is active. To decide correctly, you may have to write your own alternative to ReadLine , which reads individual keystrokes and will block the common object when writing the resulting character, to avoid simultaneously writing two streams to the console.

0
source

Source: https://habr.com/ru/post/1263961/


All Articles